Merge branch 'qlcnic-next'

Jitendra Kalsaria says:

====================
qlcnic driver updates

This patch series containes following changes -
* Optimize MAC learning code.
* Export board temperature using hwmon-sysfs interface.
* Add support for configuring Tx interrupt coalescing parameters from VF.
* Logging error messages in error path.
* Restrict extended vNIC support in legacy interrupt mode and log appropriate
  message.

Please apply this series to net-next.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-04-27 23:20:59 -04:00
commit 4940b8cd1b
9 changed files with 179 additions and 26 deletions

View File

@ -66,6 +66,17 @@ config QLCNIC_VXLAN
Say Y here if you want to enable hardware offload support for
Virtual eXtensible Local Area Network (VXLAN) in the driver.
config QLCNIC_HWMON
bool "QLOGIC QLCNIC 82XX and 83XX family HWMON support"
depends on QLCNIC && HWMON
default y
---help---
This configuration parameter can be used to read the
board temperature in Converged Ethernet devices
supported by qlcnic.
This data is available via the hwmon sysfs interface.
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI

View File

@ -39,8 +39,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 3
#define _QLCNIC_LINUX_SUBVERSION 57
#define QLCNIC_LINUX_VERSIONID "5.3.57"
#define _QLCNIC_LINUX_SUBVERSION 58
#define QLCNIC_LINUX_VERSIONID "5.3.58"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@ -537,6 +537,7 @@ struct qlcnic_hardware_context {
u8 phys_port_id[ETH_ALEN];
u8 lb_mode;
u16 vxlan_port;
struct device *hwmon_dev;
};
struct qlcnic_adapter_stats {
@ -2361,4 +2362,18 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter)
else
return QLC_DEFAULT_VNIC_COUNT;
}
#ifdef CONFIG_QLCNIC_HWMON
void qlcnic_register_hwmon_dev(struct qlcnic_adapter *);
void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *);
#else
static inline void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter)
{
return;
}
static inline void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter)
{
return;
}
#endif
#endif /* __QLCNIC_H_ */

View File

@ -33,6 +33,7 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
#define RSS_HASHTYPE_IP_TCP 0x3
#define QLC_83XX_FW_MBX_CMD 0
#define QLC_SKIP_INACTIVE_PCI_REGS 7
#define QLC_MAX_LEGACY_FUNC_SUPP 8
static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
@ -357,8 +358,15 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
if (!ahw->intr_tbl)
return -ENOMEM;
if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
if (adapter->ahw->pci_func >= QLC_MAX_LEGACY_FUNC_SUPP) {
dev_err(&adapter->pdev->dev, "PCI function number 8 and higher are not supported with legacy interrupt, func 0x%x\n",
ahw->pci_func);
return -EOPNOTSUPP;
}
qlcnic_83xx_enable_legacy(adapter);
}
for (i = 0; i < num_msix; i++) {
if (adapter->flags & QLCNIC_MSIX_ENABLED)
@ -879,6 +887,9 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
return 0;
}
}
dev_err(&adapter->pdev->dev, "%s: Invalid mailbox command opcode 0x%x\n",
__func__, type);
return -EINVAL;
}

View File

@ -2181,6 +2181,8 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
max_sds_rings = QLCNIC_MAX_SDS_RINGS;
max_tx_rings = QLCNIC_MAX_TX_RINGS;
} else {
dev_err(&adapter->pdev->dev, "%s: Invalid opmode %d\n",
__func__, ret);
return -EIO;
}

View File

@ -1027,8 +1027,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
u32 arg1;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE)) {
dev_err(&adapter->pdev->dev, "%s: Not a management function\n",
__func__);
return err;
}
arg1 = id | (enable_mirroring ? BIT_4 : 0);
arg1 |= pci_func << 8;
@ -1318,8 +1321,12 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
u32 arg1, arg2 = 0;
u8 pci_func;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
dev_err(&adapter->pdev->dev, "%s: Not a management function\n",
__func__);
return err;
}
pci_func = esw_cfg->pci_func;
index = qlcnic_is_valid_nic_func(adapter, pci_func);
if (index < 0)
@ -1363,6 +1370,8 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
arg1 &= ~(0x0ffff << 16);
break;
default:
dev_err(&adapter->pdev->dev, "%s: Invalid opmode 0x%x\n",
__func__, esw_cfg->op_mode);
return err;
}

View File

@ -305,7 +305,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
{
struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
struct net_device *netdev = adapter->netdev;
u16 protocol = ntohs(skb->protocol);
struct qlcnic_filter *fil, *tmp_fil;
struct hlist_head *head;
@ -330,13 +329,6 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
return;
}
if (adapter->fhash.fnum >= adapter->fhash.fmax) {
adapter->stats.mac_filter_limit_overrun++;
netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n",
adapter->fhash.fmax, adapter->fhash.fnum);
return;
}
memcpy(&src_addr, phdr->h_source, ETH_ALEN);
hval = qlcnic_mac_hash(src_addr, vlan_id);
hindex = hval & (adapter->fhash.fbucket_size - 1);
@ -353,6 +345,11 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
}
}
if (unlikely(adapter->fhash.fnum >= adapter->fhash.fmax)) {
adapter->stats.mac_filter_limit_overrun++;
return;
}
fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
if (!fil)
return;
@ -1216,8 +1213,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
if (!skb)
return buffer;
if (adapter->drv_mac_learn &&
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
if (adapter->rx_mac_learn) {
t_vid = 0;
is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
@ -1293,8 +1289,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
if (!skb)
return buffer;
if (adapter->drv_mac_learn &&
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
if (adapter->rx_mac_learn) {
t_vid = 0;
is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);

View File

@ -1014,6 +1014,8 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
if (pfn >= ahw->max_vnic_func) {
ret = QL_STATUS_INVALID_PARAM;
dev_err(&adapter->pdev->dev, "%s: Invalid function 0x%x, max 0x%x\n",
__func__, pfn, ahw->max_vnic_func);
goto err_eswitch;
}
@ -2052,6 +2054,7 @@ out:
static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
int err = 0;
adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
@ -2061,6 +2064,18 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
goto err_out;
}
if (qlcnic_83xx_check(adapter)) {
ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX_TX;
ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
} else {
ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX;
ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
}
/* clear stats */
memset(&adapter->stats, 0, sizeof(adapter->stats));
err_out:
@ -2517,9 +2532,11 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case -ENOMEM:
dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
goto err_out_free_hw;
case -EOPNOTSUPP:
dev_err(&pdev->dev, "Adapter initialization failed\n");
goto err_out_free_hw;
default:
dev_err(&pdev->dev, "Adapter initialization failed. A reboot may be required to recover from this failure\n");
dev_err(&pdev->dev, "If reboot does not help to recover from this failure, try a flash update of the adapter\n");
dev_err(&pdev->dev, "Adapter initialization failed. Driver will load in maintenance mode to recover the adapter using the application\n");
goto err_out_maintenance_mode;
}
}
@ -2593,7 +2610,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
qlcnic_alloc_lb_filters_mem(adapter);
qlcnic_add_sysfs(adapter);
qlcnic_register_hwmon_dev(adapter);
return 0;
err_out_disable_mbx_intr:
@ -2700,6 +2717,8 @@ static void qlcnic_remove(struct pci_dev *pdev)
qlcnic_remove_sysfs(adapter);
qlcnic_unregister_hwmon_dev(adapter);
qlcnic_cleanup_pci_map(adapter->ahw);
qlcnic_release_firmware(adapter);

View File

@ -16,6 +16,7 @@
#define QLC_VF_FLOOD_BIT BIT_16
#define QLC_FLOOD_MODE 0x5
#define QLC_SRIOV_ALLOW_VLAN0 BIT_19
#define QLC_INTR_COAL_TYPE_MASK 0x7
static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
@ -1178,19 +1179,41 @@ static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter,
{
struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
u16 ctx_id, pkts, time;
int err = -EINVAL;
u8 type;
type = cmd->req.arg[1] & QLC_INTR_COAL_TYPE_MASK;
ctx_id = cmd->req.arg[1] >> 16;
pkts = cmd->req.arg[2] & 0xffff;
time = cmd->req.arg[2] >> 16;
if (ctx_id != vf->rx_ctx_id)
return -EINVAL;
if (pkts > coal->rx_packets)
return -EINVAL;
if (time < coal->rx_time_us)
return -EINVAL;
switch (type) {
case QLCNIC_INTR_COAL_TYPE_RX:
if (ctx_id != vf->rx_ctx_id || pkts > coal->rx_packets ||
time < coal->rx_time_us)
goto err_label;
break;
case QLCNIC_INTR_COAL_TYPE_TX:
if (ctx_id != vf->tx_ctx_id || pkts > coal->tx_packets ||
time < coal->tx_time_us)
goto err_label;
break;
default:
netdev_err(adapter->netdev, "Invalid coalescing type 0x%x received\n",
type);
return err;
}
return 0;
err_label:
netdev_err(adapter->netdev, "Expected: rx_ctx_id 0x%x rx_packets 0x%x rx_time_us 0x%x tx_ctx_id 0x%x tx_packets 0x%x tx_time_us 0x%x\n",
vf->rx_ctx_id, coal->rx_packets, coal->rx_time_us,
vf->tx_ctx_id, coal->tx_packets, coal->tx_time_us);
netdev_err(adapter->netdev, "Received: ctx_id 0x%x packets 0x%x time_us 0x%x type 0x%x\n",
ctx_id, pkts, time, type);
return err;
}
static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran,

View File

@ -19,6 +19,10 @@
#include <linux/sysfs.h>
#include <linux/aer.h>
#include <linux/log2.h>
#ifdef CONFIG_QLCNIC_HWMON
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#endif
#define QLC_STATUS_UNSUPPORTED_CMD -2
@ -358,6 +362,8 @@ int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
if (adapter->npars[i].pci_func == pci_func)
return i;
}
dev_err(&adapter->pdev->dev, "%s: Invalid nic function\n", __func__);
return -EINVAL;
}
@ -1243,6 +1249,68 @@ static struct bin_attribute bin_attr_flash = {
.write = qlcnic_83xx_sysfs_flash_write_handler,
};
#ifdef CONFIG_QLCNIC_HWMON
static ssize_t qlcnic_hwmon_show_temp(struct device *dev,
struct device_attribute *dev_attr,
char *buf)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
unsigned int temperature = 0, value = 0;
if (qlcnic_83xx_check(adapter))
value = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
else if (qlcnic_82xx_check(adapter))
value = QLC_SHARED_REG_RD32(adapter, QLCNIC_ASIC_TEMP);
temperature = qlcnic_get_temp_val(value);
/* display millidegree celcius */
temperature *= 1000;
return sprintf(buf, "%u\n", temperature);
}
/* hwmon-sysfs attributes */
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
qlcnic_hwmon_show_temp, NULL, 1);
static struct attribute *qlcnic_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(qlcnic_hwmon);
void qlcnic_register_hwmon_dev(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
struct device *hwmon_dev;
/* Skip hwmon registration for a VF device */
if (qlcnic_sriov_vf_check(adapter)) {
adapter->ahw->hwmon_dev = NULL;
return;
}
hwmon_dev = hwmon_device_register_with_groups(dev, qlcnic_driver_name,
adapter,
qlcnic_hwmon_groups);
if (IS_ERR(hwmon_dev)) {
dev_err(dev, "Cannot register with hwmon, err=%ld\n",
PTR_ERR(hwmon_dev));
hwmon_dev = NULL;
}
adapter->ahw->hwmon_dev = hwmon_dev;
}
void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *adapter)
{
struct device *hwmon_dev = adapter->ahw->hwmon_dev;
if (hwmon_dev) {
hwmon_device_unregister(hwmon_dev);
adapter->ahw->hwmon_dev = NULL;
}
}
#endif
void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;