diff options
Diffstat (limited to 'drivers/net/xen-netback/interface.c')
-rw-r--r-- | drivers/net/xen-netback/interface.c | 43 |
1 files changed, 26 insertions, 17 deletions
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 01bb854c7f62..870f1fa58370 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
@@ -214,10 +214,14 @@ static netdev_features_t xenvif_fix_features(struct net_device *dev, | |||
214 | 214 | ||
215 | if (!vif->can_sg) | 215 | if (!vif->can_sg) |
216 | features &= ~NETIF_F_SG; | 216 | features &= ~NETIF_F_SG; |
217 | if (!vif->gso && !vif->gso_prefix) | 217 | if (~(vif->gso_mask | vif->gso_prefix_mask) & GSO_BIT(TCPV4)) |
218 | features &= ~NETIF_F_TSO; | 218 | features &= ~NETIF_F_TSO; |
219 | if (!vif->csum) | 219 | if (~(vif->gso_mask | vif->gso_prefix_mask) & GSO_BIT(TCPV6)) |
220 | features &= ~NETIF_F_TSO6; | ||
221 | if (!vif->ip_csum) | ||
220 | features &= ~NETIF_F_IP_CSUM; | 222 | features &= ~NETIF_F_IP_CSUM; |
223 | if (!vif->ipv6_csum) | ||
224 | features &= ~NETIF_F_IPV6_CSUM; | ||
221 | 225 | ||
222 | return features; | 226 | return features; |
223 | } | 227 | } |
@@ -306,18 +310,19 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, | |||
306 | vif->domid = domid; | 310 | vif->domid = domid; |
307 | vif->handle = handle; | 311 | vif->handle = handle; |
308 | vif->can_sg = 1; | 312 | vif->can_sg = 1; |
309 | vif->csum = 1; | 313 | vif->ip_csum = 1; |
310 | vif->dev = dev; | 314 | vif->dev = dev; |
311 | 315 | ||
312 | vif->credit_bytes = vif->remaining_credit = ~0UL; | 316 | vif->credit_bytes = vif->remaining_credit = ~0UL; |
313 | vif->credit_usec = 0UL; | 317 | vif->credit_usec = 0UL; |
314 | init_timer(&vif->credit_timeout); | 318 | init_timer(&vif->credit_timeout); |
315 | /* Initialize 'expires' now: it's used to track the credit window. */ | 319 | vif->credit_window_start = get_jiffies_64(); |
316 | vif->credit_timeout.expires = jiffies; | ||
317 | 320 | ||
318 | dev->netdev_ops = &xenvif_netdev_ops; | 321 | dev->netdev_ops = &xenvif_netdev_ops; |
319 | dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; | 322 | dev->hw_features = NETIF_F_SG | |
320 | dev->features = dev->hw_features; | 323 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | |
324 | NETIF_F_TSO | NETIF_F_TSO6; | ||
325 | dev->features = dev->hw_features | NETIF_F_RXCSUM; | ||
321 | SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); | 326 | SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops); |
322 | 327 | ||
323 | dev->tx_queue_len = XENVIF_QUEUE_LENGTH; | 328 | dev->tx_queue_len = XENVIF_QUEUE_LENGTH; |
@@ -363,11 +368,11 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
363 | unsigned long rx_ring_ref, unsigned int tx_evtchn, | 368 | unsigned long rx_ring_ref, unsigned int tx_evtchn, |
364 | unsigned int rx_evtchn) | 369 | unsigned int rx_evtchn) |
365 | { | 370 | { |
371 | struct task_struct *task; | ||
366 | int err = -ENOMEM; | 372 | int err = -ENOMEM; |
367 | 373 | ||
368 | /* Already connected through? */ | 374 | BUG_ON(vif->tx_irq); |
369 | if (vif->tx_irq) | 375 | BUG_ON(vif->task); |
370 | return 0; | ||
371 | 376 | ||
372 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); | 377 | err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); |
373 | if (err < 0) | 378 | if (err < 0) |
@@ -406,14 +411,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, | |||
406 | } | 411 | } |
407 | 412 | ||
408 | init_waitqueue_head(&vif->wq); | 413 | init_waitqueue_head(&vif->wq); |
409 | vif->task = kthread_create(xenvif_kthread, | 414 | task = kthread_create(xenvif_kthread, |
410 | (void *)vif, "%s", vif->dev->name); | 415 | (void *)vif, "%s", vif->dev->name); |
411 | if (IS_ERR(vif->task)) { | 416 | if (IS_ERR(task)) { |
412 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); | 417 | pr_warn("Could not allocate kthread for %s\n", vif->dev->name); |
413 | err = PTR_ERR(vif->task); | 418 | err = PTR_ERR(task); |
414 | goto err_rx_unbind; | 419 | goto err_rx_unbind; |
415 | } | 420 | } |
416 | 421 | ||
422 | vif->task = task; | ||
423 | |||
417 | rtnl_lock(); | 424 | rtnl_lock(); |
418 | if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) | 425 | if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) |
419 | dev_set_mtu(vif->dev, ETH_DATA_LEN); | 426 | dev_set_mtu(vif->dev, ETH_DATA_LEN); |
@@ -456,6 +463,11 @@ void xenvif_disconnect(struct xenvif *vif) | |||
456 | if (netif_carrier_ok(vif->dev)) | 463 | if (netif_carrier_ok(vif->dev)) |
457 | xenvif_carrier_off(vif); | 464 | xenvif_carrier_off(vif); |
458 | 465 | ||
466 | if (vif->task) { | ||
467 | kthread_stop(vif->task); | ||
468 | vif->task = NULL; | ||
469 | } | ||
470 | |||
459 | if (vif->tx_irq) { | 471 | if (vif->tx_irq) { |
460 | if (vif->tx_irq == vif->rx_irq) | 472 | if (vif->tx_irq == vif->rx_irq) |
461 | unbind_from_irqhandler(vif->tx_irq, vif); | 473 | unbind_from_irqhandler(vif->tx_irq, vif); |
@@ -466,9 +478,6 @@ void xenvif_disconnect(struct xenvif *vif) | |||
466 | vif->tx_irq = 0; | 478 | vif->tx_irq = 0; |
467 | } | 479 | } |
468 | 480 | ||
469 | if (vif->task) | ||
470 | kthread_stop(vif->task); | ||
471 | |||
472 | xenvif_unmap_frontend_rings(vif); | 481 | xenvif_unmap_frontend_rings(vif); |
473 | } | 482 | } |
474 | 483 | ||