qlcnic: support rcv ring configuration through ethtool
o Support ethtool command ETHTOOL_GCHANNELS and ETHTOOL_SCHANNELS. o Number of rcv rings configuration depend upon number of msix vector. Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
ad246c992b
commit
f94bc1e702
@@ -118,7 +118,6 @@
|
|||||||
#define PHAN_PEG_RCV_INITIALIZED 0xff01
|
#define PHAN_PEG_RCV_INITIALIZED 0xff01
|
||||||
|
|
||||||
#define NUM_RCV_DESC_RINGS 3
|
#define NUM_RCV_DESC_RINGS 3
|
||||||
#define NUM_STS_DESC_RINGS 4
|
|
||||||
|
|
||||||
#define RCV_RING_NORMAL 0
|
#define RCV_RING_NORMAL 0
|
||||||
#define RCV_RING_JUMBO 1
|
#define RCV_RING_JUMBO 1
|
||||||
@@ -871,7 +870,8 @@ struct qlcnic_ipaddr {
|
|||||||
#define QLCNIC_IS_MSI_FAMILY(adapter) \
|
#define QLCNIC_IS_MSI_FAMILY(adapter) \
|
||||||
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
|
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
|
||||||
|
|
||||||
#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS
|
#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4
|
||||||
|
#define QLCNIC_MIN_NUM_RSS_RINGS 2
|
||||||
#define QLCNIC_MSIX_TBL_SPACE 8192
|
#define QLCNIC_MSIX_TBL_SPACE 8192
|
||||||
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
|
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
|
||||||
#define QLCNIC_MSIX_TBL_PGSIZE 4096
|
#define QLCNIC_MSIX_TBL_PGSIZE 4096
|
||||||
@@ -987,7 +987,7 @@ struct qlcnic_adapter {
|
|||||||
void __iomem *crb_int_state_reg;
|
void __iomem *crb_int_state_reg;
|
||||||
void __iomem *isr_int_vec;
|
void __iomem *isr_int_vec;
|
||||||
|
|
||||||
struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
|
struct msix_entry *msix_entries;
|
||||||
|
|
||||||
struct delayed_work fw_work;
|
struct delayed_work fw_work;
|
||||||
|
|
||||||
@@ -1262,6 +1262,8 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
|
|||||||
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
|
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
|
||||||
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
|
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
|
||||||
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
|
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
|
||||||
|
int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
|
||||||
|
int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
|
||||||
|
|
||||||
/* Management functions */
|
/* Management functions */
|
||||||
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
|
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
|
||||||
|
@@ -474,6 +474,39 @@ qlcnic_set_ringparam(struct net_device *dev,
|
|||||||
return qlcnic_reset_context(adapter);
|
return qlcnic_reset_context(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qlcnic_get_channels(struct net_device *dev,
|
||||||
|
struct ethtool_channels *channel)
|
||||||
|
{
|
||||||
|
struct qlcnic_adapter *adapter = netdev_priv(dev);
|
||||||
|
|
||||||
|
channel->max_rx = rounddown_pow_of_two(min_t(int,
|
||||||
|
adapter->max_rx_ques, num_online_cpus()));
|
||||||
|
channel->max_tx = adapter->max_tx_ques;
|
||||||
|
|
||||||
|
channel->rx_count = adapter->max_sds_rings;
|
||||||
|
channel->tx_count = adapter->max_tx_ques;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qlcnic_set_channels(struct net_device *dev,
|
||||||
|
struct ethtool_channels *channel)
|
||||||
|
{
|
||||||
|
struct qlcnic_adapter *adapter = netdev_priv(dev);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (channel->other_count || channel->combined_count ||
|
||||||
|
channel->tx_count != channel->max_tx)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = qlcnic_set_max_rss(adapter, channel->rx_count);
|
||||||
|
netdev_info(dev, "allocated 0x%x sds rings\n",
|
||||||
|
adapter->max_sds_rings);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qlcnic_get_pauseparam(struct net_device *netdev,
|
qlcnic_get_pauseparam(struct net_device *netdev,
|
||||||
struct ethtool_pauseparam *pause)
|
struct ethtool_pauseparam *pause)
|
||||||
@@ -949,6 +982,8 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
|
|||||||
.get_eeprom = qlcnic_get_eeprom,
|
.get_eeprom = qlcnic_get_eeprom,
|
||||||
.get_ringparam = qlcnic_get_ringparam,
|
.get_ringparam = qlcnic_get_ringparam,
|
||||||
.set_ringparam = qlcnic_set_ringparam,
|
.set_ringparam = qlcnic_set_ringparam,
|
||||||
|
.get_channels = qlcnic_get_channels,
|
||||||
|
.set_channels = qlcnic_set_channels,
|
||||||
.get_pauseparam = qlcnic_get_pauseparam,
|
.get_pauseparam = qlcnic_get_pauseparam,
|
||||||
.set_pauseparam = qlcnic_set_pauseparam,
|
.set_pauseparam = qlcnic_set_pauseparam,
|
||||||
.get_wol = qlcnic_get_wol,
|
.get_wol = qlcnic_get_wol,
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include <linux/aer.h>
|
#include <linux/aer.h>
|
||||||
|
#include <linux/log2.h>
|
||||||
|
|
||||||
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
|
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
@@ -350,22 +351,51 @@ static struct qlcnic_nic_template qlcnic_vf_ops = {
|
|||||||
.start_firmware = qlcnicvf_start_firmware
|
.start_firmware = qlcnicvf_start_firmware
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
|
||||||
qlcnic_setup_intr(struct qlcnic_adapter *adapter)
|
{
|
||||||
|
struct pci_dev *pdev = adapter->pdev;
|
||||||
|
int err = -1;
|
||||||
|
|
||||||
|
adapter->max_sds_rings = 1;
|
||||||
|
adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
|
||||||
|
qlcnic_set_msix_bit(pdev, 0);
|
||||||
|
|
||||||
|
if (adapter->msix_supported) {
|
||||||
|
enable_msix:
|
||||||
|
qlcnic_init_msix_entries(adapter, num_msix);
|
||||||
|
err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
|
||||||
|
if (err == 0) {
|
||||||
|
adapter->flags |= QLCNIC_MSIX_ENABLED;
|
||||||
|
qlcnic_set_msix_bit(pdev, 1);
|
||||||
|
|
||||||
|
adapter->max_sds_rings = num_msix;
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "using msi-x interrupts\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (err > 0) {
|
||||||
|
num_msix = rounddown_pow_of_two(err);
|
||||||
|
if (num_msix)
|
||||||
|
goto enable_msix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
|
||||||
{
|
{
|
||||||
const struct qlcnic_legacy_intr_set *legacy_intrp;
|
const struct qlcnic_legacy_intr_set *legacy_intrp;
|
||||||
struct pci_dev *pdev = adapter->pdev;
|
struct pci_dev *pdev = adapter->pdev;
|
||||||
int err, num_msix;
|
|
||||||
|
|
||||||
if (adapter->msix_supported) {
|
if (use_msi && !pci_enable_msi(pdev)) {
|
||||||
num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
|
adapter->flags |= QLCNIC_MSI_ENABLED;
|
||||||
MSIX_ENTRIES_PER_ADAPTER : 2;
|
adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
|
||||||
} else
|
msi_tgt_status[adapter->ahw->pci_func]);
|
||||||
num_msix = 1;
|
dev_info(&pdev->dev, "using msi interrupts\n");
|
||||||
|
adapter->msix_entries[0].vector = pdev->irq;
|
||||||
adapter->max_sds_rings = 1;
|
return;
|
||||||
|
}
|
||||||
adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
|
|
||||||
|
|
||||||
legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
|
legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
|
||||||
|
|
||||||
@@ -378,42 +408,29 @@ qlcnic_setup_intr(struct qlcnic_adapter *adapter)
|
|||||||
|
|
||||||
adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
|
adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
|
||||||
ISR_INT_STATE_REG);
|
ISR_INT_STATE_REG);
|
||||||
|
|
||||||
qlcnic_set_msix_bit(pdev, 0);
|
|
||||||
|
|
||||||
if (adapter->msix_supported) {
|
|
||||||
|
|
||||||
qlcnic_init_msix_entries(adapter, num_msix);
|
|
||||||
err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
|
|
||||||
if (err == 0) {
|
|
||||||
adapter->flags |= QLCNIC_MSIX_ENABLED;
|
|
||||||
qlcnic_set_msix_bit(pdev, 1);
|
|
||||||
|
|
||||||
adapter->max_sds_rings = num_msix;
|
|
||||||
|
|
||||||
dev_info(&pdev->dev, "using msi-x interrupts\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err > 0)
|
|
||||||
pci_disable_msix(pdev);
|
|
||||||
|
|
||||||
/* fall through for msi */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_msi && !pci_enable_msi(pdev)) {
|
|
||||||
adapter->flags |= QLCNIC_MSI_ENABLED;
|
|
||||||
adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
|
|
||||||
msi_tgt_status[adapter->ahw->pci_func]);
|
|
||||||
dev_info(&pdev->dev, "using msi interrupts\n");
|
|
||||||
adapter->msix_entries[0].vector = pdev->irq;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_info(&pdev->dev, "using legacy interrupts\n");
|
dev_info(&pdev->dev, "using legacy interrupts\n");
|
||||||
adapter->msix_entries[0].vector = pdev->irq;
|
adapter->msix_entries[0].vector = pdev->irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qlcnic_setup_intr(struct qlcnic_adapter *adapter)
|
||||||
|
{
|
||||||
|
int num_msix;
|
||||||
|
|
||||||
|
if (adapter->msix_supported) {
|
||||||
|
num_msix = (num_online_cpus() >=
|
||||||
|
QLCNIC_DEF_NUM_STS_DESC_RINGS) ?
|
||||||
|
QLCNIC_DEF_NUM_STS_DESC_RINGS :
|
||||||
|
QLCNIC_MIN_NUM_RSS_RINGS;
|
||||||
|
} else
|
||||||
|
num_msix = 1;
|
||||||
|
|
||||||
|
if (!qlcnic_enable_msix(adapter, num_msix))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qlcnic_enable_msi_legacy(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
|
qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
|
||||||
{
|
{
|
||||||
@@ -1493,6 +1510,19 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
|
||||||
|
{
|
||||||
|
adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
if (adapter->msix_entries)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
static int __devinit
|
static int __devinit
|
||||||
qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
@@ -1587,6 +1617,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
|
|
||||||
qlcnic_clear_stats(adapter);
|
qlcnic_clear_stats(adapter);
|
||||||
|
|
||||||
|
err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques);
|
||||||
|
if (err)
|
||||||
|
goto err_out_decr_ref;
|
||||||
|
|
||||||
qlcnic_setup_intr(adapter);
|
qlcnic_setup_intr(adapter);
|
||||||
|
|
||||||
err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
|
err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
|
||||||
@@ -1615,6 +1649,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||||||
|
|
||||||
err_out_disable_msi:
|
err_out_disable_msi:
|
||||||
qlcnic_teardown_intr(adapter);
|
qlcnic_teardown_intr(adapter);
|
||||||
|
kfree(adapter->msix_entries);
|
||||||
|
|
||||||
err_out_decr_ref:
|
err_out_decr_ref:
|
||||||
qlcnic_clr_all_drv_state(adapter, 0);
|
qlcnic_clr_all_drv_state(adapter, 0);
|
||||||
@@ -1666,6 +1701,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
|
|||||||
qlcnic_free_lb_filters_mem(adapter);
|
qlcnic_free_lb_filters_mem(adapter);
|
||||||
|
|
||||||
qlcnic_teardown_intr(adapter);
|
qlcnic_teardown_intr(adapter);
|
||||||
|
kfree(adapter->msix_entries);
|
||||||
|
|
||||||
qlcnic_remove_diag_entries(adapter);
|
qlcnic_remove_diag_entries(adapter);
|
||||||
|
|
||||||
@@ -3299,6 +3335,56 @@ static struct device_attribute dev_attr_diag_mode = {
|
|||||||
.store = qlcnic_store_diag_mode,
|
.store = qlcnic_store_diag_mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
|
||||||
|
{
|
||||||
|
if (!use_msi_x && !use_msi) {
|
||||||
|
netdev_info(netdev, "no msix or msi support, hence no rss\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((val > max_hw) || (val < 2) || !is_power_of_2(val)) {
|
||||||
|
netdev_info(netdev, "rss_ring valid range [2 - %x] in "
|
||||||
|
" powers of 2\n", max_hw);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = adapter->netdev;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
|
netif_device_detach(netdev);
|
||||||
|
if (netif_running(netdev))
|
||||||
|
__qlcnic_down(adapter, netdev);
|
||||||
|
qlcnic_detach(adapter);
|
||||||
|
qlcnic_teardown_intr(adapter);
|
||||||
|
|
||||||
|
if (qlcnic_enable_msix(adapter, data)) {
|
||||||
|
netdev_info(netdev, "failed setting max_rss; rss disabled\n");
|
||||||
|
qlcnic_enable_msi_legacy(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netif_running(netdev)) {
|
||||||
|
err = qlcnic_attach(adapter);
|
||||||
|
if (err)
|
||||||
|
goto done;
|
||||||
|
err = __qlcnic_up(adapter, netdev);
|
||||||
|
if (err)
|
||||||
|
goto done;
|
||||||
|
qlcnic_restore_indev_addr(netdev, NETDEV_UP);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
netif_device_attach(netdev);
|
||||||
|
clear_bit(__QLCNIC_RESETTING, &adapter->state);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
|
qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
|
||||||
loff_t offset, size_t size)
|
loff_t offset, size_t size)
|
||||||
|
Reference in New Issue
Block a user