{
struct veth_allocation vc = { COMPLETION_INITIALIZER(vc.c), 0 };
- mf_allocateLpEvents(rlp, HvLpEvent_Type_VirtualLan,
+ mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
sizeof(struct VethLpEvent), number,
&veth_complete_allocation, &vc);
wait_for_completion(&vc.c);
return 0;
}
-static void veth_destroy_connection(u8 rlp)
+static void veth_stop_connection(u8 rlp)
{
struct veth_lpar_connection *cnx = veth_cnx[rlp];
del_timer_sync(&cnx->ack_timer);
if (cnx->num_events > 0)
- mf_deallocateLpEvents(cnx->remote_lp,
+ mf_deallocate_lp_events(cnx->remote_lp,
HvLpEvent_Type_VirtualLan,
cnx->num_events,
NULL, NULL);
if (cnx->num_ack_events > 0)
- mf_deallocateLpEvents(cnx->remote_lp,
+ mf_deallocate_lp_events(cnx->remote_lp,
HvLpEvent_Type_VirtualLan,
cnx->num_ack_events,
NULL, NULL);
+}
+
+static void veth_destroy_connection(u8 rlp)
+{
+ struct veth_lpar_connection *cnx = veth_cnx[rlp];
+
+ if (! cnx)
+ return;
- if (cnx->msgs)
- kfree(cnx->msgs);
+ kfree(cnx->msgs);
+ kfree(cnx);
+ veth_cnx[rlp] = NULL;
}
/*
write_unlock_irqrestore(&port->mcast_gate, flags);
}
-static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
-#ifdef SIOCETHTOOL
- struct ethtool_cmd ecmd;
-
- if (cmd != SIOCETHTOOL)
- return -EOPNOTSUPP;
- if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
- return -EFAULT;
- switch (ecmd.cmd) {
- case ETHTOOL_GSET:
- ecmd.supported = (SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
- ecmd.advertising = (SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
-
- ecmd.port = PORT_FIBRE;
- ecmd.transceiver = XCVR_INTERNAL;
- ecmd.phy_address = 0;
- ecmd.speed = SPEED_1000;
- ecmd.duplex = DUPLEX_FULL;
- ecmd.autoneg = AUTONEG_ENABLE;
- ecmd.maxtxpkt = 120;
- ecmd.maxrxpkt = 120;
- if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
- return -EFAULT;
- return 0;
-
- case ETHTOOL_GDRVINFO:{
- struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
- strncpy(info.driver, "veth", sizeof(info.driver) - 1);
- info.driver[sizeof(info.driver) - 1] = '\0';
- strncpy(info.version, "1.0", sizeof(info.version) - 1);
- if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- /* get link status */
- case ETHTOOL_GLINK:{
- struct ethtool_value edata = { ETHTOOL_GLINK };
- edata.data = 1;
- if (copy_to_user(ifr->ifr_data, &edata, sizeof(edata)))
- return -EFAULT;
- return 0;
- }
+ strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+ info->driver[sizeof(info->driver) - 1] = '\0';
+ strncpy(info->version, "1.0", sizeof(info->version) - 1);
+}
- default:
- break;
- }
+static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+ ecmd->supported = (SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+ ecmd->advertising = (SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->phy_address = 0;
+ ecmd->speed = SPEED_1000;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_ENABLE;
+ ecmd->maxtxpkt = 120;
+ ecmd->maxrxpkt = 120;
+ return 0;
+}
-#endif
- return -EOPNOTSUPP;
+static u32 veth_get_link(struct net_device *dev)
+{
+ return 1;
}
+static struct ethtool_ops ops = {
+ .get_drvinfo = veth_get_drvinfo,
+ .get_settings = veth_get_settings,
+ .get_link = veth_get_link,
+};
+
static void veth_tx_timeout(struct net_device *dev)
{
struct veth_port *port = (struct veth_port *)dev->priv;
dev->change_mtu = veth_change_mtu;
dev->set_mac_address = NULL;
dev->set_multicast_list = veth_set_multicast_list;
- dev->do_ioctl = veth_ioctl;
+ SET_ETHTOOL_OPS(dev, &ops);
dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000);
dev->tx_timeout = veth_tx_timeout;
vio_unregister_driver(&veth_driver);
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_destroy_connection(i);
+ veth_stop_connection(i);
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
+
+ /* Hypervisor callbacks may have scheduled more work while we
+ * were destroying connections. Now that we've disconnected from
+ * the hypervisor make sure everything's finished. */
+ flush_scheduled_work();
+
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
+ veth_destroy_connection(i);
+
}
module_exit(veth_module_cleanup);