qlogic: Move the QLogic drivers

Moves the QLogic drivers into drivers/net/ethernet/qlogic/ and
the necessary Kconfig and Makefile changes.

CC: Ron Mercer <ron.mercer@qlogic.com>
CC: Amit Kumar Salecha <amit.salecha@qlogic.com>
CC: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Acked-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
This commit is contained in:
Jeff Kirsher
2011-04-08 19:06:30 -07:00
parent dee1ad47f2
commit aa43c2158d
32 changed files with 67 additions and 33 deletions

View File

@@ -0,0 +1,53 @@
#
# QLogic network device configuration
#
config NET_VENDOR_QLOGIC
bool "QLogic devices"
depends on PCI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about QLogic cards. If you say Y, you will be asked for
your specific card in the following questions.
if NET_VENDOR_QLOGIC
config QLA3XXX
tristate "QLogic QLA3XXX Network Driver Support"
depends on PCI
---help---
This driver supports QLogic ISP3XXX gigabit Ethernet cards.
To compile this driver as a module, choose M here: the module
will be called qla3xxx.
config QLCNIC
tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support"
depends on PCI
select FW_LOADER
---help---
This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
devices.
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI
---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.
config NETXEN_NIC
tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
depends on PCI
select FW_LOADER
---help---
This enables the support for NetXen's Gigabit Ethernet card.
endif # NET_VENDOR_QLOGIC

View File

@@ -0,0 +1,8 @@
#
# Makefile for the QLogic network device drivers.
#
obj-$(CONFIG_QLA3XXX) += qla3xxx.o
obj-$(CONFIG_QLCNIC) += qlcnic/
obj-$(CONFIG_QLGE) += qlge/
obj-$(CONFIG_NETXEN_NIC) += netxen/

View File

@@ -0,0 +1,29 @@
# Copyright (C) 2003 - 2009 NetXen, Inc.
# Copyright (C) 2009 - QLogic Corporation.
# All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.
#
# The full GNU General Public License is included in this distribution
# in the file called "COPYING".
#
#
obj-$(CONFIG_NETXEN_NIC) := netxen_nic.o
netxen_nic-y := netxen_nic_hw.o netxen_nic_main.o netxen_nic_init.o \
netxen_nic_ethtool.o netxen_nic_ctx.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,793 @@
/*
* Copyright (C) 2003 - 2009 NetXen, Inc.
* Copyright (C) 2009 - QLogic Corporation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
* in the file called "COPYING".
*
*/
#include "netxen_nic_hw.h"
#include "netxen_nic.h"
#define NXHAL_VERSION 1
static u32
netxen_poll_rsp(struct netxen_adapter *adapter)
{
u32 rsp = NX_CDRP_RSP_OK;
int timeout = 0;
do {
/* give atleast 1ms for firmware to respond */
msleep(1);
if (++timeout > NX_OS_CRB_RETRY_COUNT)
return NX_CDRP_RSP_TIMEOUT;
rsp = NXRD32(adapter, NX_CDRP_CRB_OFFSET);
} while (!NX_CDRP_IS_RSP(rsp));
return rsp;
}
static u32
netxen_issue_cmd(struct netxen_adapter *adapter,
u32 pci_fn, u32 version, u32 arg1, u32 arg2, u32 arg3, u32 cmd)
{
u32 rsp;
u32 signature = 0;
u32 rcode = NX_RCODE_SUCCESS;
signature = NX_CDRP_SIGNATURE_MAKE(pci_fn, version);
/* Acquire semaphore before accessing CRB */
if (netxen_api_lock(adapter))
return NX_RCODE_TIMEOUT;
NXWR32(adapter, NX_SIGN_CRB_OFFSET, signature);
NXWR32(adapter, NX_ARG1_CRB_OFFSET, arg1);
NXWR32(adapter, NX_ARG2_CRB_OFFSET, arg2);
NXWR32(adapter, NX_ARG3_CRB_OFFSET, arg3);
NXWR32(adapter, NX_CDRP_CRB_OFFSET, NX_CDRP_FORM_CMD(cmd));
rsp = netxen_poll_rsp(adapter);
if (rsp == NX_CDRP_RSP_TIMEOUT) {
printk(KERN_ERR "%s: card response timeout.\n",
netxen_nic_driver_name);
rcode = NX_RCODE_TIMEOUT;
} else if (rsp == NX_CDRP_RSP_FAIL) {
rcode = NXRD32(adapter, NX_ARG1_CRB_OFFSET);
printk(KERN_ERR "%s: failed card response code:0x%x\n",
netxen_nic_driver_name, rcode);
}
/* Release semaphore */
netxen_api_unlock(adapter);
return rcode;
}
int
nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu)
{
u32 rcode = NX_RCODE_SUCCESS;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
rcode = netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
recv_ctx->context_id,
mtu,
0,
NX_CDRP_CMD_SET_MTU);
if (rcode != NX_RCODE_SUCCESS)
return -EIO;
return 0;
}
int
nx_fw_cmd_set_gbe_port(struct netxen_adapter *adapter,
u32 speed, u32 duplex, u32 autoneg)
{
return netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
speed,
duplex,
autoneg,
NX_CDRP_CMD_CONFIG_GBE_PORT);
}
static int
nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
{
void *addr;
nx_hostrq_rx_ctx_t *prq;
nx_cardrsp_rx_ctx_t *prsp;
nx_hostrq_rds_ring_t *prq_rds;
nx_hostrq_sds_ring_t *prq_sds;
nx_cardrsp_rds_ring_t *prsp_rds;
nx_cardrsp_sds_ring_t *prsp_sds;
struct nx_host_rds_ring *rds_ring;
struct nx_host_sds_ring *sds_ring;
dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
u64 phys_addr;
int i, nrds_rings, nsds_rings;
size_t rq_size, rsp_size;
u32 cap, reg, val;
int err;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
nrds_rings = adapter->max_rds_rings;
nsds_rings = adapter->max_sds_rings;
rq_size =
SIZEOF_HOSTRQ_RX(nx_hostrq_rx_ctx_t, nrds_rings, nsds_rings);
rsp_size =
SIZEOF_CARDRSP_RX(nx_cardrsp_rx_ctx_t, nrds_rings, nsds_rings);
addr = pci_alloc_consistent(adapter->pdev,
rq_size, &hostrq_phys_addr);
if (addr == NULL)
return -ENOMEM;
prq = addr;
addr = pci_alloc_consistent(adapter->pdev,
rsp_size, &cardrsp_phys_addr);
if (addr == NULL) {
err = -ENOMEM;
goto out_free_rq;
}
prsp = addr;
prq->host_rsp_dma_addr = cpu_to_le64(cardrsp_phys_addr);
cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN);
cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS);
prq->capabilities[0] = cpu_to_le32(cap);
prq->host_int_crb_mode =
cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED);
prq->host_rds_crb_mode =
cpu_to_le32(NX_HOST_RDS_CRB_MODE_UNIQUE);
prq->num_rds_rings = cpu_to_le16(nrds_rings);
prq->num_sds_rings = cpu_to_le16(nsds_rings);
prq->rds_ring_offset = cpu_to_le32(0);
val = le32_to_cpu(prq->rds_ring_offset) +
(sizeof(nx_hostrq_rds_ring_t) * nrds_rings);
prq->sds_ring_offset = cpu_to_le32(val);
prq_rds = (nx_hostrq_rds_ring_t *)(prq->data +
le32_to_cpu(prq->rds_ring_offset));
for (i = 0; i < nrds_rings; i++) {
rds_ring = &recv_ctx->rds_rings[i];
prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
prq_rds[i].ring_kind = cpu_to_le32(i);
prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
}
prq_sds = (nx_hostrq_sds_ring_t *)(prq->data +
le32_to_cpu(prq->sds_ring_offset));
for (i = 0; i < nsds_rings; i++) {
sds_ring = &recv_ctx->sds_rings[i];
prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
prq_sds[i].msi_index = cpu_to_le16(i);
}
phys_addr = hostrq_phys_addr;
err = netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
(u32)(phys_addr >> 32),
(u32)(phys_addr & 0xffffffff),
rq_size,
NX_CDRP_CMD_CREATE_RX_CTX);
if (err) {
printk(KERN_WARNING
"Failed to create rx ctx in firmware%d\n", err);
goto out_free_rsp;
}
prsp_rds = ((nx_cardrsp_rds_ring_t *)
&prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
rds_ring = &recv_ctx->rds_rings[i];
reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
rds_ring->crb_rcv_producer = netxen_get_ioaddr(adapter,
NETXEN_NIC_REG(reg - 0x200));
}
prsp_sds = ((nx_cardrsp_sds_ring_t *)
&prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);
for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
sds_ring = &recv_ctx->sds_rings[i];
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
sds_ring->crb_sts_consumer = netxen_get_ioaddr(adapter,
NETXEN_NIC_REG(reg - 0x200));
reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
sds_ring->crb_intr_mask = netxen_get_ioaddr(adapter,
NETXEN_NIC_REG(reg - 0x200));
}
recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
recv_ctx->context_id = le16_to_cpu(prsp->context_id);
recv_ctx->virt_port = prsp->virt_port;
out_free_rsp:
pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr);
out_free_rq:
pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr);
return err;
}
static void
nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
if (netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
recv_ctx->context_id,
NX_DESTROY_CTX_RESET,
0,
NX_CDRP_CMD_DESTROY_RX_CTX)) {
printk(KERN_WARNING
"%s: Failed to destroy rx ctx in firmware\n",
netxen_nic_driver_name);
}
}
static int
nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
{
nx_hostrq_tx_ctx_t *prq;
nx_hostrq_cds_ring_t *prq_cds;
nx_cardrsp_tx_ctx_t *prsp;
void *rq_addr, *rsp_addr;
size_t rq_size, rsp_size;
u32 temp;
int err = 0;
u64 offset, phys_addr;
dma_addr_t rq_phys_addr, rsp_phys_addr;
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
rq_size = SIZEOF_HOSTRQ_TX(nx_hostrq_tx_ctx_t);
rq_addr = pci_alloc_consistent(adapter->pdev,
rq_size, &rq_phys_addr);
if (!rq_addr)
return -ENOMEM;
rsp_size = SIZEOF_CARDRSP_TX(nx_cardrsp_tx_ctx_t);
rsp_addr = pci_alloc_consistent(adapter->pdev,
rsp_size, &rsp_phys_addr);
if (!rsp_addr) {
err = -ENOMEM;
goto out_free_rq;
}
memset(rq_addr, 0, rq_size);
prq = rq_addr;
memset(rsp_addr, 0, rsp_size);
prsp = rsp_addr;
prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
temp = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN | NX_CAP0_LSO);
prq->capabilities[0] = cpu_to_le32(temp);
prq->host_int_crb_mode =
cpu_to_le32(NX_HOST_INT_CRB_MODE_SHARED);
prq->interrupt_ctl = 0;
prq->msi_index = 0;
prq->dummy_dma_addr = cpu_to_le64(adapter->dummy_dma.phys_addr);
offset = recv_ctx->phys_addr + sizeof(struct netxen_ring_ctx);
prq->cmd_cons_dma_addr = cpu_to_le64(offset);
prq_cds = &prq->cds_ring;
prq_cds->host_phys_addr = cpu_to_le64(tx_ring->phys_addr);
prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
phys_addr = rq_phys_addr;
err = netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
(u32)(phys_addr >> 32),
((u32)phys_addr & 0xffffffff),
rq_size,
NX_CDRP_CMD_CREATE_TX_CTX);
if (err == NX_RCODE_SUCCESS) {
temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
tx_ring->crb_cmd_producer = netxen_get_ioaddr(adapter,
NETXEN_NIC_REG(temp - 0x200));
#if 0
adapter->tx_state =
le32_to_cpu(prsp->host_ctx_state);
#endif
adapter->tx_context_id =
le16_to_cpu(prsp->context_id);
} else {
printk(KERN_WARNING
"Failed to create tx ctx in firmware%d\n", err);
err = -EIO;
}
pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr);
out_free_rq:
pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr);
return err;
}
static void
nx_fw_cmd_destroy_tx_ctx(struct netxen_adapter *adapter)
{
if (netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
adapter->tx_context_id,
NX_DESTROY_CTX_RESET,
0,
NX_CDRP_CMD_DESTROY_TX_CTX)) {
printk(KERN_WARNING
"%s: Failed to destroy tx ctx in firmware\n",
netxen_nic_driver_name);
}
}
int
nx_fw_cmd_query_phy(struct netxen_adapter *adapter, u32 reg, u32 *val)
{
u32 rcode;
rcode = netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
reg,
0,
0,
NX_CDRP_CMD_READ_PHY);
if (rcode != NX_RCODE_SUCCESS)
return -EIO;
return NXRD32(adapter, NX_ARG1_CRB_OFFSET);
}
int
nx_fw_cmd_set_phy(struct netxen_adapter *adapter, u32 reg, u32 val)
{
u32 rcode;
rcode = netxen_issue_cmd(adapter,
adapter->ahw.pci_func,
NXHAL_VERSION,
reg,
val,
0,
NX_CDRP_CMD_WRITE_PHY);
if (rcode != NX_RCODE_SUCCESS)
return -EIO;
return 0;
}
static u64 ctx_addr_sig_regs[][3] = {
{NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
{NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
{NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
{NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
};
#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0])
#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2])
#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1])
#define lower32(x) ((u32)((x) & 0xffffffff))
#define upper32(x) ((u32)(((u64)(x) >> 32) & 0xffffffff))
static struct netxen_recv_crb recv_crb_registers[] = {
/* Instance 0 */
{
/* crb_rcv_producer: */
{
NETXEN_NIC_REG(0x100),
/* Jumbo frames */
NETXEN_NIC_REG(0x110),
/* LRO */
NETXEN_NIC_REG(0x120)
},
/* crb_sts_consumer: */
{
NETXEN_NIC_REG(0x138),
NETXEN_NIC_REG_2(0x000),
NETXEN_NIC_REG_2(0x004),
NETXEN_NIC_REG_2(0x008),
},
/* sw_int_mask */
{
CRB_SW_INT_MASK_0,
NETXEN_NIC_REG_2(0x044),
NETXEN_NIC_REG_2(0x048),
NETXEN_NIC_REG_2(0x04c),
},
},
/* Instance 1 */
{
/* crb_rcv_producer: */
{
NETXEN_NIC_REG(0x144),
/* Jumbo frames */
NETXEN_NIC_REG(0x154),
/* LRO */
NETXEN_NIC_REG(0x164)
},
/* crb_sts_consumer: */
{
NETXEN_NIC_REG(0x17c),
NETXEN_NIC_REG_2(0x020),
NETXEN_NIC_REG_2(0x024),
NETXEN_NIC_REG_2(0x028),
},
/* sw_int_mask */
{
CRB_SW_INT_MASK_1,
NETXEN_NIC_REG_2(0x064),
NETXEN_NIC_REG_2(0x068),
NETXEN_NIC_REG_2(0x06c),
},
},
/* Instance 2 */
{
/* crb_rcv_producer: */
{
NETXEN_NIC_REG(0x1d8),
/* Jumbo frames */
NETXEN_NIC_REG(0x1f8),
/* LRO */
NETXEN_NIC_REG(0x208)
},
/* crb_sts_consumer: */
{
NETXEN_NIC_REG(0x220),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
},
/* sw_int_mask */
{
CRB_SW_INT_MASK_2,
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
},
},
/* Instance 3 */
{
/* crb_rcv_producer: */
{
NETXEN_NIC_REG(0x22c),
/* Jumbo frames */
NETXEN_NIC_REG(0x23c),
/* LRO */
NETXEN_NIC_REG(0x24c)
},
/* crb_sts_consumer: */
{
NETXEN_NIC_REG(0x264),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
},
/* sw_int_mask */
{
CRB_SW_INT_MASK_3,
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
NETXEN_NIC_REG_2(0x03c),
},
},
};
static int
netxen_init_old_ctx(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx;
struct nx_host_rds_ring *rds_ring;
struct nx_host_sds_ring *sds_ring;
struct nx_host_tx_ring *tx_ring;
int ring;
int port = adapter->portnum;
struct netxen_ring_ctx *hwctx;
u32 signature;
tx_ring = adapter->tx_ring;
recv_ctx = &adapter->recv_ctx;
hwctx = recv_ctx->hwctx;
hwctx->cmd_ring_addr = cpu_to_le64(tx_ring->phys_addr);
hwctx->cmd_ring_size = cpu_to_le32(tx_ring->num_desc);
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
hwctx->rcv_rings[ring].addr =
cpu_to_le64(rds_ring->phys_addr);
hwctx->rcv_rings[ring].size =
cpu_to_le32(rds_ring->num_desc);
}
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (ring == 0) {
hwctx->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr);
hwctx->sts_ring_size = cpu_to_le32(sds_ring->num_desc);
}
hwctx->sts_rings[ring].addr = cpu_to_le64(sds_ring->phys_addr);
hwctx->sts_rings[ring].size = cpu_to_le32(sds_ring->num_desc);
hwctx->sts_rings[ring].msi_index = cpu_to_le16(ring);
}
hwctx->sts_ring_count = cpu_to_le32(adapter->max_sds_rings);
signature = (adapter->max_sds_rings > 1) ?
NETXEN_CTX_SIGNATURE_V2 : NETXEN_CTX_SIGNATURE;
NXWR32(adapter, CRB_CTX_ADDR_REG_LO(port),
lower32(recv_ctx->phys_addr));
NXWR32(adapter, CRB_CTX_ADDR_REG_HI(port),
upper32(recv_ctx->phys_addr));
NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port),
signature | port);
return 0;
}
int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
{
void *addr;
int err = 0;
int ring;
struct netxen_recv_context *recv_ctx;
struct nx_host_rds_ring *rds_ring;
struct nx_host_sds_ring *sds_ring;
struct nx_host_tx_ring *tx_ring;
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
int port = adapter->portnum;
recv_ctx = &adapter->recv_ctx;
tx_ring = adapter->tx_ring;
addr = pci_alloc_consistent(pdev,
sizeof(struct netxen_ring_ctx) + sizeof(uint32_t),
&recv_ctx->phys_addr);
if (addr == NULL) {
dev_err(&pdev->dev, "failed to allocate hw context\n");
return -ENOMEM;
}
memset(addr, 0, sizeof(struct netxen_ring_ctx));
recv_ctx->hwctx = addr;
recv_ctx->hwctx->ctx_id = cpu_to_le32(port);
recv_ctx->hwctx->cmd_consumer_offset =
cpu_to_le64(recv_ctx->phys_addr +
sizeof(struct netxen_ring_ctx));
tx_ring->hw_consumer =
(__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx));
/* cmd desc ring */
addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring),
&tx_ring->phys_addr);
if (addr == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n",
netdev->name);
err = -ENOMEM;
goto err_out_free;
}
tx_ring->desc_head = addr;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
addr = pci_alloc_consistent(adapter->pdev,
RCV_DESC_RINGSIZE(rds_ring),
&rds_ring->phys_addr);
if (addr == NULL) {
dev_err(&pdev->dev,
"%s: failed to allocate rds ring [%d]\n",
netdev->name, ring);
err = -ENOMEM;
goto err_out_free;
}
rds_ring->desc_head = addr;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
rds_ring->crb_rcv_producer =
netxen_get_ioaddr(adapter,
recv_crb_registers[port].crb_rcv_producer[ring]);
}
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
addr = pci_alloc_consistent(adapter->pdev,
STATUS_DESC_RINGSIZE(sds_ring),
&sds_ring->phys_addr);
if (addr == NULL) {
dev_err(&pdev->dev,
"%s: failed to allocate sds ring [%d]\n",
netdev->name, ring);
err = -ENOMEM;
goto err_out_free;
}
sds_ring->desc_head = addr;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
sds_ring->crb_sts_consumer =
netxen_get_ioaddr(adapter,
recv_crb_registers[port].crb_sts_consumer[ring]);
sds_ring->crb_intr_mask =
netxen_get_ioaddr(adapter,
recv_crb_registers[port].sw_int_mask[ring]);
}
}
if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
if (test_and_set_bit(__NX_FW_ATTACHED, &adapter->state))
goto done;
err = nx_fw_cmd_create_rx_ctx(adapter);
if (err)
goto err_out_free;
err = nx_fw_cmd_create_tx_ctx(adapter);
if (err)
goto err_out_free;
} else {
err = netxen_init_old_ctx(adapter);
if (err)
goto err_out_free;
}
done:
return 0;
err_out_free:
netxen_free_hw_resources(adapter);
return err;
}
void netxen_free_hw_resources(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx;
struct nx_host_rds_ring *rds_ring;
struct nx_host_sds_ring *sds_ring;
struct nx_host_tx_ring *tx_ring;
int ring;
int port = adapter->portnum;
if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
if (!test_and_clear_bit(__NX_FW_ATTACHED, &adapter->state))
goto done;
nx_fw_cmd_destroy_rx_ctx(adapter);
nx_fw_cmd_destroy_tx_ctx(adapter);
} else {
netxen_api_lock(adapter);
NXWR32(adapter, CRB_CTX_SIGNATURE_REG(port),
NETXEN_CTX_D3_RESET | port);
netxen_api_unlock(adapter);
}
/* Allow dma queues to drain after context reset */
msleep(20);
done:
recv_ctx = &adapter->recv_ctx;
if (recv_ctx->hwctx != NULL) {
pci_free_consistent(adapter->pdev,
sizeof(struct netxen_ring_ctx) +
sizeof(uint32_t),
recv_ctx->hwctx,
recv_ctx->phys_addr);
recv_ctx->hwctx = NULL;
}
tx_ring = adapter->tx_ring;
if (tx_ring->desc_head != NULL) {
pci_free_consistent(adapter->pdev,
TX_DESC_RINGSIZE(tx_ring),
tx_ring->desc_head, tx_ring->phys_addr);
tx_ring->desc_head = NULL;
}
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
if (rds_ring->desc_head != NULL) {
pci_free_consistent(adapter->pdev,
RCV_DESC_RINGSIZE(rds_ring),
rds_ring->desc_head,
rds_ring->phys_addr);
rds_ring->desc_head = NULL;
}
}
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (sds_ring->desc_head != NULL) {
pci_free_consistent(adapter->pdev,
STATUS_DESC_RINGSIZE(sds_ring),
sds_ring->desc_head,
sds_ring->phys_addr);
sds_ring->desc_head = NULL;
}
}
}

View File

@@ -0,0 +1,835 @@
/*
* Copyright (C) 2003 - 2009 NetXen, Inc.
* Copyright (C) 2009 - QLogic Corporation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
* in the file called "COPYING".
*
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
struct netxen_nic_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
int stat_offset;
};
#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \
offsetof(struct netxen_adapter, m)
#define NETXEN_NIC_PORT_WINDOW 0x10000
#define NETXEN_NIC_INVALID_DATA 0xDEADBEEF
static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = {
{"xmit_called", NETXEN_NIC_STAT(stats.xmitcalled)},
{"xmit_finished", NETXEN_NIC_STAT(stats.xmitfinished)},
{"rx_dropped", NETXEN_NIC_STAT(stats.rxdropped)},
{"tx_dropped", NETXEN_NIC_STAT(stats.txdropped)},
{"csummed", NETXEN_NIC_STAT(stats.csummed)},
{"rx_pkts", NETXEN_NIC_STAT(stats.rx_pkts)},
{"lro_pkts", NETXEN_NIC_STAT(stats.lro_pkts)},
{"rx_bytes", NETXEN_NIC_STAT(stats.rxbytes)},
{"tx_bytes", NETXEN_NIC_STAT(stats.txbytes)},
};
#define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats)
static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline"
};
#define NETXEN_NIC_TEST_LEN ARRAY_SIZE(netxen_nic_gstrings_test)
#define NETXEN_NIC_REGS_COUNT 30
#define NETXEN_NIC_REGS_LEN (NETXEN_NIC_REGS_COUNT * sizeof(__le32))
#define NETXEN_MAX_EEPROM_LEN 1024
static int netxen_nic_get_eeprom_len(struct net_device *dev)
{
return NETXEN_FLASH_TOTAL_SIZE;
}
static void
netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 fw_major = 0;
u32 fw_minor = 0;
u32 fw_build = 0;
strncpy(drvinfo->driver, netxen_nic_driver_name, 32);
strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32);
fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
}
static int
netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct netxen_adapter *adapter = netdev_priv(dev);
int check_sfp_module = 0;
/* read which mode */
if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full);
ecmd->advertising = (ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full);
ecmd->port = PORT_TP;
ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->duplex = adapter->link_duplex;
ecmd->autoneg = adapter->link_autoneg;
} else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
u32 val;
val = NXRD32(adapter, NETXEN_PORT_MODE_ADDR);
if (val == NETXEN_PORT_MODE_802_3_AP) {
ecmd->supported = SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_1000baseT_Full;
} else {
ecmd->supported = SUPPORTED_10000baseT_Full;
ecmd->advertising = ADVERTISED_10000baseT_Full;
}
if (netif_running(dev) && adapter->has_link_events) {
ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->autoneg = adapter->link_autoneg;
ecmd->duplex = adapter->link_duplex;
goto skip;
}
ecmd->port = PORT_TP;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
u16 pcifn = adapter->ahw.pci_func;
val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn));
ethtool_cmd_speed_set(ecmd, P3_LINK_SPEED_MHZ *
P3_LINK_SPEED_VAL(pcifn, val));
} else
ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = AUTONEG_DISABLE;
} else
return -EIO;
skip:
ecmd->phy_address = adapter->physical_port;
ecmd->transceiver = XCVR_EXTERNAL;
switch (adapter->ahw.board_type) {
case NETXEN_BRDTYPE_P2_SB35_4G:
case NETXEN_BRDTYPE_P2_SB31_2G:
case NETXEN_BRDTYPE_P3_REF_QG:
case NETXEN_BRDTYPE_P3_4_GB:
case NETXEN_BRDTYPE_P3_4_GB_MM:
ecmd->supported |= SUPPORTED_Autoneg;
ecmd->advertising |= ADVERTISED_Autoneg;
case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
case NETXEN_BRDTYPE_P3_10G_CX4:
case NETXEN_BRDTYPE_P3_10G_CX4_LP:
case NETXEN_BRDTYPE_P3_10000_BASE_T:
ecmd->supported |= SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_TP;
ecmd->port = PORT_TP;
ecmd->autoneg = (adapter->ahw.board_type ==
NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
(AUTONEG_DISABLE) : (adapter->link_autoneg);
break;
case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
case NETXEN_BRDTYPE_P3_IMEZ:
case NETXEN_BRDTYPE_P3_XG_LOM:
case NETXEN_BRDTYPE_P3_HMEZ:
ecmd->supported |= SUPPORTED_MII;
ecmd->advertising |= ADVERTISED_MII;
ecmd->port = PORT_MII;
ecmd->autoneg = AUTONEG_DISABLE;
break;
case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
case NETXEN_BRDTYPE_P3_10G_SFP_CT:
case NETXEN_BRDTYPE_P3_10G_SFP_QT:
ecmd->advertising |= ADVERTISED_TP;
ecmd->supported |= SUPPORTED_TP;
check_sfp_module = netif_running(dev) &&
adapter->has_link_events;
case NETXEN_BRDTYPE_P2_SB31_10G:
case NETXEN_BRDTYPE_P3_10G_XFP:
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
ecmd->port = PORT_FIBRE;
ecmd->autoneg = AUTONEG_DISABLE;
break;
case NETXEN_BRDTYPE_P3_10G_TP:
if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
ecmd->advertising |=
(ADVERTISED_FIBRE | ADVERTISED_TP);
ecmd->port = PORT_FIBRE;
check_sfp_module = netif_running(dev) &&
adapter->has_link_events;
} else {
ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg);
ecmd->advertising |=
(ADVERTISED_TP | ADVERTISED_Autoneg);
ecmd->port = PORT_TP;
}
break;
default:
printk(KERN_ERR "netxen-nic: Unsupported board model %d\n",
adapter->ahw.board_type);
return -EIO;
}
if (check_sfp_module) {
switch (adapter->module_type) {
case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
case LINKEVENT_MODULE_OPTICAL_SRLR:
case LINKEVENT_MODULE_OPTICAL_LRM:
case LINKEVENT_MODULE_OPTICAL_SFP_1G:
ecmd->port = PORT_FIBRE;
break;
case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
case LINKEVENT_MODULE_TWINAX:
ecmd->port = PORT_TP;
break;
default:
ecmd->port = -1;
}
}
return 0;
}
static int
netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 speed = ethtool_cmd_speed(ecmd);
int ret;
if (adapter->ahw.port_type != NETXEN_NIC_GBE)
return -EOPNOTSUPP;
if (!(adapter->capabilities & NX_FW_CAPABILITY_GBE_LINK_CFG))
return -EOPNOTSUPP;
ret = nx_fw_cmd_set_gbe_port(adapter, speed, ecmd->duplex,
ecmd->autoneg);
if (ret == NX_RCODE_NOT_SUPPORTED)
return -EOPNOTSUPP;
else if (ret)
return -EIO;
adapter->link_speed = speed;
adapter->link_duplex = ecmd->duplex;
adapter->link_autoneg = ecmd->autoneg;
if (!netif_running(dev))
return 0;
dev->netdev_ops->ndo_stop(dev);
return dev->netdev_ops->ndo_open(dev);
}
static int netxen_nic_get_regs_len(struct net_device *dev)
{
return NETXEN_NIC_REGS_LEN;
}
static void
netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
struct netxen_adapter *adapter = netdev_priv(dev);
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
struct nx_host_sds_ring *sds_ring;
u32 *regs_buff = p;
int ring, i = 0;
int port = adapter->physical_port;
memset(p, 0, NETXEN_NIC_REGS_LEN);
regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
(adapter->pdev)->device;
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
return;
regs_buff[i++] = NXRD32(adapter, CRB_CMDPEG_STATE);
regs_buff[i++] = NXRD32(adapter, CRB_RCVPEG_STATE);
regs_buff[i++] = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
regs_buff[i++] = NXRDIO(adapter, adapter->crb_int_state_reg);
regs_buff[i++] = NXRD32(adapter, NX_CRB_DEV_REF_COUNT);
regs_buff[i++] = NXRD32(adapter, NX_CRB_DEV_STATE);
regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER);
regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1);
regs_buff[i++] = NXRD32(adapter, NETXEN_PEG_HALT_STATUS2);
regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_0+0x3c);
regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_1+0x3c);
regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_2+0x3c);
regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_3+0x3c);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
regs_buff[i++] = NXRD32(adapter, NETXEN_CRB_PEG_NET_4+0x3c);
i += 2;
regs_buff[i++] = NXRD32(adapter, CRB_XG_STATE_P3);
regs_buff[i++] = le32_to_cpu(*(adapter->tx_ring->hw_consumer));
} else {
i++;
regs_buff[i++] = NXRD32(adapter,
NETXEN_NIU_XGE_CONFIG_0+(0x10000*port));
regs_buff[i++] = NXRD32(adapter,
NETXEN_NIU_XGE_CONFIG_1+(0x10000*port));
regs_buff[i++] = NXRD32(adapter, CRB_XG_STATE);
regs_buff[i++] = NXRDIO(adapter,
adapter->tx_ring->crb_cmd_consumer);
}
regs_buff[i++] = NXRDIO(adapter, adapter->tx_ring->crb_cmd_producer);
regs_buff[i++] = NXRDIO(adapter,
recv_ctx->rds_rings[0].crb_rcv_producer);
regs_buff[i++] = NXRDIO(adapter,
recv_ctx->rds_rings[1].crb_rcv_producer);
regs_buff[i++] = adapter->max_sds_rings;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &(recv_ctx->sds_rings[ring]);
regs_buff[i++] = NXRDIO(adapter,
sds_ring->crb_sts_consumer);
}
}
static u32 netxen_nic_test_link(struct net_device *dev)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 val, port;
port = adapter->physical_port;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
val = NXRD32(adapter, CRB_XG_STATE_P3);
val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
return (val == XG_LINK_UP_P3) ? 0 : 1;
} else {
val = NXRD32(adapter, CRB_XG_STATE);
val = (val >> port*8) & 0xff;
return (val == XG_LINK_UP) ? 0 : 1;
}
}
static int
netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * bytes)
{
struct netxen_adapter *adapter = netdev_priv(dev);
int offset;
int ret;
if (eeprom->len == 0)
return -EINVAL;
eeprom->magic = (adapter->pdev)->vendor |
((adapter->pdev)->device << 16);
offset = eeprom->offset;
ret = netxen_rom_fast_read_words(adapter, offset, bytes,
eeprom->len);
if (ret < 0)
return ret;
return 0;
}
static void
netxen_nic_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct netxen_adapter *adapter = netdev_priv(dev);
ring->rx_pending = adapter->num_rxd;
ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
ring->rx_jumbo_pending += adapter->num_lro_rxd;
ring->tx_pending = adapter->num_txd;
if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
} else {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
}
ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
}
static u32
netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
{
u32 num_desc;
num_desc = max(val, min);
num_desc = min(num_desc, max);
num_desc = roundup_pow_of_two(num_desc);
if (val != num_desc) {
printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
netxen_nic_driver_name, r_name, num_desc, val);
}
return num_desc;
}
static int
netxen_nic_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
u16 num_rxd, num_jumbo_rxd, num_txd;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return -EOPNOTSUPP;
if (ring->rx_mini_pending)
return -EOPNOTSUPP;
if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
}
num_rxd = netxen_validate_ringparam(ring->rx_pending,
MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending,
MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
num_txd = netxen_validate_ringparam(ring->tx_pending,
MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
num_jumbo_rxd == adapter->num_jumbo_rxd)
return 0;
adapter->num_rxd = num_rxd;
adapter->num_jumbo_rxd = num_jumbo_rxd;
adapter->num_txd = num_txd;
return netxen_nic_reset_context(adapter);
}
static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
int port = adapter->physical_port;
if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return;
/* get flow control settings */
val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port));
pause->rx_pause = netxen_gb_get_rx_flowctl(val);
val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL);
switch (port) {
case 0:
pause->tx_pause = !(netxen_gb_get_gb0_mask(val));
break;
case 1:
pause->tx_pause = !(netxen_gb_get_gb1_mask(val));
break;
case 2:
pause->tx_pause = !(netxen_gb_get_gb2_mask(val));
break;
case 3:
default:
pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
break;
}
} else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return;
pause->rx_pause = 1;
val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL);
if (port == 0)
pause->tx_pause = !(netxen_xg_get_xg0_mask(val));
else
pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
} else {
printk(KERN_ERR"%s: Unknown board type: %x\n",
netxen_nic_driver_name, adapter->ahw.port_type);
}
}
static int
netxen_nic_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
int port = adapter->physical_port;
/* read mode */
if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EIO;
/* set flow control */
val = NXRD32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port));
if (pause->rx_pause)
netxen_gb_rx_flowctl(val);
else
netxen_gb_unset_rx_flowctl(val);
NXWR32(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
val);
/* set autoneg */
val = NXRD32(adapter, NETXEN_NIU_GB_PAUSE_CTL);
switch (port) {
case 0:
if (pause->tx_pause)
netxen_gb_unset_gb0_mask(val);
else
netxen_gb_set_gb0_mask(val);
break;
case 1:
if (pause->tx_pause)
netxen_gb_unset_gb1_mask(val);
else
netxen_gb_set_gb1_mask(val);
break;
case 2:
if (pause->tx_pause)
netxen_gb_unset_gb2_mask(val);
else
netxen_gb_set_gb2_mask(val);
break;
case 3:
default:
if (pause->tx_pause)
netxen_gb_unset_gb3_mask(val);
else
netxen_gb_set_gb3_mask(val);
break;
}
NXWR32(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
} else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return -EIO;
val = NXRD32(adapter, NETXEN_NIU_XG_PAUSE_CTL);
if (port == 0) {
if (pause->tx_pause)
netxen_xg_unset_xg0_mask(val);
else
netxen_xg_set_xg0_mask(val);
} else {
if (pause->tx_pause)
netxen_xg_unset_xg1_mask(val);
else
netxen_xg_set_xg1_mask(val);
}
NXWR32(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);
} else {
printk(KERN_ERR "%s: Unknown board type: %x\n",
netxen_nic_driver_name,
adapter->ahw.port_type);
}
return 0;
}
static int netxen_nic_reg_test(struct net_device *dev)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 data_read, data_written;
data_read = NXRD32(adapter, NETXEN_PCIX_PH_REG(0));
if ((data_read & 0xffff) != adapter->pdev->vendor)
return 1;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
return 0;
data_written = (u32)0xa5a5a5a5;
NXWR32(adapter, CRB_SCRATCHPAD_TEST, data_written);
data_read = NXRD32(adapter, CRB_SCRATCHPAD_TEST);
if (data_written != data_read)
return 1;
return 0;
}
static int netxen_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_TEST:
return NETXEN_NIC_TEST_LEN;
case ETH_SS_STATS:
return NETXEN_NIC_STATS_LEN;
default:
return -EOPNOTSUPP;
}
}
static void
netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 * data)
{
memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN);
if ((data[0] = netxen_nic_reg_test(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
/* link test */
if ((data[1] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
}
static void
netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
{
int index;
switch (stringset) {
case ETH_SS_TEST:
memcpy(data, *netxen_nic_gstrings_test,
NETXEN_NIC_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
memcpy(data + index * ETH_GSTRING_LEN,
netxen_nic_gstrings_stats[index].stat_string,
ETH_GSTRING_LEN);
}
break;
}
}
static void
netxen_nic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
{
struct netxen_adapter *adapter = netdev_priv(dev);
int index;
for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
char *p =
(char *)adapter +
netxen_nic_gstrings_stats[index].stat_offset;
data[index] =
(netxen_nic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
}
}
static void
netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 wol_cfg = 0;
wol->supported = 0;
wol->wolopts = 0;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return;
wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV);
if (wol_cfg & (1UL << adapter->portnum))
wol->supported |= WAKE_MAGIC;
wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG);
if (wol_cfg & (1UL << adapter->portnum))
wol->wolopts |= WAKE_MAGIC;
}
static int
netxen_nic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct netxen_adapter *adapter = netdev_priv(dev);
u32 wol_cfg = 0;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return -EOPNOTSUPP;
if (wol->wolopts & ~WAKE_MAGIC)
return -EOPNOTSUPP;
wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG_NV);
if (!(wol_cfg & (1 << adapter->portnum)))
return -EOPNOTSUPP;
wol_cfg = NXRD32(adapter, NETXEN_WOL_CONFIG);
if (wol->wolopts & WAKE_MAGIC)
wol_cfg |= 1UL << adapter->portnum;
else
wol_cfg &= ~(1UL << adapter->portnum);
NXWR32(adapter, NETXEN_WOL_CONFIG, wol_cfg);
return 0;
}
/*
* Set the coalescing parameters. Currently only normal is supported.
* If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
* firmware coalescing to default.
*/
static int netxen_set_intr_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ethcoal)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
if (!NX_IS_REVISION_P3(adapter->ahw.revision_id))
return -EINVAL;
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
return -EINVAL;
/*
* Return Error if unsupported values or
* unsupported parameters are set.
*/
if (ethcoal->rx_coalesce_usecs > 0xffff ||
ethcoal->rx_max_coalesced_frames > 0xffff ||
ethcoal->tx_coalesce_usecs > 0xffff ||
ethcoal->tx_max_coalesced_frames > 0xffff ||
ethcoal->rx_coalesce_usecs_irq ||
ethcoal->rx_max_coalesced_frames_irq ||
ethcoal->tx_coalesce_usecs_irq ||
ethcoal->tx_max_coalesced_frames_irq ||
ethcoal->stats_block_coalesce_usecs ||
ethcoal->use_adaptive_rx_coalesce ||
ethcoal->use_adaptive_tx_coalesce ||
ethcoal->pkt_rate_low ||
ethcoal->rx_coalesce_usecs_low ||
ethcoal->rx_max_coalesced_frames_low ||
ethcoal->tx_coalesce_usecs_low ||
ethcoal->tx_max_coalesced_frames_low ||
ethcoal->pkt_rate_high ||
ethcoal->rx_coalesce_usecs_high ||
ethcoal->rx_max_coalesced_frames_high ||
ethcoal->tx_coalesce_usecs_high ||
ethcoal->tx_max_coalesced_frames_high)
return -EINVAL;
if (!ethcoal->rx_coalesce_usecs ||
!ethcoal->rx_max_coalesced_frames) {
adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT;
adapter->coal.normal.data.rx_time_us =
NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US;
adapter->coal.normal.data.rx_packets =
NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS;
} else {
adapter->coal.flags = 0;
adapter->coal.normal.data.rx_time_us =
ethcoal->rx_coalesce_usecs;
adapter->coal.normal.data.rx_packets =
ethcoal->rx_max_coalesced_frames;
}
adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
adapter->coal.normal.data.tx_packets =
ethcoal->tx_max_coalesced_frames;
netxen_config_intr_coalesce(adapter);
return 0;
}
static int netxen_get_intr_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ethcoal)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
if (!NX_IS_REVISION_P3(adapter->ahw.revision_id))
return -EINVAL;
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
return -EINVAL;
ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
ethcoal->rx_max_coalesced_frames =
adapter->coal.normal.data.rx_packets;
ethcoal->tx_max_coalesced_frames =
adapter->coal.normal.data.tx_packets;
return 0;
}
const struct ethtool_ops netxen_nic_ethtool_ops = {
.get_settings = netxen_nic_get_settings,
.set_settings = netxen_nic_set_settings,
.get_drvinfo = netxen_nic_get_drvinfo,
.get_regs_len = netxen_nic_get_regs_len,
.get_regs = netxen_nic_get_regs,
.get_link = ethtool_op_get_link,
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
.set_ringparam = netxen_nic_set_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
.get_wol = netxen_nic_get_wol,
.set_wol = netxen_nic_set_wol,
.self_test = netxen_nic_diag_test,
.get_strings = netxen_nic_get_strings,
.get_ethtool_stats = netxen_nic_get_ethtool_stats,
.get_sset_count = netxen_get_sset_count,
.get_coalesce = netxen_get_intr_coalesce,
.set_coalesce = netxen_set_intr_coalesce,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,287 @@
/*
* Copyright (C) 2003 - 2009 NetXen, Inc.
* Copyright (C) 2009 - QLogic Corporation.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution
* in the file called "COPYING".
*
*/
#ifndef __NETXEN_NIC_HW_H_
#define __NETXEN_NIC_HW_H_
/* Hardware memory size of 128 meg */
#define NETXEN_MEMADDR_MAX (128 * 1024 * 1024)
struct netxen_adapter;
#define NETXEN_PCI_MAPSIZE_BYTES (NETXEN_PCI_MAPSIZE << 20)
void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
/* Nibble or Byte mode for phy interface (GbE mode only) */
#define _netxen_crb_get_bit(var, bit) ((var >> bit) & 0x1)
/*
* NIU GB MAC Config Register 0 (applies to GB0, GB1, GB2, GB3)
*
* Bit 0 : enable_tx => 1:enable frame xmit, 0:disable
* Bit 1 : tx_synced => R/O: xmit enable synched to xmit stream
* Bit 2 : enable_rx => 1:enable frame recv, 0:disable
* Bit 3 : rx_synced => R/O: recv enable synched to recv stream
* Bit 4 : tx_flowctl => 1:enable pause frame generation, 0:disable
* Bit 5 : rx_flowctl => 1:act on recv'd pause frames, 0:ignore
* Bit 8 : loopback => 1:loop MAC xmits to MAC recvs, 0:normal
* Bit 16: tx_reset_pb => 1:reset frame xmit protocol blk, 0:no-op
* Bit 17: rx_reset_pb => 1:reset frame recv protocol blk, 0:no-op
* Bit 18: tx_reset_mac => 1:reset data/ctl multiplexer blk, 0:no-op
* Bit 19: rx_reset_mac => 1:reset ctl frames & timers blk, 0:no-op
* Bit 31: soft_reset => 1:reset the MAC and the SERDES, 0:no-op
*/
#define netxen_gb_tx_flowctl(config_word) \
((config_word) |= 1 << 4)
#define netxen_gb_rx_flowctl(config_word) \
((config_word) |= 1 << 5)
#define netxen_gb_tx_reset_pb(config_word) \
((config_word) |= 1 << 16)
#define netxen_gb_rx_reset_pb(config_word) \
((config_word) |= 1 << 17)
#define netxen_gb_tx_reset_mac(config_word) \
((config_word) |= 1 << 18)
#define netxen_gb_rx_reset_mac(config_word) \
((config_word) |= 1 << 19)
#define netxen_gb_unset_tx_flowctl(config_word) \
((config_word) &= ~(1 << 4))
#define netxen_gb_unset_rx_flowctl(config_word) \
((config_word) &= ~(1 << 5))
#define netxen_gb_get_tx_synced(config_word) \
_netxen_crb_get_bit((config_word), 1)
#define netxen_gb_get_rx_synced(config_word) \
_netxen_crb_get_bit((config_word), 3)
#define netxen_gb_get_tx_flowctl(config_word) \
_netxen_crb_get_bit((config_word), 4)
#define netxen_gb_get_rx_flowctl(config_word) \
_netxen_crb_get_bit((config_word), 5)
#define netxen_gb_get_soft_reset(config_word) \
_netxen_crb_get_bit((config_word), 31)
#define netxen_gb_get_stationaddress_low(config_word) ((config_word) >> 16)
#define netxen_gb_set_mii_mgmt_clockselect(config_word, val) \
((config_word) |= ((val) & 0x07))
#define netxen_gb_mii_mgmt_reset(config_word) \
((config_word) |= 1 << 31)
#define netxen_gb_mii_mgmt_unset(config_word) \
((config_word) &= ~(1 << 31))
/*
* NIU GB MII Mgmt Command Register (applies to GB0, GB1, GB2, GB3)
* Bit 0 : read_cycle => 1:perform single read cycle, 0:no-op
* Bit 1 : scan_cycle => 1:perform continuous read cycles, 0:no-op
*/
#define netxen_gb_mii_mgmt_set_read_cycle(config_word) \
((config_word) |= 1 << 0)
#define netxen_gb_mii_mgmt_reg_addr(config_word, val) \
((config_word) |= ((val) & 0x1F))
#define netxen_gb_mii_mgmt_phy_addr(config_word, val) \
((config_word) |= (((val) & 0x1F) << 8))
/*
* NIU GB MII Mgmt Indicators Register (applies to GB0, GB1, GB2, GB3)
* Read-only register.
* Bit 0 : busy => 1:performing an MII mgmt cycle, 0:idle
* Bit 1 : scanning => 1:scan operation in progress, 0:idle
* Bit 2 : notvalid => :mgmt result data not yet valid, 0:idle
*/
#define netxen_get_gb_mii_mgmt_busy(config_word) \
_netxen_crb_get_bit(config_word, 0)
#define netxen_get_gb_mii_mgmt_scanning(config_word) \
_netxen_crb_get_bit(config_word, 1)
#define netxen_get_gb_mii_mgmt_notvalid(config_word) \
_netxen_crb_get_bit(config_word, 2)
/*
* NIU XG Pause Ctl Register
*
* Bit 0 : xg0_mask => 1:disable tx pause frames
* Bit 1 : xg0_request => 1:request single pause frame
* Bit 2 : xg0_on_off => 1:request is pause on, 0:off
* Bit 3 : xg1_mask => 1:disable tx pause frames
* Bit 4 : xg1_request => 1:request single pause frame
* Bit 5 : xg1_on_off => 1:request is pause on, 0:off
*/
#define netxen_xg_set_xg0_mask(config_word) \
((config_word) |= 1 << 0)
#define netxen_xg_set_xg1_mask(config_word) \
((config_word) |= 1 << 3)
#define netxen_xg_get_xg0_mask(config_word) \
_netxen_crb_get_bit((config_word), 0)
#define netxen_xg_get_xg1_mask(config_word) \
_netxen_crb_get_bit((config_word), 3)
#define netxen_xg_unset_xg0_mask(config_word) \
((config_word) &= ~(1 << 0))
#define netxen_xg_unset_xg1_mask(config_word) \
((config_word) &= ~(1 << 3))
/*
* NIU XG Pause Ctl Register
*
* Bit 0 : xg0_mask => 1:disable tx pause frames
* Bit 1 : xg0_request => 1:request single pause frame
* Bit 2 : xg0_on_off => 1:request is pause on, 0:off
* Bit 3 : xg1_mask => 1:disable tx pause frames
* Bit 4 : xg1_request => 1:request single pause frame
* Bit 5 : xg1_on_off => 1:request is pause on, 0:off
*/
#define netxen_gb_set_gb0_mask(config_word) \
((config_word) |= 1 << 0)
#define netxen_gb_set_gb1_mask(config_word) \
((config_word) |= 1 << 2)
#define netxen_gb_set_gb2_mask(config_word) \
((config_word) |= 1 << 4)
#define netxen_gb_set_gb3_mask(config_word) \
((config_word) |= 1 << 6)
#define netxen_gb_get_gb0_mask(config_word) \
_netxen_crb_get_bit((config_word), 0)
#define netxen_gb_get_gb1_mask(config_word) \
_netxen_crb_get_bit((config_word), 2)
#define netxen_gb_get_gb2_mask(config_word) \
_netxen_crb_get_bit((config_word), 4)
#define netxen_gb_get_gb3_mask(config_word) \
_netxen_crb_get_bit((config_word), 6)
#define netxen_gb_unset_gb0_mask(config_word) \
((config_word) &= ~(1 << 0))
#define netxen_gb_unset_gb1_mask(config_word) \
((config_word) &= ~(1 << 2))
#define netxen_gb_unset_gb2_mask(config_word) \
((config_word) &= ~(1 << 4))
#define netxen_gb_unset_gb3_mask(config_word) \
((config_word) &= ~(1 << 6))
/*
* PHY-Specific MII control/status registers.
*/
#define NETXEN_NIU_GB_MII_MGMT_ADDR_CONTROL 0
#define NETXEN_NIU_GB_MII_MGMT_ADDR_STATUS 1
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_0 2
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_ID_1 3
#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG 4
#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART 5
#define NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG_MORE 6
#define NETXEN_NIU_GB_MII_MGMT_ADDR_NEXTPAGE_XMIT 7
#define NETXEN_NIU_GB_MII_MGMT_ADDR_LNKPART_NEXTPAGE 8
#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_CONTROL 9
#define NETXEN_NIU_GB_MII_MGMT_ADDR_1000BT_STATUS 10
#define NETXEN_NIU_GB_MII_MGMT_ADDR_EXTENDED_STATUS 15
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL 16
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS 17
#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE 18
#define NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS 19
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE 20
#define NETXEN_NIU_GB_MII_MGMT_ADDR_RECV_ERROR_COUNT 21
#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_CONTROL 24
#define NETXEN_NIU_GB_MII_MGMT_ADDR_LED_OVERRIDE 25
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_CONTROL_MORE_YET 26
#define NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS_MORE 27
/*
* PHY-Specific Status Register (reg 17).
*
* Bit 0 : jabber => 1:jabber detected, 0:not
* Bit 1 : polarity => 1:polarity reversed, 0:normal
* Bit 2 : recvpause => 1:receive pause enabled, 0:disabled
* Bit 3 : xmitpause => 1:transmit pause enabled, 0:disabled
* Bit 4 : energydetect => 1:sleep, 0:active
* Bit 5 : downshift => 1:downshift, 0:no downshift
* Bit 6 : crossover => 1:MDIX (crossover), 0:MDI (no crossover)
* Bits 7-9 : cablelen => not valid in 10Mb/s mode
* 0:<50m, 1:50-80m, 2:80-110m, 3:110-140m, 4:>140m
* Bit 10 : link => 1:link up, 0:link down
* Bit 11 : resolved => 1:speed and duplex resolved, 0:not yet
* Bit 12 : pagercvd => 1:page received, 0:page not received
* Bit 13 : duplex => 1:full duplex, 0:half duplex
* Bits 14-15 : speed => 0:10Mb/s, 1:100Mb/s, 2:1000Mb/s, 3:rsvd
*/
#define netxen_get_phy_speed(config_word) (((config_word) >> 14) & 0x03)
#define netxen_set_phy_speed(config_word, val) \
((config_word) |= ((val & 0x03) << 14))
#define netxen_set_phy_duplex(config_word) \
((config_word) |= 1 << 13)
#define netxen_clear_phy_duplex(config_word) \
((config_word) &= ~(1 << 13))
#define netxen_get_phy_link(config_word) \
_netxen_crb_get_bit(config_word, 10)
#define netxen_get_phy_duplex(config_word) \
_netxen_crb_get_bit(config_word, 13)
/*
* NIU Mode Register.
* Bit 0 : enable FibreChannel
* Bit 1 : enable 10/100/1000 Ethernet
* Bit 2 : enable 10Gb Ethernet
*/
#define netxen_get_niu_enable_ge(config_word) \
_netxen_crb_get_bit(config_word, 1)
#define NETXEN_NIU_NON_PROMISC_MODE 0
#define NETXEN_NIU_PROMISC_MODE 1
#define NETXEN_NIU_ALLMULTI_MODE 2
/*
* NIU XG MAC Config Register
*
* Bit 0 : tx_enable => 1:enable frame xmit, 0:disable
* Bit 2 : rx_enable => 1:enable frame recv, 0:disable
* Bit 4 : soft_reset => 1:reset the MAC , 0:no-op
* Bit 27: xaui_framer_reset
* Bit 28: xaui_rx_reset
* Bit 29: xaui_tx_reset
* Bit 30: xg_ingress_afifo_reset
* Bit 31: xg_egress_afifo_reset
*/
#define netxen_xg_soft_reset(config_word) \
((config_word) |= 1 << 4)
typedef struct {
unsigned valid;
unsigned start_128M;
unsigned end_128M;
unsigned start_2M;
} crb_128M_2M_sub_block_map_t;
typedef struct {
crb_128M_2M_sub_block_map_t sub_block[16];
} crb_128M_2M_block_map_t;
#endif /* __NETXEN_NIC_HW_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
#
# Makefile for Qlogic 1G/10G Ethernet Driver for CNA devices
#
obj-$(CONFIG_QLCNIC) := qlcnic.o
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic_ethtool.o qlcnic_ctx.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
#
# 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,688 @@
#include <linux/kernel.h>
#include <linux/init.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"
static const char ql_gstrings_test[][ETH_GSTRING_LEN] = {
"Loopback test (offline)"
};
#define QLGE_TEST_LEN (sizeof(ql_gstrings_test) / ETH_GSTRING_LEN)
static int ql_update_ring_coalescing(struct ql_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 = ql_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 = ql_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 ql_update_stats(struct ql_adapter *qdev)
{
u32 i;
u64 data;
u64 *iter = &qdev->nic_stats.tx_pkts;
spin_lock(&qdev->stats_lock);
if (ql_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 (ql_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 (ql_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 TX pause frame counter statistics.
*/
for (i = 0x500; i < 0x540; i += 8) {
if (ql_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 (ql_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 (ql_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:
ql_sem_unlock(qdev, qdev->xg_sem_mask);
quit:
spin_unlock(&qdev->stats_lock);
QL_DUMP_STAT(qdev);
}
static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
{"tx_pkts"},
{"tx_bytes"},
{"tx_mcast_pkts"},
{"tx_bcast_pkts"},
{"tx_ucast_pkts"},
{"tx_ctl_pkts"},
{"tx_pause_pkts"},
{"tx_64_pkts"},
{"tx_65_to_127_pkts"},
{"tx_128_to_255_pkts"},
{"tx_256_511_pkts"},
{"tx_512_to_1023_pkts"},
{"tx_1024_to_1518_pkts"},
{"tx_1519_to_max_pkts"},
{"tx_undersize_pkts"},
{"tx_oversize_pkts"},
{"rx_bytes"},
{"rx_bytes_ok"},
{"rx_pkts"},
{"rx_pkts_ok"},
{"rx_bcast_pkts"},
{"rx_mcast_pkts"},
{"rx_ucast_pkts"},
{"rx_undersize_pkts"},
{"rx_oversize_pkts"},
{"rx_jabber_pkts"},
{"rx_undersize_fcerr_pkts"},
{"rx_drop_events"},
{"rx_fcerr_pkts"},
{"rx_align_err"},
{"rx_symbol_err"},
{"rx_mac_err"},
{"rx_ctl_pkts"},
{"rx_pause_pkts"},
{"rx_64_pkts"},
{"rx_65_to_127_pkts"},
{"rx_128_255_pkts"},
{"rx_256_511_pkts"},
{"rx_512_to_1023_pkts"},
{"rx_1024_to_1518_pkts"},
{"rx_1519_to_max_pkts"},
{"rx_len_err_pkts"},
{"tx_cbfc_pause_frames0"},
{"tx_cbfc_pause_frames1"},
{"tx_cbfc_pause_frames2"},
{"tx_cbfc_pause_frames3"},
{"tx_cbfc_pause_frames4"},
{"tx_cbfc_pause_frames5"},
{"tx_cbfc_pause_frames6"},
{"tx_cbfc_pause_frames7"},
{"rx_cbfc_pause_frames0"},
{"rx_cbfc_pause_frames1"},
{"rx_cbfc_pause_frames2"},
{"rx_cbfc_pause_frames3"},
{"rx_cbfc_pause_frames4"},
{"rx_cbfc_pause_frames5"},
{"rx_cbfc_pause_frames6"},
{"rx_cbfc_pause_frames7"},
{"rx_nic_fifo_drop"},
};
static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(buf, ql_stats_str_arr, sizeof(ql_stats_str_arr));
break;
}
}
static int ql_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
case ETH_SS_TEST:
return QLGE_TEST_LEN;
case ETH_SS_STATS:
return ARRAY_SIZE(ql_stats_str_arr);
default:
return -EOPNOTSUPP;
}
}
static void
ql_get_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *stats, u64 *data)
{
struct ql_adapter *qdev = netdev_priv(ndev);
struct nic_stats *s = &qdev->nic_stats;
ql_update_stats(qdev);
*data++ = s->tx_pkts;
*data++ = s->tx_bytes;
*data++ = s->tx_mcast_pkts;
*data++ = s->tx_bcast_pkts;
*data++ = s->tx_ucast_pkts;
*data++ = s->tx_ctl_pkts;
*data++ = s->tx_pause_pkts;
*data++ = s->tx_64_pkt;
*data++ = s->tx_65_to_127_pkt;
*data++ = s->tx_128_to_255_pkt;
*data++ = s->tx_256_511_pkt;
*data++ = s->tx_512_to_1023_pkt;
*data++ = s->tx_1024_to_1518_pkt;
*data++ = s->tx_1519_to_max_pkt;
*data++ = s->tx_undersize_pkt;
*data++ = s->tx_oversize_pkt;
*data++ = s->rx_bytes;
*data++ = s->rx_bytes_ok;
*data++ = s->rx_pkts;
*data++ = s->rx_pkts_ok;
*data++ = s->rx_bcast_pkts;
*data++ = s->rx_mcast_pkts;
*data++ = s->rx_ucast_pkts;
*data++ = s->rx_undersize_pkts;
*data++ = s->rx_oversize_pkts;
*data++ = s->rx_jabber_pkts;
*data++ = s->rx_undersize_fcerr_pkts;
*data++ = s->rx_drop_events;
*data++ = s->rx_fcerr_pkts;
*data++ = s->rx_align_err;
*data++ = s->rx_symbol_err;
*data++ = s->rx_mac_err;
*data++ = s->rx_ctl_pkts;
*data++ = s->rx_pause_pkts;
*data++ = s->rx_64_pkts;
*data++ = s->rx_65_to_127_pkts;
*data++ = s->rx_128_255_pkts;
*data++ = s->rx_256_511_pkts;
*data++ = s->rx_512_to_1023_pkts;
*data++ = s->rx_1024_to_1518_pkts;
*data++ = s->rx_1519_to_max_pkts;
*data++ = s->rx_len_err_pkts;
*data++ = s->tx_cbfc_pause_frames0;
*data++ = s->tx_cbfc_pause_frames1;
*data++ = s->tx_cbfc_pause_frames2;
*data++ = s->tx_cbfc_pause_frames3;
*data++ = s->tx_cbfc_pause_frames4;
*data++ = s->tx_cbfc_pause_frames5;
*data++ = s->tx_cbfc_pause_frames6;
*data++ = s->tx_cbfc_pause_frames7;
*data++ = s->rx_cbfc_pause_frames0;
*data++ = s->rx_cbfc_pause_frames1;
*data++ = s->rx_cbfc_pause_frames2;
*data++ = s->rx_cbfc_pause_frames3;
*data++ = s->rx_cbfc_pause_frames4;
*data++ = s->rx_cbfc_pause_frames5;
*data++ = s->rx_cbfc_pause_frames6;
*data++ = s->rx_cbfc_pause_frames7;
*data++ = s->rx_nic_fifo_drop;
}
static int ql_get_settings(struct net_device *ndev,
struct ethtool_cmd *ecmd)
{
struct ql_adapter *qdev = netdev_priv(ndev);
ecmd->supported = SUPPORTED_10000baseT_Full;
ecmd->advertising = ADVERTISED_10000baseT_Full;
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->transceiver = XCVR_EXTERNAL;
if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
STS_LINK_TYPE_10GBASET) {
ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
ecmd->port = PORT_TP;
} else {
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
ecmd->port = PORT_FIBRE;
}
ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
return 0;
}
static void ql_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *drvinfo)
{
struct ql_adapter *qdev = netdev_priv(ndev);
strncpy(drvinfo->driver, qlge_driver_name, 32);
strncpy(drvinfo->version, qlge_driver_version, 32);
snprintf(drvinfo->fw_version, 32, "v%d.%d.%d",
(qdev->fw_rev_id & 0x00ff0000) >> 16,
(qdev->fw_rev_id & 0x0000ff00) >> 8,
(qdev->fw_rev_id & 0x000000ff));
strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
drvinfo->n_stats = 0;
drvinfo->testinfo_len = 0;
if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
drvinfo->regdump_len = sizeof(struct ql_mpi_coredump);
else
drvinfo->regdump_len = sizeof(struct ql_reg_dump);
drvinfo->eedump_len = 0;
}
static void ql_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
struct ql_adapter *qdev = netdev_priv(ndev);
/* What we support. */
wol->supported = WAKE_MAGIC;
/* What we've currently got set. */
wol->wolopts = qdev->wol;
}
static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status;
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);
if (!qdev->wol) {
u32 wol = 0;
status = ql_mb_wol_mode(qdev, wol);
netif_err(qdev, drv, qdev->ndev, "WOL %s (wol code 0x%x)\n",
status == 0 ? "cleared successfully" : "clear failed",
wol);
}
return 0;
}
static int ql_set_phys_id(struct net_device *ndev,
enum ethtool_phys_id_state state)
{
struct ql_adapter *qdev = netdev_priv(ndev);
switch (state) {
case ETHTOOL_ID_ACTIVE:
/* Save the current LED settings */
if (ql_mb_get_led_cfg(qdev))
return -EIO;
/* Start blinking */
ql_mb_set_led_cfg(qdev, QL_LED_BLINK);
return 0;
case ETHTOOL_ID_INACTIVE:
/* Restore LED settings */
if (ql_mb_set_led_cfg(qdev, qdev->led_config))
return -EIO;
return 0;
default:
return -EINVAL;
}
}
static int ql_start_loopback(struct ql_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 ql_mb_set_port_cfg(qdev);
}
static void ql_stop_loopback(struct ql_adapter *qdev)
{
qdev->link_config &= ~CFG_LOOPBACK_PCS;
ql_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 ql_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);
memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
}
void ql_check_lb_frame(struct ql_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 ql_run_loopback_test(struct ql_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);
ql_create_lb_frame(skb, size);
rc = ql_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. */
msleep(2);
ql_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
return atomic_read(&qdev->lb_count) ? -EIO : 0;
}
static int ql_loopback_test(struct ql_adapter *qdev, u64 *data)
{
*data = ql_start_loopback(qdev);
if (*data)
goto out;
*data = ql_run_loopback_test(qdev);
out:
ql_stop_loopback(qdev);
return *data;
}
static void ql_self_test(struct net_device *ndev,
struct ethtool_test *eth_test, u64 *data)
{
struct ql_adapter *qdev = netdev_priv(ndev);
if (netif_running(ndev)) {
set_bit(QL_SELFTEST, &qdev->flags);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
if (ql_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 ql_get_regs_len(struct net_device *ndev)
{
struct ql_adapter *qdev = netdev_priv(ndev);
if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
return sizeof(struct ql_mpi_coredump);
else
return sizeof(struct ql_reg_dump);
}
static void ql_get_regs(struct net_device *ndev,
struct ethtool_regs *regs, void *p)
{
struct ql_adapter *qdev = netdev_priv(ndev);
ql_get_dump(qdev, p);
qdev->core_is_dumped = 0;
if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
regs->len = sizeof(struct ql_mpi_coredump);
else
regs->len = sizeof(struct ql_reg_dump);
}
static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
{
struct ql_adapter *qdev = netdev_priv(dev);
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 ql_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *c)
{
struct ql_adapter *qdev = netdev_priv(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 ql_update_ring_coalescing(qdev);
}
static void ql_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ql_adapter *qdev = netdev_priv(netdev);
ql_mb_get_port_cfg(qdev);
if (qdev->link_config & CFG_PAUSE_STD) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
}
static int ql_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct ql_adapter *qdev = netdev_priv(netdev);
int status = 0;
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;
status = ql_mb_set_port_cfg(qdev);
return status;
}
static u32 ql_get_msglevel(struct net_device *ndev)
{
struct ql_adapter *qdev = netdev_priv(ndev);
return qdev->msg_enable;
}
static void ql_set_msglevel(struct net_device *ndev, u32 value)
{
struct ql_adapter *qdev = netdev_priv(ndev);
qdev->msg_enable = value;
}
const struct ethtool_ops qlge_ethtool_ops = {
.get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo,
.get_wol = ql_get_wol,
.set_wol = ql_set_wol,
.get_regs_len = ql_get_regs_len,
.get_regs = ql_get_regs,
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
.get_link = ethtool_op_get_link,
.set_phys_id = ql_set_phys_id,
.self_test = ql_self_test,
.get_pauseparam = ql_get_pauseparam,
.set_pauseparam = ql_set_pauseparam,
.get_coalesce = ql_get_coalesce,
.set_coalesce = ql_set_coalesce,
.get_sset_count = ql_get_sset_count,
.get_strings = ql_get_strings,
.get_ethtool_stats = ql_get_ethtool_stats,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff