qlcnic: dcb: Query adapter DCB capabilities.

o Query adapter DCB capabilities and  populate local data structures
  with relevant information.

o Add QLCNIC_DCB to Kconfig for enabling/disabling DCB.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sucheta Chakraborty 2013-08-23 13:38:25 -04:00 committed by David S. Miller
parent d853f11166
commit 14d385b990
12 changed files with 345 additions and 0 deletions

View File

@ -45,6 +45,17 @@ config QLCNIC_SRIOV
This allows for virtual function acceleration in virtualized
environments.
config QLCNIC_DCB
bool "QLOGIC QLCNIC 82XX and 83XX family DCB Support"
depends on QLCNIC && DCB
default y
---help---
This configuration parameter enables DCB support in QLE83XX
and QLE82XX Converged Ethernet devices. This allows for DCB
get operations support through rtNetlink interface. Only CEE
mode of DCB is supported. PG and PFC values are related only
to Tx.
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI

View File

@ -11,3 +11,5 @@ qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic_minidump.o qlcnic_sriov_common.o
qlcnic-$(CONFIG_QLCNIC_SRIOV) += qlcnic_sriov_pf.o
qlcnic-$(CONFIG_QLCNIC_DCB) += qlcnic_dcb.o

View File

@ -34,6 +34,7 @@
#include "qlcnic_hdr.h"
#include "qlcnic_hw.h"
#include "qlcnic_83xx_hw.h"
#include "qlcnic_dcb.h"
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 3
@ -959,6 +960,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_SRIOV_CAPABLE 11
#define __QLCNIC_MBX_POLL_ENABLE 12
#define __QLCNIC_DIAG_MODE 13
#define __QLCNIC_DCB_STATE 14
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@ -1062,6 +1064,7 @@ struct qlcnic_adapter {
struct delayed_work fw_work;
struct delayed_work idc_aen_work;
struct delayed_work mbx_poll_work;
struct qlcnic_dcb *dcb;
struct qlcnic_filter_hash fhash;
struct qlcnic_filter_hash rx_fhash;
@ -2092,4 +2095,51 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter)
return status;
}
static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (dcb && dcb->ops->get_hw_capability)
return dcb->ops->get_hw_capability(adapter);
return 0;
}
static inline void qlcnic_dcb_free(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (dcb && dcb->ops->free)
dcb->ops->free(adapter);
}
static inline int qlcnic_dcb_attach(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (dcb && dcb->ops->attach)
return dcb->ops->attach(adapter);
return 0;
}
static inline int
qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter, char *buf)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (dcb && dcb->ops->query_hw_capability)
return dcb->ops->query_hw_capability(adapter, buf);
return 0;
}
static inline void qlcnic_dcb_get_info(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (dcb && dcb->ops->get_info)
dcb->ops->get_info(adapter);
}
#endif /* __QLCNIC_H_ */

View File

@ -67,6 +67,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
{QLCNIC_CMD_CONFIG_VPORT, 4, 4},
{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},
};
const u32 qlcnic_83xx_ext_reg_tbl[] = {

View File

@ -635,6 +635,8 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
if (adapter->portnum == 0)
qlcnic_set_drv_version(adapter);
qlcnic_dcb_get_info(adapter);
qlcnic_83xx_idc_attach_driver(adapter);
return 0;
@ -2228,6 +2230,9 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
if (err)
goto disable_mbx_intr;
if (adapter->dcb && qlcnic_dcb_attach(adapter))
qlcnic_clear_dcb_ops(adapter);
/* Periodically monitor device status */
qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
return 0;

View File

@ -39,6 +39,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
{QLCNIC_CMD_82XX_SET_DRV_VER, 4, 1},
{QLCNIC_CMD_GET_LED_STATUS, 4, 2},
{QLCNIC_CMD_MQ_TX_CONFIG_INTR, 2, 3},
{QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},
};
static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)

View File

@ -0,0 +1,213 @@
/*
* QLogic qlcnic NIC Driver
* Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
#include "qlcnic.h"
#define QLC_DCB_MAX_TC 0x8
#define QLC_DCB_TSA_SUPPORT(V) (V & 0x1)
#define QLC_DCB_ETS_SUPPORT(V) ((V >> 1) & 0x1)
#define QLC_DCB_VERSION_SUPPORT(V) ((V >> 2) & 0xf)
#define QLC_DCB_MAX_NUM_TC(V) ((V >> 20) & 0xf)
#define QLC_DCB_MAX_NUM_ETS_TC(V) ((V >> 24) & 0xf)
#define QLC_DCB_MAX_NUM_PFC_TC(V) ((V >> 28) & 0xf)
static void __qlcnic_dcb_free(struct qlcnic_adapter *);
static int __qlcnic_dcb_attach(struct qlcnic_adapter *);
static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *, char *);
static void __qlcnic_dcb_get_info(struct qlcnic_adapter *);
static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *);
static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *);
struct qlcnic_dcb_capability {
bool tsa_capability;
bool ets_capability;
u8 max_num_tc;
u8 max_ets_tc;
u8 max_pfc_tc;
u8 dcb_capability;
};
struct qlcnic_dcb_cfg {
struct qlcnic_dcb_capability capability;
u32 version;
};
static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = {
.free = __qlcnic_dcb_free,
.attach = __qlcnic_dcb_attach,
.query_hw_capability = __qlcnic_dcb_query_hw_capability,
.get_info = __qlcnic_dcb_get_info,
.get_hw_capability = qlcnic_83xx_dcb_get_hw_capability,
};
static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = {
.free = __qlcnic_dcb_free,
.attach = __qlcnic_dcb_attach,
.query_hw_capability = __qlcnic_dcb_query_hw_capability,
.get_info = __qlcnic_dcb_get_info,
.get_hw_capability = qlcnic_82xx_dcb_get_hw_capability,
};
void qlcnic_set_dcb_ops(struct qlcnic_adapter *adapter)
{
if (qlcnic_82xx_check(adapter))
adapter->dcb->ops = &qlcnic_82xx_dcb_ops;
else if (qlcnic_83xx_check(adapter))
adapter->dcb->ops = &qlcnic_83xx_dcb_ops;
}
int __qlcnic_register_dcb(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb;
dcb = kzalloc(sizeof(struct qlcnic_dcb), GFP_ATOMIC);
if (!dcb)
return -ENOMEM;
adapter->dcb = dcb;
qlcnic_set_dcb_ops(adapter);
return 0;
}
static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
if (!dcb)
return;
kfree(dcb->cfg);
dcb->cfg = NULL;
kfree(dcb);
adapter->dcb = NULL;
}
static void __qlcnic_dcb_get_info(struct qlcnic_adapter *adapter)
{
qlcnic_dcb_get_hw_capability(adapter);
}
static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb *dcb = adapter->dcb;
dcb->cfg = kzalloc(sizeof(struct qlcnic_dcb_cfg), GFP_ATOMIC);
if (!dcb->cfg)
return -ENOMEM;
qlcnic_dcb_get_info(adapter);
return 0;
}
static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *adapter,
char *buf)
{
struct qlcnic_cmd_args cmd;
u32 mbx_out;
int err;
err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DCB_QUERY_CAP);
if (err)
return err;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err) {
dev_err(&adapter->pdev->dev,
"Failed to query DCBX capability, err %d\n", err);
} else {
mbx_out = cmd.rsp.arg[1];
if (buf)
memcpy(buf, &mbx_out, sizeof(u32));
}
qlcnic_free_mbx_args(&cmd);
return err;
}
static int __qlcnic_dcb_get_capability(struct qlcnic_adapter *adapter, u32 *val)
{
struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
u32 mbx_out;
int err;
memset(cap, 0, sizeof(struct qlcnic_dcb_capability));
err = qlcnic_dcb_query_hw_capability(adapter, (char *)val);
if (err)
return err;
mbx_out = *val;
if (QLC_DCB_TSA_SUPPORT(mbx_out))
cap->tsa_capability = true;
if (QLC_DCB_ETS_SUPPORT(mbx_out))
cap->ets_capability = true;
cap->max_num_tc = QLC_DCB_MAX_NUM_TC(mbx_out);
cap->max_ets_tc = QLC_DCB_MAX_NUM_ETS_TC(mbx_out);
cap->max_pfc_tc = QLC_DCB_MAX_NUM_PFC_TC(mbx_out);
if (cap->max_num_tc > QLC_DCB_MAX_TC ||
cap->max_ets_tc > cap->max_num_tc ||
cap->max_pfc_tc > cap->max_num_tc) {
dev_err(&adapter->pdev->dev, "Invalid DCB configuration\n");
return -EINVAL;
}
return err;
}
static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb_cfg *cfg = adapter->dcb->cfg;
struct qlcnic_dcb_capability *cap;
u32 mbx_out;
int err;
err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
if (err)
return err;
cap = &cfg->capability;
cap->dcb_capability = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_LLD_MANAGED;
if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
set_bit(__QLCNIC_DCB_STATE, &adapter->state);
return err;
}
static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter)
{
struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability;
u32 mbx_out;
int err;
err = __qlcnic_dcb_get_capability(adapter, &mbx_out);
if (err)
return err;
if (mbx_out & BIT_2)
cap->dcb_capability = DCB_CAP_DCBX_VER_CEE;
if (mbx_out & BIT_3)
cap->dcb_capability |= DCB_CAP_DCBX_VER_IEEE;
if (cap->dcb_capability)
cap->dcb_capability |= DCB_CAP_DCBX_LLD_MANAGED;
if (cap->dcb_capability && cap->tsa_capability && cap->ets_capability)
set_bit(__QLCNIC_DCB_STATE, &adapter->state);
return err;
}

View File

@ -0,0 +1,32 @@
/*
* QLogic qlcnic NIC Driver
* Copyright (c) 2009-2013 QLogic Corporation
*
* See LICENSE.qlcnic for copyright and licensing details.
*/
#ifndef __QLCNIC_DCBX_H
#define __QLCNIC_DCBX_H
void qlcnic_clear_dcb_ops(struct qlcnic_adapter *);
#ifdef CONFIG_QLCNIC_DCB
int __qlcnic_register_dcb(struct qlcnic_adapter *);
#else
static inline int __qlcnic_register_dcb(struct qlcnic_adapter *adapter)
{ return 0; }
#endif
struct qlcnic_dcb_ops {
void (*free) (struct qlcnic_adapter *);
int (*attach) (struct qlcnic_adapter *);
int (*query_hw_capability) (struct qlcnic_adapter *, char *);
int (*get_hw_capability) (struct qlcnic_adapter *);
void (*get_info) (struct qlcnic_adapter *);
};
struct qlcnic_dcb {
struct qlcnic_dcb_ops *ops;
struct qlcnic_dcb_cfg *cfg;
};
#endif

View File

@ -85,6 +85,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_GET_TEMP_HDR 0x30
#define QLCNIC_CMD_BC_EVENT_SETUP 0x31
#define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_DCB_QUERY_CAP 0x34
#define QLCNIC_CMD_GET_MAC_STATS 0x37
#define QLCNIC_CMD_82XX_SET_DRV_VER 0x38
#define QLCNIC_CMD_MQ_TX_CONFIG_INTR 0x39

View File

@ -2121,6 +2121,17 @@ void qlcnic_set_drv_version(struct qlcnic_adapter *adapter)
qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);
}
static int qlcnic_register_dcb(struct qlcnic_adapter *adapter)
{
return __qlcnic_register_dcb(adapter);
}
void qlcnic_clear_dcb_ops(struct qlcnic_adapter *adapter)
{
kfree(adapter->dcb);
adapter->dcb = NULL;
}
static int
qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@ -2217,6 +2228,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_LIST_HEAD(&adapter->mac_list);
qlcnic_register_dcb(adapter);
if (qlcnic_82xx_check(adapter)) {
qlcnic_check_vf(adapter, ent);
adapter->portnum = adapter->ahw->pci_func;
@ -2245,6 +2258,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_hw;
adapter->flags |= QLCNIC_NEED_FLR;
if (adapter->dcb && qlcnic_dcb_attach(adapter))
qlcnic_clear_dcb_ops(adapter);
} else if (qlcnic_83xx_check(adapter)) {
adapter->max_drv_tx_rings = 1;
qlcnic_83xx_check_vf(adapter, ent);
@ -2369,6 +2386,8 @@ static void qlcnic_remove(struct pci_dev *pdev)
qlcnic_cancel_idc_work(adapter);
ahw = adapter->ahw;
qlcnic_dcb_free(adapter);
unregister_netdev(netdev);
qlcnic_sriov_cleanup(adapter);
@ -2411,6 +2430,7 @@ static void qlcnic_remove(struct pci_dev *pdev)
destroy_workqueue(adapter->qlcnic_wq);
adapter->qlcnic_wq = NULL;
}
qlcnic_free_adapter_resources(adapter);
kfree(ahw);
free_netdev(netdev);
@ -3228,6 +3248,8 @@ qlcnic_attach_work(struct work_struct *work)
return;
}
attach:
qlcnic_dcb_get_info(adapter);
if (netif_running(netdev)) {
if (qlcnic_up(adapter, netdev))
goto done;

View File

@ -538,6 +538,9 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
if (err)
goto err_out_send_channel_term;
if (adapter->dcb && qlcnic_dcb_attach(adapter))
qlcnic_clear_dcb_ops(adapter);
err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);
if (err)
goto err_out_send_channel_term;
@ -545,6 +548,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
pci_set_drvdata(adapter->pdev, adapter);
dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
adapter->netdev->name);
qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
adapter->ahw->idc.delay);
return 0;
@ -1577,6 +1581,8 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
if (err)
goto err_out_term_channel;
qlcnic_dcb_get_info(adapter);
return 0;
err_out_term_channel:

View File

@ -1284,6 +1284,7 @@ static const int qlcnic_pf_passthru_supp_cmds[] = {
QLCNIC_CMD_GET_STATISTICS,
QLCNIC_CMD_GET_PORT_CONFIG,
QLCNIC_CMD_GET_LINK_STATUS,
QLCNIC_CMD_DCB_QUERY_CAP,
};
static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = {