Skip to content

Commit

Permalink
qlcnic: dcb: Query adapter DCB capabilities.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sucheta Chakraborty authored and David S. Miller committed Aug 27, 2013
1 parent d853f11 commit 14d385b
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 0 deletions.
11 changes: 11 additions & 0 deletions drivers/net/ethernet/qlogic/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 50 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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_ */
1 change: 1 addition & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
213 changes: 213 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
Original file line number Diff line number Diff line change
@@ -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;
}
32 changes: 32 additions & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 14d385b

Please sign in to comment.