Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ieee1394: nodemgr: parallelize between several hosts

Remove the global nodemgr_serialize mutex which enclosed most of the
host thread event loop. This allows for parallelism between several
host adapter cards.

Properly serialize the driver hooks .update(), .suspend(), .resume(),
and .remove() by means of device->sem. These hooks can be called from
outside the host threads' contexts.

Get() and put() the device.driver when calling its hooks.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

+44 -27
+44 -27
drivers/ieee1394/nodemgr.c
··· 19 19 #include <linux/mutex.h> 20 20 #include <linux/freezer.h> 21 21 #include <asm/atomic.h> 22 + #include <asm/semaphore.h> 22 23 23 24 #include "csr.h" 24 25 #include "highlevel.h" ··· 145 144 * driver/device mappings. The old nodemgr used to handle all this itself, 146 145 * but now we are much simpler because of the LDM. 147 146 */ 148 - 149 - static DEFINE_MUTEX(nodemgr_serialize); 150 147 151 148 struct host_info { 152 149 struct hpsb_host *host; ··· 1381 1382 { 1382 1383 struct device *dev; 1383 1384 struct unit_directory *ud; 1385 + struct device_driver *drv; 1386 + int error; 1384 1387 1385 1388 HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", 1386 1389 NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); ··· 1396 1395 if (ud->ne != ne) 1397 1396 continue; 1398 1397 1399 - if (ud->device.driver && 1400 - (!ud->device.driver->suspend || 1401 - ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) 1398 + drv = get_driver(ud->device.driver); 1399 + if (!drv) 1400 + continue; 1401 + 1402 + error = 1; /* release if suspend is not implemented */ 1403 + if (drv->suspend) { 1404 + down(&ud->device.sem); 1405 + error = drv->suspend(&ud->device, PMSG_SUSPEND); 1406 + up(&ud->device.sem); 1407 + } 1408 + if (error) 1402 1409 device_release_driver(&ud->device); 1410 + put_driver(drv); 1403 1411 } 1404 1412 up(&nodemgr_ud_class.sem); 1405 1413 } ··· 1418 1408 { 1419 1409 struct device *dev; 1420 1410 struct unit_directory *ud; 1411 + struct device_driver *drv; 1421 1412 1422 1413 ne->in_limbo = 0; 1423 1414 device_remove_file(&ne->device, &dev_attr_ne_in_limbo); ··· 1429 1418 if (ud->ne != ne) 1430 1419 continue; 1431 1420 1432 - if (ud->device.driver && ud->device.driver->resume) 1433 - ud->device.driver->resume(&ud->device); 1421 + drv = get_driver(ud->device.driver); 1422 + if (!drv) 1423 + continue; 1424 + 1425 + if (drv->resume) { 1426 + down(&ud->device.sem); 1427 + drv->resume(&ud->device); 1428 + up(&ud->device.sem); 1429 + } 1430 + put_driver(drv); 1434 1431 } 1435 1432 up(&nodemgr_ud_class.sem); 1436 1433 ··· 1449 1430 1450 1431 static void nodemgr_update_pdrv(struct node_entry *ne) 1451 1432 { 1452 - struct unit_directory *ud; 1453 - struct hpsb_protocol_driver *pdrv; 1454 1433 struct device *dev; 1434 + struct unit_directory *ud; 1435 + struct device_driver *drv; 1436 + struct hpsb_protocol_driver *pdrv; 1437 + int error; 1455 1438 1456 1439 down(&nodemgr_ud_class.sem); 1457 1440 list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { ··· 1461 1440 if (ud->ne != ne) 1462 1441 continue; 1463 1442 1464 - if (ud->device.driver) { 1465 - pdrv = container_of(ud->device.driver, 1466 - struct hpsb_protocol_driver, 1467 - driver); 1468 - if (pdrv->update && pdrv->update(ud)) 1469 - device_release_driver(&ud->device); 1443 + drv = get_driver(ud->device.driver); 1444 + if (!drv) 1445 + continue; 1446 + 1447 + error = 0; 1448 + pdrv = container_of(drv, struct hpsb_protocol_driver, driver); 1449 + if (pdrv->update) { 1450 + down(&ud->device.sem); 1451 + error = pdrv->update(ud); 1452 + up(&ud->device.sem); 1470 1453 } 1454 + if (error) 1455 + device_release_driver(&ud->device); 1456 + put_driver(drv); 1471 1457 } 1472 1458 up(&nodemgr_ud_class.sem); 1473 1459 } ··· 1716 1688 if (kthread_should_stop()) 1717 1689 goto exit; 1718 1690 1719 - if (mutex_lock_interruptible(&nodemgr_serialize)) { 1720 - if (try_to_freeze()) 1721 - continue; 1722 - goto exit; 1723 - } 1724 - 1725 1691 /* Pause for 1/4 second in 1/16 second intervals, 1726 1692 * to make sure things settle down. */ 1727 1693 g = get_hpsb_generation(host); 1728 1694 for (i = 0; i < 4 ; i++) { 1729 1695 if (msleep_interruptible(63) || kthread_should_stop()) 1730 - goto unlock_exit; 1696 + goto exit; 1731 1697 1732 1698 /* Now get the generation in which the node ID's we collect 1733 1699 * are valid. During the bus scan we will use this generation ··· 1739 1717 if (!nodemgr_check_irm_capability(host, reset_cycles) || 1740 1718 !nodemgr_do_irm_duties(host, reset_cycles)) { 1741 1719 reset_cycles++; 1742 - mutex_unlock(&nodemgr_serialize); 1743 1720 continue; 1744 1721 } 1745 1722 reset_cycles = 0; ··· 1755 1734 1756 1735 /* Update some of our sysfs symlinks */ 1757 1736 nodemgr_update_host_dev_links(host); 1758 - 1759 - mutex_unlock(&nodemgr_serialize); 1760 1737 } 1761 - unlock_exit: 1762 - mutex_unlock(&nodemgr_serialize); 1763 1738 exit: 1764 1739 HPSB_VERBOSE("NodeMgr: Exiting thread"); 1765 1740 return 0;