|
@@ -695,8 +695,12 @@ static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
|
|
|
}
|
|
|
|
|
|
static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
|
|
|
+ struct net_device *ndev,
|
|
|
unsigned long event)
|
|
|
{
|
|
|
+ struct pci_dev *pdev_net;
|
|
|
+ unsigned int slot;
|
|
|
+
|
|
|
switch (event) {
|
|
|
case NETDEV_REBOOT:
|
|
|
case NETDEV_DOWN:
|
|
@@ -714,6 +718,24 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
|
|
|
else
|
|
|
pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
|
|
|
break;
|
|
|
+ case NETDEV_UNREGISTER:
|
|
|
+ dev_put(dev->netdev);
|
|
|
+ dev->netdev = NULL;
|
|
|
+ break;
|
|
|
+ case NETDEV_REGISTER:
|
|
|
+ /* vmxnet3 will have same bus, slot. But func will be 0 */
|
|
|
+ slot = PCI_SLOT(dev->pdev->devfn);
|
|
|
+ pdev_net = pci_get_slot(dev->pdev->bus,
|
|
|
+ PCI_DEVFN(slot, 0));
|
|
|
+ if ((dev->netdev == NULL) &&
|
|
|
+ (pci_get_drvdata(pdev_net) == ndev)) {
|
|
|
+ /* this is our netdev */
|
|
|
+ dev->netdev = ndev;
|
|
|
+ dev_hold(ndev);
|
|
|
+ }
|
|
|
+ pci_dev_put(pdev_net);
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
|
|
|
event, dev->ib_dev.name);
|
|
@@ -730,8 +752,11 @@ static void pvrdma_netdevice_event_work(struct work_struct *work)
|
|
|
|
|
|
mutex_lock(&pvrdma_device_list_lock);
|
|
|
list_for_each_entry(dev, &pvrdma_device_list, device_link) {
|
|
|
- if (dev->netdev == netdev_work->event_netdev) {
|
|
|
- pvrdma_netdevice_event_handle(dev, netdev_work->event);
|
|
|
+ if ((netdev_work->event == NETDEV_REGISTER) ||
|
|
|
+ (dev->netdev == netdev_work->event_netdev)) {
|
|
|
+ pvrdma_netdevice_event_handle(dev,
|
|
|
+ netdev_work->event_netdev,
|
|
|
+ netdev_work->event);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -964,6 +989,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
|
|
|
ret = -ENODEV;
|
|
|
goto err_free_cq_ring;
|
|
|
}
|
|
|
+ dev_hold(dev->netdev);
|
|
|
|
|
|
dev_info(&pdev->dev, "paired device to %s\n", dev->netdev->name);
|
|
|
|
|
@@ -1036,6 +1062,10 @@ err_free_intrs:
|
|
|
pvrdma_free_irq(dev);
|
|
|
pci_free_irq_vectors(pdev);
|
|
|
err_free_cq_ring:
|
|
|
+ if (dev->netdev) {
|
|
|
+ dev_put(dev->netdev);
|
|
|
+ dev->netdev = NULL;
|
|
|
+ }
|
|
|
pvrdma_page_dir_cleanup(dev, &dev->cq_pdir);
|
|
|
err_free_async_ring:
|
|
|
pvrdma_page_dir_cleanup(dev, &dev->async_pdir);
|
|
@@ -1075,6 +1105,11 @@ static void pvrdma_pci_remove(struct pci_dev *pdev)
|
|
|
|
|
|
flush_workqueue(event_wq);
|
|
|
|
|
|
+ if (dev->netdev) {
|
|
|
+ dev_put(dev->netdev);
|
|
|
+ dev->netdev = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
/* Unregister ib device */
|
|
|
ib_unregister_device(&dev->ib_dev);
|
|
|
|