summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/chelsio
diff options
context:
space:
mode:
authorHariprasad Shenai <hariprasad@chelsio.com>2016-08-23 11:35:32 +0530
committerDavid S. Miller <davem@davemloft.net>2016-08-23 17:07:08 -0700
commite7b48a32dc5db48ca14e6472b920102c7e53f5aa (patch)
tree8d0bb64a559d51f41457ca4d04dda8c32a6a7ade /drivers/net/ethernet/chelsio
parentcebc5cbab48f5c58512e26aa1965284354227258 (diff)
downloadblackbird-op-linux-e7b48a32dc5db48ca14e6472b920102c7e53f5aa.tar.gz
blackbird-op-linux-e7b48a32dc5db48ca14e6472b920102c7e53f5aa.zip
cxgb4: Fix issue while re-registering VF mgmt netdev
When we disable SRIOV, we used to unregister the netdev but wasn't freed. But next time when the same netdev is registered, since the state was in 'NETREG_UNREGISTERED', we used to hit BUG_ON in register_netdevice, where it expects the state to be 'NETREG_UNINITIALIZED'. Alloc netdev and register them while configuring SRIOV, and free them when SRIOV is disabled. Also added a new function to setup ethernet properties instead of using ether_setup. Set carrier off by default, since we don't have to do any transmit on the interface. Fixes: 7829451c695e ("cxgb4: Add control net_device for configuring PCIe VF") Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/chelsio')
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c97
2 files changed, 67 insertions, 31 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index f988c600c68d..3f7b33aa5ec5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -798,6 +798,7 @@ struct adapter {
unsigned int mbox;
unsigned int pf;
unsigned int flags;
+ unsigned int adap_idx;
enum chip_type chip;
int msg_enable;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index be5c942ad8e0..44019bdd526d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3085,6 +3085,15 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
}
#ifdef CONFIG_PCI_IOV
+static int dummy_open(struct net_device *dev)
+{
+ /* Turn carrier off since we don't have to transmit anything on this
+ * interface.
+ */
+ netif_carrier_off(dev);
+ return 0;
+}
+
static int cxgb_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
{
struct port_info *pi = netdev_priv(dev);
@@ -3246,11 +3255,12 @@ static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_set_tx_maxrate = cxgb_set_tx_maxrate,
};
-static const struct net_device_ops cxgb4_mgmt_netdev_ops = {
#ifdef CONFIG_PCI_IOV
+static const struct net_device_ops cxgb4_mgmt_netdev_ops = {
+ .ndo_open = dummy_open,
.ndo_set_vf_mac = cxgb_set_vf_mac,
-#endif
};
+#endif
static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
@@ -5023,6 +5033,51 @@ static int get_chip_type(struct pci_dev *pdev, u32 pl_rev)
}
#ifdef CONFIG_PCI_IOV
+static void dummy_setup(struct net_device *dev)
+{
+ dev->type = ARPHRD_NONE;
+ dev->mtu = 0;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 0;
+ dev->flags |= IFF_NOARP;
+ dev->priv_flags |= IFF_NO_QUEUE;
+
+ /* Initialize the device structure. */
+ dev->netdev_ops = &cxgb4_mgmt_netdev_ops;
+ dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops;
+ dev->destructor = free_netdev;
+}
+
+static int config_mgmt_dev(struct pci_dev *pdev)
+{
+ struct adapter *adap = pci_get_drvdata(pdev);
+ struct net_device *netdev;
+ struct port_info *pi;
+ char name[IFNAMSIZ];
+ int err;
+
+ snprintf(name, IFNAMSIZ, "mgmtpf%d%d", adap->adap_idx, adap->pf);
+ netdev = alloc_netdev(0, name, NET_NAME_UNKNOWN, dummy_setup);
+ if (!netdev)
+ return -ENOMEM;
+
+ pi = netdev_priv(netdev);
+ pi->adapter = adap;
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adap->port[0] = netdev;
+
+ err = register_netdev(adap->port[0]);
+ if (err) {
+ pr_info("Unable to register VF mgmt netdev %s\n", name);
+ free_netdev(adap->port[0]);
+ adap->port[0] = NULL;
+ return err;
+ }
+ return 0;
+}
+
static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
{
struct adapter *adap = pci_get_drvdata(pdev);
@@ -5057,8 +5112,10 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
*/
if (!num_vfs) {
pci_disable_sriov(pdev);
- if (adap->port[0]->reg_state == NETREG_REGISTERED)
+ if (adap->port[0]) {
unregister_netdev(adap->port[0]);
+ adap->port[0] = NULL;
+ }
return num_vfs;
}
@@ -5067,11 +5124,9 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
if (err)
return err;
- if (adap->port[0]->reg_state == NETREG_UNINITIALIZED) {
- err = register_netdev(adap->port[0]);
- if (err < 0)
- pr_info("Unable to register VF mgmt netdev\n");
- }
+ err = config_mgmt_dev(pdev);
+ if (err)
+ return err;
}
return num_vfs;
}
@@ -5084,9 +5139,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bool highdma = false;
struct adapter *adapter = NULL;
struct net_device *netdev;
-#ifdef CONFIG_PCI_IOV
- char name[IFNAMSIZ];
-#endif
void __iomem *regs;
u32 whoami, pl_rev;
enum chip_type chip;
@@ -5447,40 +5499,24 @@ sriov:
goto free_pci_region;
}
- snprintf(name, IFNAMSIZ, "mgmtpf%d%d", adap_idx, func);
- netdev = alloc_netdev(0, name, NET_NAME_UNKNOWN, ether_setup);
- if (!netdev) {
- err = -ENOMEM;
- goto free_adapter;
- }
-
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
adapter->name = pci_name(pdev);
adapter->mbox = func;
adapter->pf = func;
adapter->regs = regs;
+ adapter->adap_idx = adap_idx;
adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
(sizeof(struct mbox_cmd) *
T4_OS_LOG_MBOX_CMDS),
GFP_KERNEL);
if (!adapter->mbox_log) {
err = -ENOMEM;
- goto free_netdevice;
+ goto free_adapter;
}
- pi = netdev_priv(netdev);
- pi->adapter = adapter;
- SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, adapter);
-
- adapter->port[0] = netdev;
- netdev->netdev_ops = &cxgb4_mgmt_netdev_ops;
- netdev->ethtool_ops = &cxgb4_mgmt_ethtool_ops;
-
return 0;
- free_netdevice:
- free_netdev(adapter->port[0]);
free_adapter:
kfree(adapter);
free_pci_region:
@@ -5582,9 +5618,8 @@ static void remove_one(struct pci_dev *pdev)
}
#ifdef CONFIG_PCI_IOV
else {
- if (adapter->port[0]->reg_state == NETREG_REGISTERED)
+ if (adapter->port[0])
unregister_netdev(adapter->port[0]);
- free_netdev(adapter->port[0]);
iounmap(adapter->regs);
kfree(adapter);
pci_disable_sriov(pdev);
OpenPOWER on IntegriCloud