mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 14:14:24 +08:00
staging: qlge: Retire the driver
No significant improvements have been done to this driver since commit
a7c3ddf29a
("staging: qlge: clean up debugging code in the QL_ALL_DUMP
ifdef land") in January 2021. The driver should not stay in staging
forever. Since it has been abandoned by the vendor and no one has stepped
up to maintain it, delete it.
If some users manifest themselves, the driver will be restored to
drivers/net/ as suggested in the linked message.
Link: https://lore.kernel.org/netdev/20231019074237.7ef255d7@kernel.org/
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Cc: Manish Chopra <manishc@marvell.com>
Cc: Coiby Xu <coiby.xu@gmail.com>
Signed-off-by: Benjamin Poirier <benjamin.poirier@gmail.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/r/20231020124457.312449-3-benjamin.poirier@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
88eddb0cce
commit
875be09092
@ -16,7 +16,6 @@ Contents:
|
||||
ethernet/index
|
||||
fddi/index
|
||||
hamradio/index
|
||||
qlogic/index
|
||||
wifi/index
|
||||
wwan/index
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
|
||||
QLogic QLGE Device Drivers
|
||||
===============================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
qlge
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@ -1,118 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=======================================
|
||||
QLogic QLGE 10Gb Ethernet device driver
|
||||
=======================================
|
||||
|
||||
This driver use drgn and devlink for debugging.
|
||||
|
||||
Dump kernel data structures in drgn
|
||||
-----------------------------------
|
||||
|
||||
To dump kernel data structures, the following Python script can be used
|
||||
in drgn:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def align(x, a):
|
||||
"""the alignment a should be a power of 2
|
||||
"""
|
||||
mask = a - 1
|
||||
return (x+ mask) & ~mask
|
||||
|
||||
def struct_size(struct_type):
|
||||
struct_str = "struct {}".format(struct_type)
|
||||
return sizeof(Object(prog, struct_str, address=0x0))
|
||||
|
||||
def netdev_priv(netdevice):
|
||||
NETDEV_ALIGN = 32
|
||||
return netdevice.value_() + align(struct_size("net_device"), NETDEV_ALIGN)
|
||||
|
||||
name = 'xxx'
|
||||
qlge_device = None
|
||||
netdevices = prog['init_net'].dev_base_head.address_of_()
|
||||
for netdevice in list_for_each_entry("struct net_device", netdevices, "dev_list"):
|
||||
if netdevice.name.string_().decode('ascii') == name:
|
||||
print(netdevice.name)
|
||||
|
||||
ql_adapter = Object(prog, "struct ql_adapter", address=netdev_priv(qlge_device))
|
||||
|
||||
The struct ql_adapter will be printed in drgn as follows,
|
||||
|
||||
>>> ql_adapter
|
||||
(struct ql_adapter){
|
||||
.ricb = (struct ricb){
|
||||
.base_cq = (u8)0,
|
||||
.flags = (u8)120,
|
||||
.mask = (__le16)26637,
|
||||
.hash_cq_id = (u8 [1024]){ 172, 142, 255, 255 },
|
||||
.ipv6_hash_key = (__le32 [10]){},
|
||||
.ipv4_hash_key = (__le32 [4]){},
|
||||
},
|
||||
.flags = (unsigned long)0,
|
||||
.wol = (u32)0,
|
||||
.nic_stats = (struct nic_stats){
|
||||
.tx_pkts = (u64)0,
|
||||
.tx_bytes = (u64)0,
|
||||
.tx_mcast_pkts = (u64)0,
|
||||
.tx_bcast_pkts = (u64)0,
|
||||
.tx_ucast_pkts = (u64)0,
|
||||
.tx_ctl_pkts = (u64)0,
|
||||
.tx_pause_pkts = (u64)0,
|
||||
...
|
||||
},
|
||||
.active_vlans = (unsigned long [64]){
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52780853100545, 18446744073709551615,
|
||||
18446619461681283072, 0, 42949673024, 2147483647,
|
||||
},
|
||||
.rx_ring = (struct rx_ring [17]){
|
||||
{
|
||||
.cqicb = (struct cqicb){
|
||||
.msix_vect = (u8)0,
|
||||
.reserved1 = (u8)0,
|
||||
.reserved2 = (u8)0,
|
||||
.flags = (u8)0,
|
||||
.len = (__le16)0,
|
||||
.rid = (__le16)0,
|
||||
...
|
||||
},
|
||||
.cq_base = (void *)0x0,
|
||||
.cq_base_dma = (dma_addr_t)0,
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
coredump via devlink
|
||||
--------------------
|
||||
|
||||
|
||||
And the coredump obtained via devlink in json format looks like,
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ devlink health dump show DEVICE reporter coredump -p -j
|
||||
{
|
||||
"Core Registers": {
|
||||
"segment": 1,
|
||||
"values": [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]
|
||||
},
|
||||
"Test Logic Regs": {
|
||||
"segment": 2,
|
||||
"values": [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]
|
||||
},
|
||||
"RMII Registers": {
|
||||
"segment": 3,
|
||||
"values": [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]
|
||||
},
|
||||
...
|
||||
"Sem Registers": {
|
||||
"segment": 50,
|
||||
"values": [ 0,0,0,0 ]
|
||||
}
|
||||
}
|
||||
|
||||
When the module parameter qlge_force_coredump is set to be true, the MPI
|
||||
RISC reset before coredumping. So coredumping will much longer since
|
||||
devlink tool has to wait for 5 secs for the resetting to be
|
||||
finished.
|
@ -17540,15 +17540,6 @@ L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/net/ethernet/qlogic/qlcnic/
|
||||
|
||||
QLOGIC QLGE 10Gb ETHERNET DRIVER
|
||||
M: Manish Chopra <manishc@marvell.com>
|
||||
M: GR-Linux-NIC-Dev@marvell.com
|
||||
M: Coiby Xu <coiby.xu@gmail.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/networking/device_drivers/qlogic/qlge.rst
|
||||
F: drivers/staging/qlge/
|
||||
|
||||
QM1D1B0004 MEDIA DRIVER
|
||||
M: Akihiro Tsukada <tskd08@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -248,7 +248,6 @@ CONFIG_UIO_AEC=m
|
||||
CONFIG_UIO_SERCOS3=m
|
||||
CONFIG_UIO_PCI_GENERIC=m
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_QLGE=m
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT2_FS_XATTR=y
|
||||
CONFIG_EXT2_FS_SECURITY=y
|
||||
|
@ -72,8 +72,6 @@ source "drivers/staging/axis-fifo/Kconfig"
|
||||
|
||||
source "drivers/staging/fieldbus/Kconfig"
|
||||
|
||||
source "drivers/staging/qlge/Kconfig"
|
||||
|
||||
source "drivers/staging/vme_user/Kconfig"
|
||||
|
||||
endif # STAGING
|
||||
|
@ -26,4 +26,3 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
|
||||
obj-$(CONFIG_PI433) += pi433/
|
||||
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
|
||||
obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
|
||||
obj-$(CONFIG_QLGE) += qlge/
|
||||
|
@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config QLGE
|
||||
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
|
||||
depends on ETHERNET && PCI
|
||||
select NET_DEVLINK
|
||||
help
|
||||
This driver supports QLogic ISP8XXX 10Gb Ethernet cards.
|
||||
|
||||
To compile this driver as a module, choose M here. The module will be
|
||||
called qlge.
|
@ -1,8 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Makefile for the Qlogic 10GbE PCI Express ethernet driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_QLGE) += qlge.o
|
||||
|
||||
qlge-objs := qlge_main.o qlge_dbg.o qlge_mpi.o qlge_ethtool.o qlge_devlink.o
|
@ -1,28 +0,0 @@
|
||||
* commit 7c734359d350 ("qlge: Size RX buffers based on MTU.", v2.6.33-rc1)
|
||||
introduced dead code in the receive routines, which should be rewritten
|
||||
anyways by the admission of the author himself, see the comment above
|
||||
qlge_build_rx_skb(). That function is now used exclusively to handle packets
|
||||
that underwent header splitting but it still contains code to handle non
|
||||
split cases.
|
||||
* truesize accounting is incorrect (ex: a 9000B frame has skb->truesize 10280
|
||||
while containing two frags of order-1 allocations, ie. >16K)
|
||||
* while in that area, using two 8k buffers to store one 9k frame is a poor
|
||||
choice of buffer size.
|
||||
* in the "chain of large buffers" case, the driver uses an skb allocated with
|
||||
head room but only puts data in the frags.
|
||||
* rename "rx" queues to "completion" queues. Calling tx completion queues "rx
|
||||
queues" is confusing.
|
||||
* struct rx_ring is used for rx and tx completions, with some members relevant
|
||||
to one case only
|
||||
* the flow control implementation in firmware is buggy (sends a flood of pause
|
||||
frames, resets the link, device and driver buffer queues become
|
||||
desynchronized), disable it by default
|
||||
* the driver has a habit of using runtime checks where compile time checks are
|
||||
possible (ex. qlge_free_rx_buffers())
|
||||
* reorder struct members to avoid holes if it doesn't impact performance
|
||||
* use better-suited apis (ex. use pci_iomap() instead of ioremap())
|
||||
* remove duplicate and useless comments
|
||||
* fix weird line wrapping (all over, ex. the qlge_set_routing_reg() calls in
|
||||
qlge_set_multicast_list()).
|
||||
* remove useless casts (ex. memset((void *)mac_iocb_ptr, ...))
|
||||
* fix checkpatch issues
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,167 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include "qlge.h"
|
||||
#include "qlge_devlink.h"
|
||||
|
||||
static int qlge_fill_seg_(struct devlink_fmsg *fmsg,
|
||||
struct mpi_coredump_segment_header *seg_header,
|
||||
u32 *reg_data)
|
||||
{
|
||||
int regs_num = (seg_header->seg_size
|
||||
- sizeof(struct mpi_coredump_segment_header)) / sizeof(u32);
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = devlink_fmsg_pair_nest_start(fmsg, seg_header->description);
|
||||
if (err)
|
||||
return err;
|
||||
err = devlink_fmsg_obj_nest_start(fmsg);
|
||||
if (err)
|
||||
return err;
|
||||
err = devlink_fmsg_u32_pair_put(fmsg, "segment", seg_header->seg_num);
|
||||
if (err)
|
||||
return err;
|
||||
err = devlink_fmsg_arr_pair_nest_start(fmsg, "values");
|
||||
if (err)
|
||||
return err;
|
||||
for (i = 0; i < regs_num; i++) {
|
||||
err = devlink_fmsg_u32_put(fmsg, *reg_data);
|
||||
if (err)
|
||||
return err;
|
||||
reg_data++;
|
||||
}
|
||||
err = devlink_fmsg_obj_nest_end(fmsg);
|
||||
if (err)
|
||||
return err;
|
||||
err = devlink_fmsg_arr_pair_nest_end(fmsg);
|
||||
if (err)
|
||||
return err;
|
||||
err = devlink_fmsg_pair_nest_end(fmsg);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define FILL_SEG(seg_hdr, seg_regs) \
|
||||
do { \
|
||||
err = qlge_fill_seg_(fmsg, &dump->seg_hdr, dump->seg_regs); \
|
||||
if (err) { \
|
||||
kvfree(dump); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int qlge_reporter_coredump(struct devlink_health_reporter *reporter,
|
||||
struct devlink_fmsg *fmsg, void *priv_ctx,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
struct qlge_adapter *qdev = devlink_health_reporter_priv(reporter);
|
||||
struct qlge_mpi_coredump *dump;
|
||||
wait_queue_head_t wait;
|
||||
|
||||
if (!netif_running(qdev->ndev))
|
||||
return 0;
|
||||
|
||||
if (test_bit(QL_FRC_COREDUMP, &qdev->flags)) {
|
||||
if (qlge_own_firmware(qdev)) {
|
||||
qlge_queue_fw_error(qdev);
|
||||
init_waitqueue_head(&wait);
|
||||
wait_event_timeout(wait, 0, 5 * HZ);
|
||||
} else {
|
||||
netif_err(qdev, ifup, qdev->ndev,
|
||||
"Force Coredump failed because this NIC function doesn't own the firmware\n");
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
dump = kvmalloc(sizeof(*dump), GFP_KERNEL);
|
||||
if (!dump)
|
||||
return -ENOMEM;
|
||||
|
||||
err = qlge_core_dump(qdev, dump);
|
||||
if (err) {
|
||||
kvfree(dump);
|
||||
return err;
|
||||
}
|
||||
|
||||
qlge_soft_reset_mpi_risc(qdev);
|
||||
|
||||
FILL_SEG(core_regs_seg_hdr, mpi_core_regs);
|
||||
FILL_SEG(test_logic_regs_seg_hdr, test_logic_regs);
|
||||
FILL_SEG(rmii_regs_seg_hdr, rmii_regs);
|
||||
FILL_SEG(fcmac1_regs_seg_hdr, fcmac1_regs);
|
||||
FILL_SEG(fcmac2_regs_seg_hdr, fcmac2_regs);
|
||||
FILL_SEG(fc1_mbx_regs_seg_hdr, fc1_mbx_regs);
|
||||
FILL_SEG(ide_regs_seg_hdr, ide_regs);
|
||||
FILL_SEG(nic1_mbx_regs_seg_hdr, nic1_mbx_regs);
|
||||
FILL_SEG(smbus_regs_seg_hdr, smbus_regs);
|
||||
FILL_SEG(fc2_mbx_regs_seg_hdr, fc2_mbx_regs);
|
||||
FILL_SEG(nic2_mbx_regs_seg_hdr, nic2_mbx_regs);
|
||||
FILL_SEG(i2c_regs_seg_hdr, i2c_regs);
|
||||
FILL_SEG(memc_regs_seg_hdr, memc_regs);
|
||||
FILL_SEG(pbus_regs_seg_hdr, pbus_regs);
|
||||
FILL_SEG(mde_regs_seg_hdr, mde_regs);
|
||||
FILL_SEG(nic_regs_seg_hdr, nic_regs);
|
||||
FILL_SEG(nic2_regs_seg_hdr, nic2_regs);
|
||||
FILL_SEG(xgmac1_seg_hdr, xgmac1);
|
||||
FILL_SEG(xgmac2_seg_hdr, xgmac2);
|
||||
FILL_SEG(code_ram_seg_hdr, code_ram);
|
||||
FILL_SEG(memc_ram_seg_hdr, memc_ram);
|
||||
FILL_SEG(xaui_an_hdr, serdes_xaui_an);
|
||||
FILL_SEG(xaui_hss_pcs_hdr, serdes_xaui_hss_pcs);
|
||||
FILL_SEG(xfi_an_hdr, serdes_xfi_an);
|
||||
FILL_SEG(xfi_train_hdr, serdes_xfi_train);
|
||||
FILL_SEG(xfi_hss_pcs_hdr, serdes_xfi_hss_pcs);
|
||||
FILL_SEG(xfi_hss_tx_hdr, serdes_xfi_hss_tx);
|
||||
FILL_SEG(xfi_hss_rx_hdr, serdes_xfi_hss_rx);
|
||||
FILL_SEG(xfi_hss_pll_hdr, serdes_xfi_hss_pll);
|
||||
|
||||
err = qlge_fill_seg_(fmsg, &dump->misc_nic_seg_hdr,
|
||||
(u32 *)&dump->misc_nic_info);
|
||||
if (err) {
|
||||
kvfree(dump);
|
||||
return err;
|
||||
}
|
||||
|
||||
FILL_SEG(intr_states_seg_hdr, intr_states);
|
||||
FILL_SEG(cam_entries_seg_hdr, cam_entries);
|
||||
FILL_SEG(nic_routing_words_seg_hdr, nic_routing_words);
|
||||
FILL_SEG(ets_seg_hdr, ets);
|
||||
FILL_SEG(probe_dump_seg_hdr, probe_dump);
|
||||
FILL_SEG(routing_reg_seg_hdr, routing_regs);
|
||||
FILL_SEG(mac_prot_reg_seg_hdr, mac_prot_regs);
|
||||
FILL_SEG(xaui2_an_hdr, serdes2_xaui_an);
|
||||
FILL_SEG(xaui2_hss_pcs_hdr, serdes2_xaui_hss_pcs);
|
||||
FILL_SEG(xfi2_an_hdr, serdes2_xfi_an);
|
||||
FILL_SEG(xfi2_train_hdr, serdes2_xfi_train);
|
||||
FILL_SEG(xfi2_hss_pcs_hdr, serdes2_xfi_hss_pcs);
|
||||
FILL_SEG(xfi2_hss_tx_hdr, serdes2_xfi_hss_tx);
|
||||
FILL_SEG(xfi2_hss_rx_hdr, serdes2_xfi_hss_rx);
|
||||
FILL_SEG(xfi2_hss_pll_hdr, serdes2_xfi_hss_pll);
|
||||
FILL_SEG(sem_regs_seg_hdr, sem_regs);
|
||||
|
||||
kvfree(dump);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct devlink_health_reporter_ops qlge_reporter_ops = {
|
||||
.name = "coredump",
|
||||
.dump = qlge_reporter_coredump,
|
||||
};
|
||||
|
||||
long qlge_health_create_reporters(struct qlge_adapter *priv)
|
||||
{
|
||||
struct devlink *devlink;
|
||||
long err = 0;
|
||||
|
||||
devlink = priv_to_devlink(priv);
|
||||
priv->reporter =
|
||||
devlink_health_reporter_create(devlink, &qlge_reporter_ops,
|
||||
0, priv);
|
||||
if (IS_ERR(priv->reporter)) {
|
||||
err = PTR_ERR(priv->reporter);
|
||||
netdev_warn(priv->ndev,
|
||||
"Failed to create reporter, err = %ld\n",
|
||||
err);
|
||||
}
|
||||
return err;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef QLGE_DEVLINK_H
|
||||
#define QLGE_DEVLINK_H
|
||||
|
||||
#include <net/devlink.h>
|
||||
|
||||
long qlge_health_create_reporters(struct qlge_adapter *priv);
|
||||
|
||||
#endif /* QLGE_DEVLINK_H */
|
@ -1,746 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "qlge.h"
|
||||
|
||||
struct qlge_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int sizeof_stat;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define QL_SIZEOF(m) sizeof_field(struct qlge_adapter, m)
|
||||
#define QL_OFF(m) offsetof(struct qlge_adapter, m)
|
||||
|
||||
static const struct qlge_stats qlge_gstrings_stats[] = {
|
||||
{"tx_pkts", QL_SIZEOF(nic_stats.tx_pkts), QL_OFF(nic_stats.tx_pkts)},
|
||||
{"tx_bytes", QL_SIZEOF(nic_stats.tx_bytes), QL_OFF(nic_stats.tx_bytes)},
|
||||
{"tx_mcast_pkts", QL_SIZEOF(nic_stats.tx_mcast_pkts),
|
||||
QL_OFF(nic_stats.tx_mcast_pkts)},
|
||||
{"tx_bcast_pkts", QL_SIZEOF(nic_stats.tx_bcast_pkts),
|
||||
QL_OFF(nic_stats.tx_bcast_pkts)},
|
||||
{"tx_ucast_pkts", QL_SIZEOF(nic_stats.tx_ucast_pkts),
|
||||
QL_OFF(nic_stats.tx_ucast_pkts)},
|
||||
{"tx_ctl_pkts", QL_SIZEOF(nic_stats.tx_ctl_pkts),
|
||||
QL_OFF(nic_stats.tx_ctl_pkts)},
|
||||
{"tx_pause_pkts", QL_SIZEOF(nic_stats.tx_pause_pkts),
|
||||
QL_OFF(nic_stats.tx_pause_pkts)},
|
||||
{"tx_64_pkts", QL_SIZEOF(nic_stats.tx_64_pkt),
|
||||
QL_OFF(nic_stats.tx_64_pkt)},
|
||||
{"tx_65_to_127_pkts", QL_SIZEOF(nic_stats.tx_65_to_127_pkt),
|
||||
QL_OFF(nic_stats.tx_65_to_127_pkt)},
|
||||
{"tx_128_to_255_pkts", QL_SIZEOF(nic_stats.tx_128_to_255_pkt),
|
||||
QL_OFF(nic_stats.tx_128_to_255_pkt)},
|
||||
{"tx_256_511_pkts", QL_SIZEOF(nic_stats.tx_256_511_pkt),
|
||||
QL_OFF(nic_stats.tx_256_511_pkt)},
|
||||
{"tx_512_to_1023_pkts", QL_SIZEOF(nic_stats.tx_512_to_1023_pkt),
|
||||
QL_OFF(nic_stats.tx_512_to_1023_pkt)},
|
||||
{"tx_1024_to_1518_pkts", QL_SIZEOF(nic_stats.tx_1024_to_1518_pkt),
|
||||
QL_OFF(nic_stats.tx_1024_to_1518_pkt)},
|
||||
{"tx_1519_to_max_pkts", QL_SIZEOF(nic_stats.tx_1519_to_max_pkt),
|
||||
QL_OFF(nic_stats.tx_1519_to_max_pkt)},
|
||||
{"tx_undersize_pkts", QL_SIZEOF(nic_stats.tx_undersize_pkt),
|
||||
QL_OFF(nic_stats.tx_undersize_pkt)},
|
||||
{"tx_oversize_pkts", QL_SIZEOF(nic_stats.tx_oversize_pkt),
|
||||
QL_OFF(nic_stats.tx_oversize_pkt)},
|
||||
{"rx_bytes", QL_SIZEOF(nic_stats.rx_bytes), QL_OFF(nic_stats.rx_bytes)},
|
||||
{"rx_bytes_ok", QL_SIZEOF(nic_stats.rx_bytes_ok),
|
||||
QL_OFF(nic_stats.rx_bytes_ok)},
|
||||
{"rx_pkts", QL_SIZEOF(nic_stats.rx_pkts), QL_OFF(nic_stats.rx_pkts)},
|
||||
{"rx_pkts_ok", QL_SIZEOF(nic_stats.rx_pkts_ok),
|
||||
QL_OFF(nic_stats.rx_pkts_ok)},
|
||||
{"rx_bcast_pkts", QL_SIZEOF(nic_stats.rx_bcast_pkts),
|
||||
QL_OFF(nic_stats.rx_bcast_pkts)},
|
||||
{"rx_mcast_pkts", QL_SIZEOF(nic_stats.rx_mcast_pkts),
|
||||
QL_OFF(nic_stats.rx_mcast_pkts)},
|
||||
{"rx_ucast_pkts", QL_SIZEOF(nic_stats.rx_ucast_pkts),
|
||||
QL_OFF(nic_stats.rx_ucast_pkts)},
|
||||
{"rx_undersize_pkts", QL_SIZEOF(nic_stats.rx_undersize_pkts),
|
||||
QL_OFF(nic_stats.rx_undersize_pkts)},
|
||||
{"rx_oversize_pkts", QL_SIZEOF(nic_stats.rx_oversize_pkts),
|
||||
QL_OFF(nic_stats.rx_oversize_pkts)},
|
||||
{"rx_jabber_pkts", QL_SIZEOF(nic_stats.rx_jabber_pkts),
|
||||
QL_OFF(nic_stats.rx_jabber_pkts)},
|
||||
{"rx_undersize_fcerr_pkts",
|
||||
QL_SIZEOF(nic_stats.rx_undersize_fcerr_pkts),
|
||||
QL_OFF(nic_stats.rx_undersize_fcerr_pkts)},
|
||||
{"rx_drop_events", QL_SIZEOF(nic_stats.rx_drop_events),
|
||||
QL_OFF(nic_stats.rx_drop_events)},
|
||||
{"rx_fcerr_pkts", QL_SIZEOF(nic_stats.rx_fcerr_pkts),
|
||||
QL_OFF(nic_stats.rx_fcerr_pkts)},
|
||||
{"rx_align_err", QL_SIZEOF(nic_stats.rx_align_err),
|
||||
QL_OFF(nic_stats.rx_align_err)},
|
||||
{"rx_symbol_err", QL_SIZEOF(nic_stats.rx_symbol_err),
|
||||
QL_OFF(nic_stats.rx_symbol_err)},
|
||||
{"rx_mac_err", QL_SIZEOF(nic_stats.rx_mac_err),
|
||||
QL_OFF(nic_stats.rx_mac_err)},
|
||||
{"rx_ctl_pkts", QL_SIZEOF(nic_stats.rx_ctl_pkts),
|
||||
QL_OFF(nic_stats.rx_ctl_pkts)},
|
||||
{"rx_pause_pkts", QL_SIZEOF(nic_stats.rx_pause_pkts),
|
||||
QL_OFF(nic_stats.rx_pause_pkts)},
|
||||
{"rx_64_pkts", QL_SIZEOF(nic_stats.rx_64_pkts),
|
||||
QL_OFF(nic_stats.rx_64_pkts)},
|
||||
{"rx_65_to_127_pkts", QL_SIZEOF(nic_stats.rx_65_to_127_pkts),
|
||||
QL_OFF(nic_stats.rx_65_to_127_pkts)},
|
||||
{"rx_128_255_pkts", QL_SIZEOF(nic_stats.rx_128_255_pkts),
|
||||
QL_OFF(nic_stats.rx_128_255_pkts)},
|
||||
{"rx_256_511_pkts", QL_SIZEOF(nic_stats.rx_256_511_pkts),
|
||||
QL_OFF(nic_stats.rx_256_511_pkts)},
|
||||
{"rx_512_to_1023_pkts", QL_SIZEOF(nic_stats.rx_512_to_1023_pkts),
|
||||
QL_OFF(nic_stats.rx_512_to_1023_pkts)},
|
||||
{"rx_1024_to_1518_pkts", QL_SIZEOF(nic_stats.rx_1024_to_1518_pkts),
|
||||
QL_OFF(nic_stats.rx_1024_to_1518_pkts)},
|
||||
{"rx_1519_to_max_pkts", QL_SIZEOF(nic_stats.rx_1519_to_max_pkts),
|
||||
QL_OFF(nic_stats.rx_1519_to_max_pkts)},
|
||||
{"rx_len_err_pkts", QL_SIZEOF(nic_stats.rx_len_err_pkts),
|
||||
QL_OFF(nic_stats.rx_len_err_pkts)},
|
||||
{"rx_code_err", QL_SIZEOF(nic_stats.rx_code_err),
|
||||
QL_OFF(nic_stats.rx_code_err)},
|
||||
{"rx_oversize_err", QL_SIZEOF(nic_stats.rx_oversize_err),
|
||||
QL_OFF(nic_stats.rx_oversize_err)},
|
||||
{"rx_undersize_err", QL_SIZEOF(nic_stats.rx_undersize_err),
|
||||
QL_OFF(nic_stats.rx_undersize_err)},
|
||||
{"rx_preamble_err", QL_SIZEOF(nic_stats.rx_preamble_err),
|
||||
QL_OFF(nic_stats.rx_preamble_err)},
|
||||
{"rx_frame_len_err", QL_SIZEOF(nic_stats.rx_frame_len_err),
|
||||
QL_OFF(nic_stats.rx_frame_len_err)},
|
||||
{"rx_crc_err", QL_SIZEOF(nic_stats.rx_crc_err),
|
||||
QL_OFF(nic_stats.rx_crc_err)},
|
||||
{"rx_err_count", QL_SIZEOF(nic_stats.rx_err_count),
|
||||
QL_OFF(nic_stats.rx_err_count)},
|
||||
{"tx_cbfc_pause_frames0", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames0),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames0)},
|
||||
{"tx_cbfc_pause_frames1", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames1),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames1)},
|
||||
{"tx_cbfc_pause_frames2", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames2),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames2)},
|
||||
{"tx_cbfc_pause_frames3", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames3),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames3)},
|
||||
{"tx_cbfc_pause_frames4", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames4),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames4)},
|
||||
{"tx_cbfc_pause_frames5", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames5),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames5)},
|
||||
{"tx_cbfc_pause_frames6", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames6),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames6)},
|
||||
{"tx_cbfc_pause_frames7", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames7),
|
||||
QL_OFF(nic_stats.tx_cbfc_pause_frames7)},
|
||||
{"rx_cbfc_pause_frames0", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames0),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames0)},
|
||||
{"rx_cbfc_pause_frames1", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames1),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames1)},
|
||||
{"rx_cbfc_pause_frames2", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames2),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames2)},
|
||||
{"rx_cbfc_pause_frames3", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames3),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames3)},
|
||||
{"rx_cbfc_pause_frames4", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames4),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames4)},
|
||||
{"rx_cbfc_pause_frames5", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames5),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames5)},
|
||||
{"rx_cbfc_pause_frames6", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames6),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames6)},
|
||||
{"rx_cbfc_pause_frames7", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames7),
|
||||
QL_OFF(nic_stats.rx_cbfc_pause_frames7)},
|
||||
{"rx_nic_fifo_drop", QL_SIZEOF(nic_stats.rx_nic_fifo_drop),
|
||||
QL_OFF(nic_stats.rx_nic_fifo_drop)},
|
||||
};
|
||||
|
||||
static const char qlge_gstrings_test[][ETH_GSTRING_LEN] = {
|
||||
"Loopback test (offline)"
|
||||
};
|
||||
|
||||
#define QLGE_TEST_LEN (sizeof(qlge_gstrings_test) / ETH_GSTRING_LEN)
|
||||
#define QLGE_STATS_LEN ARRAY_SIZE(qlge_gstrings_stats)
|
||||
#define QLGE_RCV_MAC_ERR_STATS 7
|
||||
|
||||
static int qlge_update_ring_coalescing(struct qlge_adapter *qdev)
|
||||
{
|
||||
int i, status = 0;
|
||||
struct rx_ring *rx_ring;
|
||||
struct cqicb *cqicb;
|
||||
|
||||
if (!netif_running(qdev->ndev))
|
||||
return status;
|
||||
|
||||
/* Skip the default queue, and update the outbound handler
|
||||
* queues if they changed.
|
||||
*/
|
||||
cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_count];
|
||||
if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs ||
|
||||
le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) {
|
||||
for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) {
|
||||
rx_ring = &qdev->rx_ring[i];
|
||||
cqicb = (struct cqicb *)rx_ring;
|
||||
cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
|
||||
cqicb->pkt_delay =
|
||||
cpu_to_le16(qdev->tx_max_coalesced_frames);
|
||||
cqicb->flags = FLAGS_LI;
|
||||
status = qlge_write_cfg(qdev, cqicb, sizeof(*cqicb),
|
||||
CFG_LCQ, rx_ring->cq_id);
|
||||
if (status) {
|
||||
netif_err(qdev, ifup, qdev->ndev,
|
||||
"Failed to load CQICB.\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the inbound (RSS) handler queues if they changed. */
|
||||
cqicb = (struct cqicb *)&qdev->rx_ring[0];
|
||||
if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs ||
|
||||
le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) {
|
||||
for (i = 0; i < qdev->rss_ring_count; i++, rx_ring++) {
|
||||
rx_ring = &qdev->rx_ring[i];
|
||||
cqicb = (struct cqicb *)rx_ring;
|
||||
cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs);
|
||||
cqicb->pkt_delay =
|
||||
cpu_to_le16(qdev->rx_max_coalesced_frames);
|
||||
cqicb->flags = FLAGS_LI;
|
||||
status = qlge_write_cfg(qdev, cqicb, sizeof(*cqicb),
|
||||
CFG_LCQ, rx_ring->cq_id);
|
||||
if (status) {
|
||||
netif_err(qdev, ifup, qdev->ndev,
|
||||
"Failed to load CQICB.\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void qlge_update_stats(struct qlge_adapter *qdev)
|
||||
{
|
||||
u32 i;
|
||||
u64 data;
|
||||
u64 *iter = &qdev->nic_stats.tx_pkts;
|
||||
|
||||
spin_lock(&qdev->stats_lock);
|
||||
if (qlge_sem_spinlock(qdev, qdev->xg_sem_mask)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Couldn't get xgmac sem.\n");
|
||||
goto quit;
|
||||
}
|
||||
/*
|
||||
* Get TX statistics.
|
||||
*/
|
||||
for (i = 0x200; i < 0x280; i += 8) {
|
||||
if (qlge_read_xgmac_reg64(qdev, i, &data)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Error reading status register 0x%.04x.\n",
|
||||
i);
|
||||
goto end;
|
||||
} else {
|
||||
*iter = data;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get RX statistics.
|
||||
*/
|
||||
for (i = 0x300; i < 0x3d0; i += 8) {
|
||||
if (qlge_read_xgmac_reg64(qdev, i, &data)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Error reading status register 0x%.04x.\n",
|
||||
i);
|
||||
goto end;
|
||||
} else {
|
||||
*iter = data;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
/* Update receive mac error statistics */
|
||||
iter += QLGE_RCV_MAC_ERR_STATS;
|
||||
|
||||
/*
|
||||
* Get Per-priority TX pause frame counter statistics.
|
||||
*/
|
||||
for (i = 0x500; i < 0x540; i += 8) {
|
||||
if (qlge_read_xgmac_reg64(qdev, i, &data)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Error reading status register 0x%.04x.\n",
|
||||
i);
|
||||
goto end;
|
||||
} else {
|
||||
*iter = data;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Per-priority RX pause frame counter statistics.
|
||||
*/
|
||||
for (i = 0x568; i < 0x5a8; i += 8) {
|
||||
if (qlge_read_xgmac_reg64(qdev, i, &data)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Error reading status register 0x%.04x.\n",
|
||||
i);
|
||||
goto end;
|
||||
} else {
|
||||
*iter = data;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get RX NIC FIFO DROP statistics.
|
||||
*/
|
||||
if (qlge_read_xgmac_reg64(qdev, 0x5b8, &data)) {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"Error reading status register 0x%.04x.\n", i);
|
||||
goto end;
|
||||
} else {
|
||||
*iter = data;
|
||||
}
|
||||
end:
|
||||
qlge_sem_unlock(qdev, qdev->xg_sem_mask);
|
||||
quit:
|
||||
spin_unlock(&qdev->stats_lock);
|
||||
}
|
||||
|
||||
static void qlge_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
|
||||
{
|
||||
int index;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_TEST:
|
||||
memcpy(buf, *qlge_gstrings_test, QLGE_TEST_LEN * ETH_GSTRING_LEN);
|
||||
break;
|
||||
case ETH_SS_STATS:
|
||||
for (index = 0; index < QLGE_STATS_LEN; index++) {
|
||||
memcpy(buf + index * ETH_GSTRING_LEN,
|
||||
qlge_gstrings_stats[index].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_get_sset_count(struct net_device *dev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_TEST:
|
||||
return QLGE_TEST_LEN;
|
||||
case ETH_SS_STATS:
|
||||
return QLGE_STATS_LEN;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qlge_get_ethtool_stats(struct net_device *ndev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
int index, length;
|
||||
|
||||
length = QLGE_STATS_LEN;
|
||||
qlge_update_stats(qdev);
|
||||
|
||||
for (index = 0; index < length; index++) {
|
||||
char *p = (char *)qdev +
|
||||
qlge_gstrings_stats[index].stat_offset;
|
||||
*data++ = (qlge_gstrings_stats[index].sizeof_stat ==
|
||||
sizeof(u64)) ? *(u64 *)p : (*(u32 *)p);
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_get_link_ksettings(struct net_device *ndev,
|
||||
struct ethtool_link_ksettings *ecmd)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
u32 supported, advertising;
|
||||
|
||||
supported = SUPPORTED_10000baseT_Full;
|
||||
advertising = ADVERTISED_10000baseT_Full;
|
||||
|
||||
if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
|
||||
STS_LINK_TYPE_10GBASET) {
|
||||
supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
|
||||
advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
|
||||
ecmd->base.port = PORT_TP;
|
||||
ecmd->base.autoneg = AUTONEG_ENABLE;
|
||||
} else {
|
||||
supported |= SUPPORTED_FIBRE;
|
||||
advertising |= ADVERTISED_FIBRE;
|
||||
ecmd->base.port = PORT_FIBRE;
|
||||
}
|
||||
|
||||
ecmd->base.speed = SPEED_10000;
|
||||
ecmd->base.duplex = DUPLEX_FULL;
|
||||
|
||||
ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
|
||||
supported);
|
||||
ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,
|
||||
advertising);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qlge_get_drvinfo(struct net_device *ndev,
|
||||
struct ethtool_drvinfo *drvinfo)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
strscpy(drvinfo->driver, qlge_driver_name, sizeof(drvinfo->driver));
|
||||
strscpy(drvinfo->version, qlge_driver_version,
|
||||
sizeof(drvinfo->version));
|
||||
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
|
||||
"v%d.%d.%d",
|
||||
(qdev->fw_rev_id & 0x00ff0000) >> 16,
|
||||
(qdev->fw_rev_id & 0x0000ff00) >> 8,
|
||||
(qdev->fw_rev_id & 0x000000ff));
|
||||
strscpy(drvinfo->bus_info, pci_name(qdev->pdev),
|
||||
sizeof(drvinfo->bus_info));
|
||||
}
|
||||
|
||||
static void qlge_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
unsigned short ssys_dev = qdev->pdev->subsystem_device;
|
||||
|
||||
/* WOL is only supported for mezz card. */
|
||||
if (ssys_dev == QLGE_MEZZ_SSYS_ID_068 ||
|
||||
ssys_dev == QLGE_MEZZ_SSYS_ID_180) {
|
||||
wol->supported = WAKE_MAGIC;
|
||||
wol->wolopts = qdev->wol;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
unsigned short ssys_dev = qdev->pdev->subsystem_device;
|
||||
|
||||
/* WOL is only supported for mezz card. */
|
||||
if (ssys_dev != QLGE_MEZZ_SSYS_ID_068 &&
|
||||
ssys_dev != QLGE_MEZZ_SSYS_ID_180) {
|
||||
netif_info(qdev, drv, qdev->ndev,
|
||||
"WOL is only supported for mezz card\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (wol->wolopts & ~WAKE_MAGIC)
|
||||
return -EINVAL;
|
||||
qdev->wol = wol->wolopts;
|
||||
|
||||
netif_info(qdev, drv, qdev->ndev, "Set wol option 0x%x\n", qdev->wol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qlge_set_phys_id(struct net_device *ndev,
|
||||
enum ethtool_phys_id_state state)
|
||||
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
switch (state) {
|
||||
case ETHTOOL_ID_ACTIVE:
|
||||
/* Save the current LED settings */
|
||||
if (qlge_mb_get_led_cfg(qdev))
|
||||
return -EIO;
|
||||
|
||||
/* Start blinking */
|
||||
qlge_mb_set_led_cfg(qdev, QL_LED_BLINK);
|
||||
return 0;
|
||||
|
||||
case ETHTOOL_ID_INACTIVE:
|
||||
/* Restore LED settings */
|
||||
if (qlge_mb_set_led_cfg(qdev, qdev->led_config))
|
||||
return -EIO;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_start_loopback(struct qlge_adapter *qdev)
|
||||
{
|
||||
if (netif_carrier_ok(qdev->ndev)) {
|
||||
set_bit(QL_LB_LINK_UP, &qdev->flags);
|
||||
netif_carrier_off(qdev->ndev);
|
||||
} else {
|
||||
clear_bit(QL_LB_LINK_UP, &qdev->flags);
|
||||
}
|
||||
qdev->link_config |= CFG_LOOPBACK_PCS;
|
||||
return qlge_mb_set_port_cfg(qdev);
|
||||
}
|
||||
|
||||
static void qlge_stop_loopback(struct qlge_adapter *qdev)
|
||||
{
|
||||
qdev->link_config &= ~CFG_LOOPBACK_PCS;
|
||||
qlge_mb_set_port_cfg(qdev);
|
||||
if (test_bit(QL_LB_LINK_UP, &qdev->flags)) {
|
||||
netif_carrier_on(qdev->ndev);
|
||||
clear_bit(QL_LB_LINK_UP, &qdev->flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void qlge_create_lb_frame(struct sk_buff *skb,
|
||||
unsigned int frame_size)
|
||||
{
|
||||
memset(skb->data, 0xFF, frame_size);
|
||||
frame_size &= ~1;
|
||||
memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
|
||||
skb->data[frame_size / 2 + 10] = (unsigned char)0xBE;
|
||||
skb->data[frame_size / 2 + 12] = (unsigned char)0xAF;
|
||||
}
|
||||
|
||||
void qlge_check_lb_frame(struct qlge_adapter *qdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
unsigned int frame_size = skb->len;
|
||||
|
||||
if ((*(skb->data + 3) == 0xFF) &&
|
||||
(*(skb->data + frame_size / 2 + 10) == 0xBE) &&
|
||||
(*(skb->data + frame_size / 2 + 12) == 0xAF)) {
|
||||
atomic_dec(&qdev->lb_count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_run_loopback_test(struct qlge_adapter *qdev)
|
||||
{
|
||||
int i;
|
||||
netdev_tx_t rc;
|
||||
struct sk_buff *skb;
|
||||
unsigned int size = SMALL_BUF_MAP_SIZE;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
skb = netdev_alloc_skb(qdev->ndev, size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb->queue_mapping = 0;
|
||||
skb_put(skb, size);
|
||||
qlge_create_lb_frame(skb, size);
|
||||
rc = qlge_lb_send(skb, qdev->ndev);
|
||||
if (rc != NETDEV_TX_OK)
|
||||
return -EPIPE;
|
||||
atomic_inc(&qdev->lb_count);
|
||||
}
|
||||
/* Give queue time to settle before testing results. */
|
||||
usleep_range(2000, 2100);
|
||||
qlge_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
|
||||
return atomic_read(&qdev->lb_count) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int qlge_loopback_test(struct qlge_adapter *qdev, u64 *data)
|
||||
{
|
||||
*data = qlge_start_loopback(qdev);
|
||||
if (*data)
|
||||
goto out;
|
||||
*data = qlge_run_loopback_test(qdev);
|
||||
out:
|
||||
qlge_stop_loopback(qdev);
|
||||
return *data;
|
||||
}
|
||||
|
||||
static void qlge_self_test(struct net_device *ndev,
|
||||
struct ethtool_test *eth_test, u64 *data)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
memset(data, 0, sizeof(u64) * QLGE_TEST_LEN);
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
set_bit(QL_SELFTEST, &qdev->flags);
|
||||
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
|
||||
/* Offline tests */
|
||||
if (qlge_loopback_test(qdev, &data[0]))
|
||||
eth_test->flags |= ETH_TEST_FL_FAILED;
|
||||
|
||||
} else {
|
||||
/* Online tests */
|
||||
data[0] = 0;
|
||||
}
|
||||
clear_bit(QL_SELFTEST, &qdev->flags);
|
||||
/* Give link time to come up after
|
||||
* port configuration changes.
|
||||
*/
|
||||
msleep_interruptible(4 * 1000);
|
||||
} else {
|
||||
netif_err(qdev, drv, qdev->ndev,
|
||||
"is down, Loopback test will fail.\n");
|
||||
eth_test->flags |= ETH_TEST_FL_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_get_regs_len(struct net_device *ndev)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
|
||||
return sizeof(struct qlge_mpi_coredump);
|
||||
else
|
||||
return sizeof(struct qlge_reg_dump);
|
||||
}
|
||||
|
||||
static void qlge_get_regs(struct net_device *ndev,
|
||||
struct ethtool_regs *regs, void *p)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
qlge_get_dump(qdev, p);
|
||||
if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
|
||||
regs->len = sizeof(struct qlge_mpi_coredump);
|
||||
else
|
||||
regs->len = sizeof(struct qlge_reg_dump);
|
||||
}
|
||||
|
||||
static int qlge_get_coalesce(struct net_device *ndev,
|
||||
struct ethtool_coalesce *c,
|
||||
struct kernel_ethtool_coalesce *kernel_coal,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
c->rx_coalesce_usecs = qdev->rx_coalesce_usecs;
|
||||
c->tx_coalesce_usecs = qdev->tx_coalesce_usecs;
|
||||
|
||||
/* This chip coalesces as follows:
|
||||
* If a packet arrives, hold off interrupts until
|
||||
* cqicb->int_delay expires, but if no other packets arrive don't
|
||||
* wait longer than cqicb->pkt_int_delay. But ethtool doesn't use a
|
||||
* timer to coalesce on a frame basis. So, we have to take ethtool's
|
||||
* max_coalesced_frames value and convert it to a delay in microseconds.
|
||||
* We do this by using a basic thoughput of 1,000,000 frames per
|
||||
* second @ (1024 bytes). This means one frame per usec. So it's a
|
||||
* simple one to one ratio.
|
||||
*/
|
||||
c->rx_max_coalesced_frames = qdev->rx_max_coalesced_frames;
|
||||
c->tx_max_coalesced_frames = qdev->tx_max_coalesced_frames;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qlge_set_coalesce(struct net_device *ndev,
|
||||
struct ethtool_coalesce *c,
|
||||
struct kernel_ethtool_coalesce *kernel_coal,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
/* Validate user parameters. */
|
||||
if (c->rx_coalesce_usecs > qdev->rx_ring_size / 2)
|
||||
return -EINVAL;
|
||||
/* Don't wait more than 10 usec. */
|
||||
if (c->rx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
|
||||
return -EINVAL;
|
||||
if (c->tx_coalesce_usecs > qdev->tx_ring_size / 2)
|
||||
return -EINVAL;
|
||||
if (c->tx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
|
||||
return -EINVAL;
|
||||
|
||||
/* Verify a change took place before updating the hardware. */
|
||||
if (qdev->rx_coalesce_usecs == c->rx_coalesce_usecs &&
|
||||
qdev->tx_coalesce_usecs == c->tx_coalesce_usecs &&
|
||||
qdev->rx_max_coalesced_frames == c->rx_max_coalesced_frames &&
|
||||
qdev->tx_max_coalesced_frames == c->tx_max_coalesced_frames)
|
||||
return 0;
|
||||
|
||||
qdev->rx_coalesce_usecs = c->rx_coalesce_usecs;
|
||||
qdev->tx_coalesce_usecs = c->tx_coalesce_usecs;
|
||||
qdev->rx_max_coalesced_frames = c->rx_max_coalesced_frames;
|
||||
qdev->tx_max_coalesced_frames = c->tx_max_coalesced_frames;
|
||||
|
||||
return qlge_update_ring_coalescing(qdev);
|
||||
}
|
||||
|
||||
static void qlge_get_pauseparam(struct net_device *ndev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
qlge_mb_get_port_cfg(qdev);
|
||||
if (qdev->link_config & CFG_PAUSE_STD) {
|
||||
pause->rx_pause = 1;
|
||||
pause->tx_pause = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int qlge_set_pauseparam(struct net_device *ndev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
if ((pause->rx_pause) && (pause->tx_pause))
|
||||
qdev->link_config |= CFG_PAUSE_STD;
|
||||
else if (!pause->rx_pause && !pause->tx_pause)
|
||||
qdev->link_config &= ~CFG_PAUSE_STD;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return qlge_mb_set_port_cfg(qdev);
|
||||
}
|
||||
|
||||
static u32 qlge_get_msglevel(struct net_device *ndev)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
return qdev->msg_enable;
|
||||
}
|
||||
|
||||
static void qlge_set_msglevel(struct net_device *ndev, u32 value)
|
||||
{
|
||||
struct qlge_adapter *qdev = netdev_to_qdev(ndev);
|
||||
|
||||
qdev->msg_enable = value;
|
||||
}
|
||||
|
||||
const struct ethtool_ops qlge_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_MAX_FRAMES,
|
||||
.get_drvinfo = qlge_get_drvinfo,
|
||||
.get_wol = qlge_get_wol,
|
||||
.set_wol = qlge_set_wol,
|
||||
.get_regs_len = qlge_get_regs_len,
|
||||
.get_regs = qlge_get_regs,
|
||||
.get_msglevel = qlge_get_msglevel,
|
||||
.set_msglevel = qlge_set_msglevel,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.set_phys_id = qlge_set_phys_id,
|
||||
.self_test = qlge_self_test,
|
||||
.get_pauseparam = qlge_get_pauseparam,
|
||||
.set_pauseparam = qlge_set_pauseparam,
|
||||
.get_coalesce = qlge_get_coalesce,
|
||||
.set_coalesce = qlge_set_coalesce,
|
||||
.get_sset_count = qlge_get_sset_count,
|
||||
.get_strings = qlge_get_strings,
|
||||
.get_ethtool_stats = qlge_get_ethtool_stats,
|
||||
.get_link_ksettings = qlge_get_link_ksettings,
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user