|
@@ -14,6 +14,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/kthread.h>
|
|
|
|
+#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/freezer.h>
|
|
#include <asm/atomic.h>
|
|
#include <asm/atomic.h>
|
|
@@ -67,7 +68,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
|
|
{
|
|
{
|
|
quadlet_t q;
|
|
quadlet_t q;
|
|
u8 i, *speed, old_speed, good_speed;
|
|
u8 i, *speed, old_speed, good_speed;
|
|
- int ret;
|
|
|
|
|
|
+ int error;
|
|
|
|
|
|
speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
|
|
speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
|
|
old_speed = *speed;
|
|
old_speed = *speed;
|
|
@@ -79,9 +80,9 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
|
|
* just finished its initialization. */
|
|
* just finished its initialization. */
|
|
for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
|
|
for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
|
|
*speed = i;
|
|
*speed = i;
|
|
- ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
|
|
|
- &q, sizeof(quadlet_t));
|
|
|
|
- if (ret)
|
|
|
|
|
|
+ error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
|
|
|
+ &q, sizeof(quadlet_t));
|
|
|
|
+ if (error)
|
|
break;
|
|
break;
|
|
*buffer = q;
|
|
*buffer = q;
|
|
good_speed = i;
|
|
good_speed = i;
|
|
@@ -95,19 +96,19 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
*speed = old_speed;
|
|
*speed = old_speed;
|
|
- return ret;
|
|
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
|
|
|
|
static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
|
|
static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
|
|
- void *buffer, void *__ci)
|
|
|
|
|
|
+ void *buffer, void *__ci)
|
|
{
|
|
{
|
|
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
|
|
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
|
|
- int i, ret;
|
|
|
|
|
|
+ int i, error;
|
|
|
|
|
|
for (i = 1; ; i++) {
|
|
for (i = 1; ; i++) {
|
|
- ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
|
|
|
- buffer, length);
|
|
|
|
- if (!ret) {
|
|
|
|
|
|
+ error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
|
|
|
|
+ buffer, length);
|
|
|
|
+ if (!error) {
|
|
ci->speed_unverified = 0;
|
|
ci->speed_unverified = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -118,14 +119,14 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
|
|
/* The ieee1394_core guessed the node's speed capability from
|
|
/* The ieee1394_core guessed the node's speed capability from
|
|
* the self ID. Check whether a lower speed works. */
|
|
* the self ID. Check whether a lower speed works. */
|
|
if (ci->speed_unverified && length == sizeof(quadlet_t)) {
|
|
if (ci->speed_unverified && length == sizeof(quadlet_t)) {
|
|
- ret = nodemgr_check_speed(ci, addr, buffer);
|
|
|
|
- if (!ret)
|
|
|
|
|
|
+ error = nodemgr_check_speed(ci, addr, buffer);
|
|
|
|
+ if (!error)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
if (msleep_interruptible(334))
|
|
if (msleep_interruptible(334))
|
|
return -EINTR;
|
|
return -EINTR;
|
|
}
|
|
}
|
|
- return ret;
|
|
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
|
|
|
|
static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
|
|
static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
|
|
@@ -260,9 +261,20 @@ static struct device nodemgr_dev_template_ne = {
|
|
.release = nodemgr_release_ne,
|
|
.release = nodemgr_release_ne,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/* This dummy driver prevents the host devices from being scanned. We have no
|
|
|
|
+ * useful drivers for them yet, and there would be a deadlock possible if the
|
|
|
|
+ * driver core scans the host device while the host's low-level driver (i.e.
|
|
|
|
+ * the host's parent device) is being removed. */
|
|
|
|
+static struct device_driver nodemgr_mid_layer_driver = {
|
|
|
|
+ .bus = &ieee1394_bus_type,
|
|
|
|
+ .name = "nodemgr",
|
|
|
|
+ .owner = THIS_MODULE,
|
|
|
|
+};
|
|
|
|
+
|
|
struct device nodemgr_dev_template_host = {
|
|
struct device nodemgr_dev_template_host = {
|
|
.bus = &ieee1394_bus_type,
|
|
.bus = &ieee1394_bus_type,
|
|
.release = nodemgr_release_host,
|
|
.release = nodemgr_release_host,
|
|
|
|
+ .driver = &nodemgr_mid_layer_driver,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -307,8 +319,8 @@ static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
|
|
return sprintf(buf, format_string, (type)driver->field);\
|
|
return sprintf(buf, format_string, (type)driver->field);\
|
|
} \
|
|
} \
|
|
static struct driver_attribute driver_attr_drv_##field = { \
|
|
static struct driver_attribute driver_attr_drv_##field = { \
|
|
- .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
|
|
|
|
- .show = fw_drv_show_##field, \
|
|
|
|
|
|
+ .attr = {.name = __stringify(field), .mode = S_IRUGO }, \
|
|
|
|
+ .show = fw_drv_show_##field, \
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -362,7 +374,7 @@ static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
|
|
#endif
|
|
#endif
|
|
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
|
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
|
|
|
|
|
- return sprintf(buf, "0x%016llx\n", tm);
|
|
|
|
|
|
+ return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);
|
|
}
|
|
}
|
|
static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
|
|
static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
|
|
#endif /* HPSB_DEBUG_TLABELS */
|
|
#endif /* HPSB_DEBUG_TLABELS */
|
|
@@ -374,11 +386,11 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute
|
|
int state = simple_strtoul(buf, NULL, 10);
|
|
int state = simple_strtoul(buf, NULL, 10);
|
|
|
|
|
|
if (state == 1) {
|
|
if (state == 1) {
|
|
- down_write(&dev->bus->subsys.rwsem);
|
|
|
|
- device_release_driver(dev);
|
|
|
|
ud->ignore_driver = 1;
|
|
ud->ignore_driver = 1;
|
|
- up_write(&dev->bus->subsys.rwsem);
|
|
|
|
- } else if (!state)
|
|
|
|
|
|
+ down_write(&ieee1394_bus_type.subsys.rwsem);
|
|
|
|
+ device_release_driver(dev);
|
|
|
|
+ up_write(&ieee1394_bus_type.subsys.rwsem);
|
|
|
|
+ } else if (state == 0)
|
|
ud->ignore_driver = 0;
|
|
ud->ignore_driver = 0;
|
|
|
|
|
|
return count;
|
|
return count;
|
|
@@ -413,11 +425,14 @@ static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf)
|
|
static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node);
|
|
static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node);
|
|
|
|
|
|
|
|
|
|
-static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count)
|
|
|
|
|
|
+static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,
|
|
|
|
+ size_t count)
|
|
{
|
|
{
|
|
|
|
+ int error = 0;
|
|
|
|
+
|
|
if (simple_strtoul(buf, NULL, 10) == 1)
|
|
if (simple_strtoul(buf, NULL, 10) == 1)
|
|
- bus_rescan_devices(&ieee1394_bus_type);
|
|
|
|
- return count;
|
|
|
|
|
|
+ error = bus_rescan_devices(&ieee1394_bus_type);
|
|
|
|
+ return error ? error : count;
|
|
}
|
|
}
|
|
static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
|
|
static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
|
|
{
|
|
{
|
|
@@ -433,7 +448,7 @@ static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size
|
|
|
|
|
|
if (state == 1)
|
|
if (state == 1)
|
|
ignore_drivers = 1;
|
|
ignore_drivers = 1;
|
|
- else if (!state)
|
|
|
|
|
|
+ else if (state == 0)
|
|
ignore_drivers = 0;
|
|
ignore_drivers = 0;
|
|
|
|
|
|
return count;
|
|
return count;
|
|
@@ -526,7 +541,7 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
|
|
int length = 0;
|
|
int length = 0;
|
|
char *scratch = buf;
|
|
char *scratch = buf;
|
|
|
|
|
|
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
|
|
|
|
|
|
+ driver = container_of(drv, struct hpsb_protocol_driver, driver);
|
|
|
|
|
|
for (id = driver->id_table; id->match_flags != 0; id++) {
|
|
for (id = driver->id_table; id->match_flags != 0; id++) {
|
|
int need_coma = 0;
|
|
int need_coma = 0;
|
|
@@ -583,7 +598,11 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
|
|
for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
|
|
- driver_create_file(drv, fw_drv_attrs[i]);
|
|
|
|
|
|
+ if (driver_create_file(drv, fw_drv_attrs[i]))
|
|
|
|
+ goto fail;
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -603,7 +622,12 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne)
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
|
|
for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
|
|
- device_create_file(dev, fw_ne_attrs[i]);
|
|
|
|
|
|
+ if (device_create_file(dev, fw_ne_attrs[i]))
|
|
|
|
+ goto fail;
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
|
|
|
|
+ (unsigned long long)ne->guid);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -613,11 +637,16 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host)
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
|
|
for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
|
|
- device_create_file(dev, fw_host_attrs[i]);
|
|
|
|
|
|
+ if (device_create_file(dev, fw_host_attrs[i]))
|
|
|
|
+ goto fail;
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to add sysfs attribute for host %d", host->id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid);
|
|
|
|
|
|
+static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
|
|
|
|
+ nodeid_t nodeid);
|
|
|
|
|
|
static void nodemgr_update_host_dev_links(struct hpsb_host *host)
|
|
static void nodemgr_update_host_dev_links(struct hpsb_host *host)
|
|
{
|
|
{
|
|
@@ -628,12 +657,18 @@ static void nodemgr_update_host_dev_links(struct hpsb_host *host)
|
|
sysfs_remove_link(&dev->kobj, "busmgr_id");
|
|
sysfs_remove_link(&dev->kobj, "busmgr_id");
|
|
sysfs_remove_link(&dev->kobj, "host_id");
|
|
sysfs_remove_link(&dev->kobj, "host_id");
|
|
|
|
|
|
- if ((ne = find_entry_by_nodeid(host, host->irm_id)))
|
|
|
|
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id");
|
|
|
|
- if ((ne = find_entry_by_nodeid(host, host->busmgr_id)))
|
|
|
|
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id");
|
|
|
|
- if ((ne = find_entry_by_nodeid(host, host->node_id)))
|
|
|
|
- sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id");
|
|
|
|
|
|
+ if ((ne = find_entry_by_nodeid(host, host->irm_id)) &&
|
|
|
|
+ sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"))
|
|
|
|
+ goto fail;
|
|
|
|
+ if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) &&
|
|
|
|
+ sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"))
|
|
|
|
+ goto fail;
|
|
|
|
+ if ((ne = find_entry_by_nodeid(host, host->node_id)) &&
|
|
|
|
+ sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id"))
|
|
|
|
+ goto fail;
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to update sysfs attributes for host %d", host->id);
|
|
}
|
|
}
|
|
|
|
|
|
static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
|
|
static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
|
|
@@ -642,32 +677,39 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
|
|
int i;
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
|
|
for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
|
|
- device_create_file(dev, fw_ud_attrs[i]);
|
|
|
|
-
|
|
|
|
|
|
+ if (device_create_file(dev, fw_ud_attrs[i]))
|
|
|
|
+ goto fail;
|
|
if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
|
|
if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
|
|
- device_create_file(dev, &dev_attr_ud_specifier_id);
|
|
|
|
-
|
|
|
|
|
|
+ if (device_create_file(dev, &dev_attr_ud_specifier_id))
|
|
|
|
+ goto fail;
|
|
if (ud->flags & UNIT_DIRECTORY_VERSION)
|
|
if (ud->flags & UNIT_DIRECTORY_VERSION)
|
|
- device_create_file(dev, &dev_attr_ud_version);
|
|
|
|
-
|
|
|
|
|
|
+ if (device_create_file(dev, &dev_attr_ud_version))
|
|
|
|
+ goto fail;
|
|
if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
|
|
if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
|
|
- device_create_file(dev, &dev_attr_ud_vendor_id);
|
|
|
|
- if (ud->vendor_name_kv)
|
|
|
|
- device_create_file(dev, &dev_attr_ud_vendor_name_kv);
|
|
|
|
|
|
+ if (device_create_file(dev, &dev_attr_ud_vendor_id))
|
|
|
|
+ goto fail;
|
|
|
|
+ if (ud->vendor_name_kv &&
|
|
|
|
+ device_create_file(dev, &dev_attr_ud_vendor_name_kv))
|
|
|
|
+ goto fail;
|
|
}
|
|
}
|
|
-
|
|
|
|
if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
|
|
if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
|
|
- device_create_file(dev, &dev_attr_ud_model_id);
|
|
|
|
- if (ud->model_name_kv)
|
|
|
|
- device_create_file(dev, &dev_attr_ud_model_name_kv);
|
|
|
|
|
|
+ if (device_create_file(dev, &dev_attr_ud_model_id))
|
|
|
|
+ goto fail;
|
|
|
|
+ if (ud->model_name_kv &&
|
|
|
|
+ device_create_file(dev, &dev_attr_ud_model_name_kv))
|
|
|
|
+ goto fail;
|
|
}
|
|
}
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to add sysfs attributes for unit %s",
|
|
|
|
+ ud->device.bus_id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
|
|
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
|
|
{
|
|
{
|
|
- struct hpsb_protocol_driver *driver;
|
|
|
|
- struct unit_directory *ud;
|
|
|
|
|
|
+ struct hpsb_protocol_driver *driver;
|
|
|
|
+ struct unit_directory *ud;
|
|
struct ieee1394_device_id *id;
|
|
struct ieee1394_device_id *id;
|
|
|
|
|
|
/* We only match unit directories */
|
|
/* We only match unit directories */
|
|
@@ -675,55 +717,77 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
ud = container_of(dev, struct unit_directory, device);
|
|
ud = container_of(dev, struct unit_directory, device);
|
|
- driver = container_of(drv, struct hpsb_protocol_driver, driver);
|
|
|
|
-
|
|
|
|
if (ud->ne->in_limbo || ud->ignore_driver)
|
|
if (ud->ne->in_limbo || ud->ignore_driver)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- for (id = driver->id_table; id->match_flags != 0; id++) {
|
|
|
|
- if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
|
|
|
|
- id->vendor_id != ud->vendor_id)
|
|
|
|
- continue;
|
|
|
|
|
|
+ /* We only match drivers of type hpsb_protocol_driver */
|
|
|
|
+ if (drv == &nodemgr_mid_layer_driver)
|
|
|
|
+ return 0;
|
|
|
|
|
|
- if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
|
|
|
|
- id->model_id != ud->model_id)
|
|
|
|
- continue;
|
|
|
|
|
|
+ driver = container_of(drv, struct hpsb_protocol_driver, driver);
|
|
|
|
+ for (id = driver->id_table; id->match_flags != 0; id++) {
|
|
|
|
+ if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
|
|
|
|
+ id->vendor_id != ud->vendor_id)
|
|
|
|
+ continue;
|
|
|
|
|
|
- if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
|
|
|
|
- id->specifier_id != ud->specifier_id)
|
|
|
|
- continue;
|
|
|
|
|
|
+ if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
|
|
|
|
+ id->model_id != ud->model_id)
|
|
|
|
+ continue;
|
|
|
|
|
|
- if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
|
|
|
|
- id->version != ud->version)
|
|
|
|
- continue;
|
|
|
|
|
|
+ if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
|
|
|
|
+ id->specifier_id != ud->specifier_id)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
|
|
|
|
+ id->version != ud->version)
|
|
|
|
+ continue;
|
|
|
|
|
|
return 1;
|
|
return 1;
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
|
|
|
|
+
|
|
static void nodemgr_remove_uds(struct node_entry *ne)
|
|
static void nodemgr_remove_uds(struct node_entry *ne)
|
|
{
|
|
{
|
|
- struct class_device *cdev, *next;
|
|
|
|
- struct unit_directory *ud;
|
|
|
|
-
|
|
|
|
- list_for_each_entry_safe(cdev, next, &nodemgr_ud_class.children, node) {
|
|
|
|
- ud = container_of(cdev, struct unit_directory, class_dev);
|
|
|
|
-
|
|
|
|
- if (ud->ne != ne)
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
|
|
+ struct class_device *cdev;
|
|
|
|
+ struct unit_directory *tmp, *ud;
|
|
|
|
+
|
|
|
|
+ /* Iteration over nodemgr_ud_class.children has to be protected by
|
|
|
|
+ * nodemgr_ud_class.sem, but class_device_unregister() will eventually
|
|
|
|
+ * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
|
|
|
|
+ * release the semaphore, and then unregister the ud. Since this code
|
|
|
|
+ * may be called from other contexts besides the knodemgrds, protect the
|
|
|
|
+ * gap after release of the semaphore by nodemgr_serialize_remove_uds.
|
|
|
|
+ */
|
|
|
|
+ mutex_lock(&nodemgr_serialize_remove_uds);
|
|
|
|
+ for (;;) {
|
|
|
|
+ ud = NULL;
|
|
|
|
+ down(&nodemgr_ud_class.sem);
|
|
|
|
+ list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
|
|
+ tmp = container_of(cdev, struct unit_directory,
|
|
|
|
+ class_dev);
|
|
|
|
+ if (tmp->ne == ne) {
|
|
|
|
+ ud = tmp;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ up(&nodemgr_ud_class.sem);
|
|
|
|
+ if (ud == NULL)
|
|
|
|
+ break;
|
|
class_device_unregister(&ud->class_dev);
|
|
class_device_unregister(&ud->class_dev);
|
|
device_unregister(&ud->device);
|
|
device_unregister(&ud->device);
|
|
}
|
|
}
|
|
|
|
+ mutex_unlock(&nodemgr_serialize_remove_uds);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static void nodemgr_remove_ne(struct node_entry *ne)
|
|
static void nodemgr_remove_ne(struct node_entry *ne)
|
|
{
|
|
{
|
|
- struct device *dev = &ne->device;
|
|
|
|
|
|
+ struct device *dev;
|
|
|
|
|
|
dev = get_device(&ne->device);
|
|
dev = get_device(&ne->device);
|
|
if (!dev)
|
|
if (!dev)
|
|
@@ -748,7 +812,7 @@ static int __nodemgr_remove_host_dev(struct device *dev, void *data)
|
|
|
|
|
|
static void nodemgr_remove_host_dev(struct device *dev)
|
|
static void nodemgr_remove_host_dev(struct device *dev)
|
|
{
|
|
{
|
|
- device_for_each_child(dev, NULL, __nodemgr_remove_host_dev);
|
|
|
|
|
|
+ WARN_ON(device_for_each_child(dev, NULL, __nodemgr_remove_host_dev));
|
|
sysfs_remove_link(&dev->kobj, "irm_id");
|
|
sysfs_remove_link(&dev->kobj, "irm_id");
|
|
sysfs_remove_link(&dev->kobj, "busmgr_id");
|
|
sysfs_remove_link(&dev->kobj, "busmgr_id");
|
|
sysfs_remove_link(&dev->kobj, "host_id");
|
|
sysfs_remove_link(&dev->kobj, "host_id");
|
|
@@ -762,16 +826,16 @@ static void nodemgr_update_bus_options(struct node_entry *ne)
|
|
#endif
|
|
#endif
|
|
quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
|
|
quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
|
|
|
|
|
|
- ne->busopt.irmc = (busoptions >> 31) & 1;
|
|
|
|
- ne->busopt.cmc = (busoptions >> 30) & 1;
|
|
|
|
- ne->busopt.isc = (busoptions >> 29) & 1;
|
|
|
|
- ne->busopt.bmc = (busoptions >> 28) & 1;
|
|
|
|
- ne->busopt.pmc = (busoptions >> 27) & 1;
|
|
|
|
- ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff;
|
|
|
|
- ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1);
|
|
|
|
|
|
+ ne->busopt.irmc = (busoptions >> 31) & 1;
|
|
|
|
+ ne->busopt.cmc = (busoptions >> 30) & 1;
|
|
|
|
+ ne->busopt.isc = (busoptions >> 29) & 1;
|
|
|
|
+ ne->busopt.bmc = (busoptions >> 28) & 1;
|
|
|
|
+ ne->busopt.pmc = (busoptions >> 27) & 1;
|
|
|
|
+ ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff;
|
|
|
|
+ ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1);
|
|
ne->busopt.max_rom = (busoptions >> 8) & 0x3;
|
|
ne->busopt.max_rom = (busoptions >> 8) & 0x3;
|
|
- ne->busopt.generation = (busoptions >> 4) & 0xf;
|
|
|
|
- ne->busopt.lnkspd = busoptions & 0x7;
|
|
|
|
|
|
+ ne->busopt.generation = (busoptions >> 4) & 0xf;
|
|
|
|
+ ne->busopt.lnkspd = busoptions & 0x7;
|
|
|
|
|
|
HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
|
|
HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
|
|
"cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
|
|
"cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
|
|
@@ -792,7 +856,7 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
|
|
|
|
|
|
ne = kzalloc(sizeof(*ne), GFP_KERNEL);
|
|
ne = kzalloc(sizeof(*ne), GFP_KERNEL);
|
|
if (!ne)
|
|
if (!ne)
|
|
- return NULL;
|
|
|
|
|
|
+ goto fail_alloc;
|
|
|
|
|
|
ne->host = host;
|
|
ne->host = host;
|
|
ne->nodeid = nodeid;
|
|
ne->nodeid = nodeid;
|
|
@@ -815,12 +879,15 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
|
|
snprintf(ne->class_dev.class_id, BUS_ID_SIZE, "%016Lx",
|
|
snprintf(ne->class_dev.class_id, BUS_ID_SIZE, "%016Lx",
|
|
(unsigned long long)(ne->guid));
|
|
(unsigned long long)(ne->guid));
|
|
|
|
|
|
- device_register(&ne->device);
|
|
|
|
- class_device_register(&ne->class_dev);
|
|
|
|
|
|
+ if (device_register(&ne->device))
|
|
|
|
+ goto fail_devreg;
|
|
|
|
+ if (class_device_register(&ne->class_dev))
|
|
|
|
+ goto fail_classdevreg;
|
|
get_device(&ne->device);
|
|
get_device(&ne->device);
|
|
|
|
|
|
- if (ne->guid_vendor_oui)
|
|
|
|
- device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui);
|
|
|
|
|
|
+ if (ne->guid_vendor_oui &&
|
|
|
|
+ device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui))
|
|
|
|
+ goto fail_addoiu;
|
|
nodemgr_create_ne_dev_files(ne);
|
|
nodemgr_create_ne_dev_files(ne);
|
|
|
|
|
|
nodemgr_update_bus_options(ne);
|
|
nodemgr_update_bus_options(ne);
|
|
@@ -830,17 +897,28 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
|
|
NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
|
|
NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
|
|
|
|
|
|
return ne;
|
|
return ne;
|
|
|
|
+
|
|
|
|
+fail_addoiu:
|
|
|
|
+ put_device(&ne->device);
|
|
|
|
+fail_classdevreg:
|
|
|
|
+ device_unregister(&ne->device);
|
|
|
|
+fail_devreg:
|
|
|
|
+ kfree(ne);
|
|
|
|
+fail_alloc:
|
|
|
|
+ HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
|
|
|
|
+ NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
|
|
|
|
+
|
|
|
|
+ return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct node_entry *find_entry_by_guid(u64 guid)
|
|
static struct node_entry *find_entry_by_guid(u64 guid)
|
|
{
|
|
{
|
|
- struct class *class = &nodemgr_ne_class;
|
|
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
struct node_entry *ne, *ret_ne = NULL;
|
|
struct node_entry *ne, *ret_ne = NULL;
|
|
|
|
|
|
- down_read(&class->subsys.rwsem);
|
|
|
|
- list_for_each_entry(cdev, &class->children, node) {
|
|
|
|
|
|
+ down(&nodemgr_ne_class.sem);
|
|
|
|
+ list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
|
|
|
|
if (ne->guid == guid) {
|
|
if (ne->guid == guid) {
|
|
@@ -848,20 +926,20 @@ static struct node_entry *find_entry_by_guid(u64 guid)
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- up_read(&class->subsys.rwsem);
|
|
|
|
|
|
+ up(&nodemgr_ne_class.sem);
|
|
|
|
|
|
- return ret_ne;
|
|
|
|
|
|
+ return ret_ne;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid)
|
|
|
|
|
|
+static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
|
|
|
|
+ nodeid_t nodeid)
|
|
{
|
|
{
|
|
- struct class *class = &nodemgr_ne_class;
|
|
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
struct node_entry *ne, *ret_ne = NULL;
|
|
struct node_entry *ne, *ret_ne = NULL;
|
|
|
|
|
|
- down_read(&class->subsys.rwsem);
|
|
|
|
- list_for_each_entry(cdev, &class->children, node) {
|
|
|
|
|
|
+ down(&nodemgr_ne_class.sem);
|
|
|
|
+ list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
|
|
|
|
if (ne->host == host && ne->nodeid == nodeid) {
|
|
if (ne->host == host && ne->nodeid == nodeid) {
|
|
@@ -869,7 +947,7 @@ static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- up_read(&class->subsys.rwsem);
|
|
|
|
|
|
+ up(&nodemgr_ne_class.sem);
|
|
|
|
|
|
return ret_ne;
|
|
return ret_ne;
|
|
}
|
|
}
|
|
@@ -891,13 +969,25 @@ static void nodemgr_register_device(struct node_entry *ne,
|
|
snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
|
|
snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
|
|
ne->device.bus_id, ud->id);
|
|
ne->device.bus_id, ud->id);
|
|
|
|
|
|
- device_register(&ud->device);
|
|
|
|
- class_device_register(&ud->class_dev);
|
|
|
|
|
|
+ if (device_register(&ud->device))
|
|
|
|
+ goto fail_devreg;
|
|
|
|
+ if (class_device_register(&ud->class_dev))
|
|
|
|
+ goto fail_classdevreg;
|
|
get_device(&ud->device);
|
|
get_device(&ud->device);
|
|
|
|
|
|
- if (ud->vendor_oui)
|
|
|
|
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
|
|
|
|
|
|
+ if (ud->vendor_oui &&
|
|
|
|
+ device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
|
|
|
|
+ goto fail_addoui;
|
|
nodemgr_create_ud_dev_files(ud);
|
|
nodemgr_create_ud_dev_files(ud);
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+fail_addoui:
|
|
|
|
+ put_device(&ud->device);
|
|
|
|
+fail_classdevreg:
|
|
|
|
+ device_unregister(&ud->device);
|
|
|
|
+fail_devreg:
|
|
|
|
+ HPSB_ERR("Failed to create unit %s", ud->device.bus_id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -977,10 +1067,9 @@ static struct unit_directory *nodemgr_process_unit_directory
|
|
/* Logical Unit Number */
|
|
/* Logical Unit Number */
|
|
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
|
|
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
|
|
if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
|
|
if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
|
|
- ud_child = kmalloc(sizeof(*ud_child), GFP_KERNEL);
|
|
|
|
|
|
+ ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL);
|
|
if (!ud_child)
|
|
if (!ud_child)
|
|
goto unit_directory_error;
|
|
goto unit_directory_error;
|
|
- memcpy(ud_child, ud, sizeof(*ud_child));
|
|
|
|
nodemgr_register_device(ne, ud_child, &ne->device);
|
|
nodemgr_register_device(ne, ud_child, &ne->device);
|
|
ud_child = NULL;
|
|
ud_child = NULL;
|
|
|
|
|
|
@@ -1094,10 +1183,16 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
|
|
last_key_id = kv->key.id;
|
|
last_key_id = kv->key.id;
|
|
}
|
|
}
|
|
|
|
|
|
- if (ne->vendor_oui)
|
|
|
|
- device_create_file(&ne->device, &dev_attr_ne_vendor_oui);
|
|
|
|
- if (ne->vendor_name_kv)
|
|
|
|
- device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv);
|
|
|
|
|
|
+ if (ne->vendor_oui &&
|
|
|
|
+ device_create_file(&ne->device, &dev_attr_ne_vendor_oui))
|
|
|
|
+ goto fail;
|
|
|
|
+ if (ne->vendor_name_kv &&
|
|
|
|
+ device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
|
|
|
|
+ goto fail;
|
|
|
|
+ return;
|
|
|
|
+fail:
|
|
|
|
+ HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
|
|
|
|
+ (unsigned long long)ne->guid);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG
|
|
#ifdef CONFIG_HOTPLUG
|
|
@@ -1161,16 +1256,20 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
|
|
#endif /* CONFIG_HOTPLUG */
|
|
#endif /* CONFIG_HOTPLUG */
|
|
|
|
|
|
|
|
|
|
-int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
|
|
|
|
|
|
+int __hpsb_register_protocol(struct hpsb_protocol_driver *drv,
|
|
|
|
+ struct module *owner)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
|
|
+ int error;
|
|
|
|
|
|
- /* This will cause a probe for devices */
|
|
|
|
- ret = driver_register(&driver->driver);
|
|
|
|
- if (!ret)
|
|
|
|
- nodemgr_create_drv_files(driver);
|
|
|
|
|
|
+ drv->driver.bus = &ieee1394_bus_type;
|
|
|
|
+ drv->driver.owner = owner;
|
|
|
|
+ drv->driver.name = drv->name;
|
|
|
|
|
|
- return ret;
|
|
|
|
|
|
+ /* This will cause a probe for devices */
|
|
|
|
+ error = driver_register(&drv->driver);
|
|
|
|
+ if (!error)
|
|
|
|
+ nodemgr_create_drv_files(drv);
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
|
|
|
|
void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
|
|
void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
|
|
@@ -1298,26 +1397,25 @@ static void nodemgr_node_scan_one(struct host_info *hi,
|
|
|
|
|
|
static void nodemgr_node_scan(struct host_info *hi, int generation)
|
|
static void nodemgr_node_scan(struct host_info *hi, int generation)
|
|
{
|
|
{
|
|
- int count;
|
|
|
|
- struct hpsb_host *host = hi->host;
|
|
|
|
- struct selfid *sid = (struct selfid *)host->topology_map;
|
|
|
|
- nodeid_t nodeid = LOCAL_BUS;
|
|
|
|
|
|
+ int count;
|
|
|
|
+ struct hpsb_host *host = hi->host;
|
|
|
|
+ struct selfid *sid = (struct selfid *)host->topology_map;
|
|
|
|
+ nodeid_t nodeid = LOCAL_BUS;
|
|
|
|
|
|
- /* Scan each node on the bus */
|
|
|
|
- for (count = host->selfid_count; count; count--, sid++) {
|
|
|
|
- if (sid->extended)
|
|
|
|
- continue;
|
|
|
|
|
|
+ /* Scan each node on the bus */
|
|
|
|
+ for (count = host->selfid_count; count; count--, sid++) {
|
|
|
|
+ if (sid->extended)
|
|
|
|
+ continue;
|
|
|
|
|
|
- if (!sid->link_active) {
|
|
|
|
- nodeid++;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- nodemgr_node_scan_one(hi, nodeid++, generation);
|
|
|
|
- }
|
|
|
|
|
|
+ if (!sid->link_active) {
|
|
|
|
+ nodeid++;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ nodemgr_node_scan_one(hi, nodeid++, generation);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
|
|
|
|
static void nodemgr_suspend_ne(struct node_entry *ne)
|
|
static void nodemgr_suspend_ne(struct node_entry *ne)
|
|
{
|
|
{
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
@@ -1327,21 +1425,22 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
|
|
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
|
|
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
|
|
|
|
|
|
ne->in_limbo = 1;
|
|
ne->in_limbo = 1;
|
|
- device_create_file(&ne->device, &dev_attr_ne_in_limbo);
|
|
|
|
|
|
+ WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
|
|
|
|
|
|
- down_write(&ne->device.bus->subsys.rwsem);
|
|
|
|
|
|
+ down(&nodemgr_ud_class.sem);
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
-
|
|
|
|
if (ud->ne != ne)
|
|
if (ud->ne != ne)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ down_write(&ieee1394_bus_type.subsys.rwsem);
|
|
if (ud->device.driver &&
|
|
if (ud->device.driver &&
|
|
(!ud->device.driver->suspend ||
|
|
(!ud->device.driver->suspend ||
|
|
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
|
|
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
|
|
device_release_driver(&ud->device);
|
|
device_release_driver(&ud->device);
|
|
|
|
+ up_write(&ieee1394_bus_type.subsys.rwsem);
|
|
}
|
|
}
|
|
- up_write(&ne->device.bus->subsys.rwsem);
|
|
|
|
|
|
+ up(&nodemgr_ud_class.sem);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1353,45 +1452,47 @@ static void nodemgr_resume_ne(struct node_entry *ne)
|
|
ne->in_limbo = 0;
|
|
ne->in_limbo = 0;
|
|
device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
|
|
device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
|
|
|
|
|
|
- down_read(&nodemgr_ud_class.subsys.rwsem);
|
|
|
|
- down_read(&ne->device.bus->subsys.rwsem);
|
|
|
|
|
|
+ down(&nodemgr_ud_class.sem);
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
-
|
|
|
|
if (ud->ne != ne)
|
|
if (ud->ne != ne)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ down_read(&ieee1394_bus_type.subsys.rwsem);
|
|
if (ud->device.driver && ud->device.driver->resume)
|
|
if (ud->device.driver && ud->device.driver->resume)
|
|
ud->device.driver->resume(&ud->device);
|
|
ud->device.driver->resume(&ud->device);
|
|
|
|
+ up_read(&ieee1394_bus_type.subsys.rwsem);
|
|
}
|
|
}
|
|
- up_read(&ne->device.bus->subsys.rwsem);
|
|
|
|
- up_read(&nodemgr_ud_class.subsys.rwsem);
|
|
|
|
|
|
+ up(&nodemgr_ud_class.sem);
|
|
|
|
|
|
HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
|
|
HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
|
|
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
|
|
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
|
|
|
|
static void nodemgr_update_pdrv(struct node_entry *ne)
|
|
static void nodemgr_update_pdrv(struct node_entry *ne)
|
|
{
|
|
{
|
|
struct unit_directory *ud;
|
|
struct unit_directory *ud;
|
|
struct hpsb_protocol_driver *pdrv;
|
|
struct hpsb_protocol_driver *pdrv;
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
|
|
|
|
|
|
+ down(&nodemgr_ud_class.sem);
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
ud = container_of(cdev, struct unit_directory, class_dev);
|
|
- if (ud->ne != ne || !ud->device.driver)
|
|
|
|
|
|
+ if (ud->ne != ne)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- pdrv = container_of(ud->device.driver, struct hpsb_protocol_driver, driver);
|
|
|
|
-
|
|
|
|
- if (pdrv->update && pdrv->update(ud)) {
|
|
|
|
- down_write(&ud->device.bus->subsys.rwsem);
|
|
|
|
- device_release_driver(&ud->device);
|
|
|
|
- up_write(&ud->device.bus->subsys.rwsem);
|
|
|
|
|
|
+ down_write(&ieee1394_bus_type.subsys.rwsem);
|
|
|
|
+ if (ud->device.driver) {
|
|
|
|
+ pdrv = container_of(ud->device.driver,
|
|
|
|
+ struct hpsb_protocol_driver,
|
|
|
|
+ driver);
|
|
|
|
+ if (pdrv->update && pdrv->update(ud))
|
|
|
|
+ device_release_driver(&ud->device);
|
|
}
|
|
}
|
|
|
|
+ up_write(&ieee1394_bus_type.subsys.rwsem);
|
|
}
|
|
}
|
|
|
|
+ up(&nodemgr_ud_class.sem);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1405,7 +1506,7 @@ static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
|
|
{
|
|
{
|
|
const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
|
|
const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
|
|
quadlet_t bc_remote, bc_local;
|
|
quadlet_t bc_remote, bc_local;
|
|
- int ret;
|
|
|
|
|
|
+ int error;
|
|
|
|
|
|
if (!ne->host->is_irm || ne->generation != generation ||
|
|
if (!ne->host->is_irm || ne->generation != generation ||
|
|
ne->nodeid == ne->host->node_id)
|
|
ne->nodeid == ne->host->node_id)
|
|
@@ -1414,16 +1515,14 @@ static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
|
|
bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
|
|
bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
|
|
|
|
|
|
/* Check if the register is implemented and 1394a compliant. */
|
|
/* Check if the register is implemented and 1394a compliant. */
|
|
- ret = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
|
|
|
|
- sizeof(bc_remote));
|
|
|
|
- if (!ret && bc_remote & cpu_to_be32(0x80000000) &&
|
|
|
|
|
|
+ error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
|
|
|
|
+ sizeof(bc_remote));
|
|
|
|
+ if (!error && bc_remote & cpu_to_be32(0x80000000) &&
|
|
bc_remote != bc_local)
|
|
bc_remote != bc_local)
|
|
hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
|
|
hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader because the
|
|
|
|
- * calls to nodemgr_update_pdrv() and nodemgr_suspend_ne() here require it. */
|
|
|
|
static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
|
|
static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
|
|
{
|
|
{
|
|
struct device *dev;
|
|
struct device *dev;
|
|
@@ -1456,7 +1555,6 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
|
|
static void nodemgr_node_probe(struct host_info *hi, int generation)
|
|
static void nodemgr_node_probe(struct host_info *hi, int generation)
|
|
{
|
|
{
|
|
struct hpsb_host *host = hi->host;
|
|
struct hpsb_host *host = hi->host;
|
|
- struct class *class = &nodemgr_ne_class;
|
|
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
struct node_entry *ne;
|
|
struct node_entry *ne;
|
|
|
|
|
|
@@ -1469,18 +1567,18 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
|
|
* while probes are time-consuming. (Well, those probes need some
|
|
* while probes are time-consuming. (Well, those probes need some
|
|
* improvement...) */
|
|
* improvement...) */
|
|
|
|
|
|
- down_read(&class->subsys.rwsem);
|
|
|
|
- list_for_each_entry(cdev, &class->children, node) {
|
|
|
|
|
|
+ down(&nodemgr_ne_class.sem);
|
|
|
|
+ list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
if (!ne->needs_probe)
|
|
if (!ne->needs_probe)
|
|
nodemgr_probe_ne(hi, ne, generation);
|
|
nodemgr_probe_ne(hi, ne, generation);
|
|
}
|
|
}
|
|
- list_for_each_entry(cdev, &class->children, node) {
|
|
|
|
|
|
+ list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
ne = container_of(cdev, struct node_entry, class_dev);
|
|
if (ne->needs_probe)
|
|
if (ne->needs_probe)
|
|
nodemgr_probe_ne(hi, ne, generation);
|
|
nodemgr_probe_ne(hi, ne, generation);
|
|
}
|
|
}
|
|
- up_read(&class->subsys.rwsem);
|
|
|
|
|
|
+ up(&nodemgr_ne_class.sem);
|
|
|
|
|
|
|
|
|
|
/* If we had a bus reset while we were scanning the bus, it is
|
|
/* If we had a bus reset while we were scanning the bus, it is
|
|
@@ -1498,15 +1596,14 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
|
|
* just removed. */
|
|
* just removed. */
|
|
|
|
|
|
if (generation == get_hpsb_generation(host))
|
|
if (generation == get_hpsb_generation(host))
|
|
- bus_rescan_devices(&ieee1394_bus_type);
|
|
|
|
-
|
|
|
|
- return;
|
|
|
|
|
|
+ if (bus_rescan_devices(&ieee1394_bus_type))
|
|
|
|
+ HPSB_DEBUG("bus_rescan_devices had an error");
|
|
}
|
|
}
|
|
|
|
|
|
static int nodemgr_send_resume_packet(struct hpsb_host *host)
|
|
static int nodemgr_send_resume_packet(struct hpsb_host *host)
|
|
{
|
|
{
|
|
struct hpsb_packet *packet;
|
|
struct hpsb_packet *packet;
|
|
- int ret = 1;
|
|
|
|
|
|
+ int error = -ENOMEM;
|
|
|
|
|
|
packet = hpsb_make_phypacket(host,
|
|
packet = hpsb_make_phypacket(host,
|
|
EXTPHYPACKET_TYPE_RESUME |
|
|
EXTPHYPACKET_TYPE_RESUME |
|
|
@@ -1514,12 +1611,12 @@ static int nodemgr_send_resume_packet(struct hpsb_host *host)
|
|
if (packet) {
|
|
if (packet) {
|
|
packet->no_waiter = 1;
|
|
packet->no_waiter = 1;
|
|
packet->generation = get_hpsb_generation(host);
|
|
packet->generation = get_hpsb_generation(host);
|
|
- ret = hpsb_send_packet(packet);
|
|
|
|
|
|
+ error = hpsb_send_packet(packet);
|
|
}
|
|
}
|
|
- if (ret)
|
|
|
|
|
|
+ if (error)
|
|
HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
|
|
HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
|
|
host->id);
|
|
host->id);
|
|
- return ret;
|
|
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
|
|
|
|
/* Perform a few high-level IRM responsibilities. */
|
|
/* Perform a few high-level IRM responsibilities. */
|
|
@@ -1692,19 +1789,18 @@ exit:
|
|
|
|
|
|
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
|
|
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
|
|
{
|
|
{
|
|
- struct class *class = &hpsb_host_class;
|
|
|
|
struct class_device *cdev;
|
|
struct class_device *cdev;
|
|
struct hpsb_host *host;
|
|
struct hpsb_host *host;
|
|
int error = 0;
|
|
int error = 0;
|
|
|
|
|
|
- down_read(&class->subsys.rwsem);
|
|
|
|
- list_for_each_entry(cdev, &class->children, node) {
|
|
|
|
|
|
+ down(&hpsb_host_class.sem);
|
|
|
|
+ list_for_each_entry(cdev, &hpsb_host_class.children, node) {
|
|
host = container_of(cdev, struct hpsb_host, class_dev);
|
|
host = container_of(cdev, struct hpsb_host, class_dev);
|
|
|
|
|
|
if ((error = cb(host, __data)))
|
|
if ((error = cb(host, __data)))
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- up_read(&class->subsys.rwsem);
|
|
|
|
|
|
+ up(&hpsb_host_class.sem);
|
|
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
@@ -1726,10 +1822,10 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
|
|
|
|
|
|
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
|
|
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
|
|
{
|
|
{
|
|
- pkt->host = ne->host;
|
|
|
|
- pkt->generation = ne->generation;
|
|
|
|
|
|
+ pkt->host = ne->host;
|
|
|
|
+ pkt->generation = ne->generation;
|
|
barrier();
|
|
barrier();
|
|
- pkt->node_id = ne->nodeid;
|
|
|
|
|
|
+ pkt->node_id = ne->nodeid;
|
|
}
|
|
}
|
|
|
|
|
|
int hpsb_node_write(struct node_entry *ne, u64 addr,
|
|
int hpsb_node_write(struct node_entry *ne, u64 addr,
|
|
@@ -1789,26 +1885,25 @@ static struct hpsb_highlevel nodemgr_highlevel = {
|
|
|
|
|
|
int init_ieee1394_nodemgr(void)
|
|
int init_ieee1394_nodemgr(void)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
|
|
+ int error;
|
|
|
|
|
|
- ret = class_register(&nodemgr_ne_class);
|
|
|
|
- if (ret < 0)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ error = class_register(&nodemgr_ne_class);
|
|
|
|
+ if (error)
|
|
|
|
+ return error;
|
|
|
|
|
|
- ret = class_register(&nodemgr_ud_class);
|
|
|
|
- if (ret < 0) {
|
|
|
|
|
|
+ error = class_register(&nodemgr_ud_class);
|
|
|
|
+ if (error) {
|
|
class_unregister(&nodemgr_ne_class);
|
|
class_unregister(&nodemgr_ne_class);
|
|
- return ret;
|
|
|
|
|
|
+ return error;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+ error = driver_register(&nodemgr_mid_layer_driver);
|
|
hpsb_register_highlevel(&nodemgr_highlevel);
|
|
hpsb_register_highlevel(&nodemgr_highlevel);
|
|
-
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
void cleanup_ieee1394_nodemgr(void)
|
|
void cleanup_ieee1394_nodemgr(void)
|
|
{
|
|
{
|
|
- hpsb_unregister_highlevel(&nodemgr_highlevel);
|
|
|
|
|
|
+ hpsb_unregister_highlevel(&nodemgr_highlevel);
|
|
|
|
|
|
class_unregister(&nodemgr_ud_class);
|
|
class_unregister(&nodemgr_ud_class);
|
|
class_unregister(&nodemgr_ne_class);
|
|
class_unregister(&nodemgr_ne_class);
|