aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/iseries_veth.c121
1 files changed, 83 insertions, 38 deletions
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index ab9fb218d111..5ce9f9348042 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -129,6 +129,7 @@ struct veth_lpar_connection {
129 int num_events; 129 int num_events;
130 struct VethCapData local_caps; 130 struct VethCapData local_caps;
131 131
132 struct kobject kobject;
132 struct timer_list ack_timer; 133 struct timer_list ack_timer;
133 134
134 spinlock_t lock; 135 spinlock_t lock;
@@ -171,6 +172,11 @@ static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
171static void veth_flush_pending(struct veth_lpar_connection *cnx); 172static void veth_flush_pending(struct veth_lpar_connection *cnx);
172static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *); 173static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
173static void veth_timed_ack(unsigned long connectionPtr); 174static void veth_timed_ack(unsigned long connectionPtr);
175static void veth_release_connection(struct kobject *kobject);
176
177static struct kobj_type veth_lpar_connection_ktype = {
178 .release = veth_release_connection
179};
174 180
175/* 181/*
176 * Utility functions 182 * Utility functions
@@ -611,7 +617,7 @@ static int veth_init_connection(u8 rlp)
611{ 617{
612 struct veth_lpar_connection *cnx; 618 struct veth_lpar_connection *cnx;
613 struct veth_msg *msgs; 619 struct veth_msg *msgs;
614 int i; 620 int i, rc;
615 621
616 if ( (rlp == this_lp) 622 if ( (rlp == this_lp)
617 || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) 623 || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -632,6 +638,14 @@ static int veth_init_connection(u8 rlp)
632 638
633 veth_cnx[rlp] = cnx; 639 veth_cnx[rlp] = cnx;
634 640
641 /* This gets us 1 reference, which is held on behalf of the driver
642 * infrastructure. It's released at module unload. */
643 kobject_init(&cnx->kobject);
644 cnx->kobject.ktype = &veth_lpar_connection_ktype;
645 rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
646 if (rc != 0)
647 return rc;
648
635 msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL); 649 msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
636 if (! msgs) { 650 if (! msgs) {
637 veth_error("Can't allocate buffers for LPAR %d.\n", rlp); 651 veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
@@ -660,11 +674,9 @@ static int veth_init_connection(u8 rlp)
660 return 0; 674 return 0;
661} 675}
662 676
663static void veth_stop_connection(u8 rlp) 677static void veth_stop_connection(struct veth_lpar_connection *cnx)
664{ 678{
665 struct veth_lpar_connection *cnx = veth_cnx[rlp]; 679 if (!cnx)
666
667 if (! cnx)
668 return; 680 return;
669 681
670 spin_lock_irq(&cnx->lock); 682 spin_lock_irq(&cnx->lock);
@@ -685,11 +697,9 @@ static void veth_stop_connection(u8 rlp)
685 flush_scheduled_work(); 697 flush_scheduled_work();
686} 698}
687 699
688static void veth_destroy_connection(u8 rlp) 700static void veth_destroy_connection(struct veth_lpar_connection *cnx)
689{ 701{
690 struct veth_lpar_connection *cnx = veth_cnx[rlp]; 702 if (!cnx)
691
692 if (! cnx)
693 return; 703 return;
694 704
695 if (cnx->num_events > 0) 705 if (cnx->num_events > 0)
@@ -704,8 +714,16 @@ static void veth_destroy_connection(u8 rlp)
704 NULL, NULL); 714 NULL, NULL);
705 715
706 kfree(cnx->msgs); 716 kfree(cnx->msgs);
717 veth_cnx[cnx->remote_lp] = NULL;
707 kfree(cnx); 718 kfree(cnx);
708 veth_cnx[rlp] = NULL; 719}
720
721static void veth_release_connection(struct kobject *kobj)
722{
723 struct veth_lpar_connection *cnx;
724 cnx = container_of(kobj, struct veth_lpar_connection, kobject);
725 veth_stop_connection(cnx);
726 veth_destroy_connection(cnx);
709} 727}
710 728
711/* 729/*
@@ -1349,15 +1367,31 @@ static void veth_timed_ack(unsigned long ptr)
1349 1367
1350static int veth_remove(struct vio_dev *vdev) 1368static int veth_remove(struct vio_dev *vdev)
1351{ 1369{
1352 int i = vdev->unit_address; 1370 struct veth_lpar_connection *cnx;
1353 struct net_device *dev; 1371 struct net_device *dev;
1372 struct veth_port *port;
1373 int i;
1354 1374
1355 dev = veth_dev[i]; 1375 dev = veth_dev[vdev->unit_address];
1356 if (dev != NULL) { 1376
1357 veth_dev[i] = NULL; 1377 if (! dev)
1358 unregister_netdev(dev); 1378 return 0;
1359 free_netdev(dev); 1379
1380 port = netdev_priv(dev);
1381
1382 for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
1383 cnx = veth_cnx[i];
1384
1385 if (cnx && (port->lpar_map & (1 << i))) {
1386 /* Drop our reference to connections on our VLAN */
1387 kobject_put(&cnx->kobject);
1388 }
1360 } 1389 }
1390
1391 veth_dev[vdev->unit_address] = NULL;
1392 unregister_netdev(dev);
1393 free_netdev(dev);
1394
1361 return 0; 1395 return 0;
1362} 1396}
1363 1397
@@ -1365,6 +1399,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1365{ 1399{
1366 int i = vdev->unit_address; 1400 int i = vdev->unit_address;
1367 struct net_device *dev; 1401 struct net_device *dev;
1402 struct veth_port *port;
1368 1403
1369 dev = veth_probe_one(i, &vdev->dev); 1404 dev = veth_probe_one(i, &vdev->dev);
1370 if (dev == NULL) { 1405 if (dev == NULL) {
@@ -1373,11 +1408,23 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
1373 } 1408 }
1374 veth_dev[i] = dev; 1409 veth_dev[i] = dev;
1375 1410
1376 /* Start the state machine on each connection, to commence 1411 port = (struct veth_port*)netdev_priv(dev);
1377 * link negotiation */ 1412
1378 for (i = 0; i < HVMAXARCHITECTEDLPS; i++) 1413 /* Start the state machine on each connection on this vlan. If we're
1379 if (veth_cnx[i]) 1414 * the first dev to do so this will commence link negotiation */
1380 veth_kick_statemachine(veth_cnx[i]); 1415 for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
1416 struct veth_lpar_connection *cnx;
1417
1418 if (! (port->lpar_map & (1 << i)))
1419 continue;
1420
1421 cnx = veth_cnx[i];
1422 if (!cnx)
1423 continue;
1424
1425 kobject_get(&cnx->kobject);
1426 veth_kick_statemachine(cnx);
1427 }
1381 1428
1382 return 0; 1429 return 0;
1383} 1430}
@@ -1406,29 +1453,27 @@ static struct vio_driver veth_driver = {
1406void __exit veth_module_cleanup(void) 1453void __exit veth_module_cleanup(void)
1407{ 1454{
1408 int i; 1455 int i;
1456 struct veth_lpar_connection *cnx;
1409 1457
1410 /* Stop the queues first to stop any new packets being sent. */ 1458 /* Disconnect our "irq" to stop events coming from the Hypervisor. */
1411 for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
1412 if (veth_dev[i])
1413 netif_stop_queue(veth_dev[i]);
1414
1415 /* Stop the connections before we unregister the driver. This
1416 * ensures there's no skbs lying around holding the device open. */
1417 for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
1418 veth_stop_connection(i);
1419
1420 HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan); 1459 HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
1421 1460
1422 /* Hypervisor callbacks may have scheduled more work while we 1461 /* Make sure any work queued from Hypervisor callbacks is finished. */
1423 * were stoping connections. Now that we've disconnected from
1424 * the hypervisor make sure everything's finished. */
1425 flush_scheduled_work(); 1462 flush_scheduled_work();
1426 1463
1427 vio_unregister_driver(&veth_driver); 1464 for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
1465 cnx = veth_cnx[i];
1466
1467 if (!cnx)
1468 continue;
1428 1469
1429 for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) 1470 /* Drop the driver's reference to the connection */
1430 veth_destroy_connection(i); 1471 kobject_put(&cnx->kobject);
1472 }
1431 1473
1474 /* Unregister the driver, which will close all the netdevs and stop
1475 * the connections when they're no longer referenced. */
1476 vio_unregister_driver(&veth_driver);
1432} 1477}
1433module_exit(veth_module_cleanup); 1478module_exit(veth_module_cleanup);
1434 1479
@@ -1456,7 +1501,7 @@ int __init veth_module_init(void)
1456 1501
1457error: 1502error:
1458 for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) { 1503 for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
1459 veth_destroy_connection(i); 1504 veth_destroy_connection(veth_cnx[i]);
1460 } 1505 }
1461 1506
1462 return rc; 1507 return rc;