#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/mutex.h>
#include <linux/freezer.h>
#include <asm/atomic.h>
};
-static char *nodemgr_find_oui_name(int oui)
-{
-#ifdef CONFIG_IEEE1394_OUI_DB
- extern struct oui_list_struct {
- int oui;
- char *name;
- } oui_list[];
- int i;
-
- for (i = 0; oui_list[i].name; i++)
- if (oui_list[i].oui == oui)
- return oui_list[i].name;
-#endif
- return NULL;
-}
-
/*
* Correct the speed map entry. This is necessary
* - for nodes with link speed < phy speed,
{
quadlet_t q;
u8 i, *speed, old_speed, good_speed;
- int ret;
+ int error;
speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
old_speed = *speed;
* just finished its initialization. */
for (i = IEEE1394_SPEED_100; i <= old_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;
*buffer = q;
good_speed = i;
return 0;
}
*speed = old_speed;
- return ret;
+ return error;
}
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;
- int i, ret;
+ int i, error;
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;
break;
}
/* The ieee1394_core guessed the node's speed capability from
* the self ID. Check whether a lower speed works. */
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;
}
if (msleep_interruptible(334))
return -EINTR;
}
- return ret;
+ return error;
}
static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
{
- return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3;
+ return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3;
}
static struct csr1212_bus_ops nodemgr_csr_ops = {
.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 = {
.bus = &ieee1394_bus_type,
.release = nodemgr_release_host,
return sprintf(buf, format_string, (type)driver->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, \
};
#endif
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);
#endif /* HPSB_DEBUG_TLABELS */
int state = simple_strtoul(buf, NULL, 10);
if (state == 1) {
- down_write(&dev->bus->subsys.rwsem);
- device_release_driver(dev);
ud->ignore_driver = 1;
- up_write(&dev->bus->subsys.rwsem);
- } else if (!state)
+ device_release_driver(dev);
+ } else if (state == 0)
ud->ignore_driver = 0;
return count;
if (state == 1)
ignore_drivers = 1;
- else if (!state)
+ else if (state == 0)
ignore_drivers = 0;
return count;
fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
fw_attr_td(ne, struct node_entry, vendor_name_kv)
-fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
static struct device_attribute *const fw_ne_attrs[] = {
fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
fw_attr_td(ud, struct unit_directory, model_name_kv)
static struct device_attribute *const fw_ud_attrs[] = {
int length = 0;
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++) {
int need_coma = 0;
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name);
+ HPSB_ERR("Failed to add sysfs attribute");
}
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
- (unsigned long long)ne->guid);
+ HPSB_ERR("Failed to add sysfs attribute");
}
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for host %d", host->id);
+ HPSB_ERR("Failed to add sysfs attribute");
}
}
return;
fail:
- HPSB_ERR("Failed to add sysfs attributes for unit %s",
- ud->device.bus_id);
+ HPSB_ERR("Failed to add sysfs attribute");
}
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;
/* We only match unit directories */
return 0;
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)
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_MODEL_ID) &&
+ id->model_id != ud->model_id)
+ continue;
- if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
- id->specifier_id != ud->specifier_id)
- 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;
+ if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
+ id->version != ud->version)
+ continue;
return 1;
- }
+ }
return 0;
}
+static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
+
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);
device_unregister(&ud->device);
}
+ mutex_unlock(&nodemgr_serialize_remove_uds);
}
static void nodemgr_remove_ne(struct node_entry *ne)
{
- struct device *dev = &ne->device;
+ struct device *dev;
dev = get_device(&ne->device);
if (!dev)
#endif
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.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 "
"cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
ne->guid = guid;
ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
ne->csr = csr;
memcpy(&ne->device, &nodemgr_dev_template_ne,
goto fail_classdevreg;
get_device(&ne->device);
- 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_update_bus_options(ne);
return ne;
-fail_addoiu:
- put_device(&ne->device);
fail_classdevreg:
device_unregister(&ne->device);
fail_devreg:
static struct node_entry *find_entry_by_guid(u64 guid)
{
- struct class *class = &nodemgr_ne_class;
struct class_device *cdev;
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);
if (ne->guid == guid) {
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 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);
if (ne->host == host && ne->nodeid == nodeid) {
break;
}
}
- up_read(&class->subsys.rwsem);
+ up(&nodemgr_ne_class.sem);
return ret_ne;
}
goto fail_classdevreg;
get_device(&ud->device);
- if (ud->vendor_oui &&
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
- goto fail_addoui;
nodemgr_create_ud_dev_files(ud);
return;
-fail_addoui:
- put_device(&ud->device);
fail_classdevreg:
device_unregister(&ud->device);
fail_devreg:
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
ud->vendor_id = kv->value.immediate;
ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
- if (ud->vendor_id)
- ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
}
break;
/* Logical Unit Number */
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
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)
goto unit_directory_error;
- memcpy(ud_child, ud, sizeof(*ud_child));
nodemgr_register_device(ne, ud_child, &ne->device);
ud_child = NULL;
switch (kv->key.id) {
case CSR1212_KV_ID_VENDOR:
ne->vendor_id = kv->value.immediate;
-
- if (ne->vendor_id)
- ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
break;
case CSR1212_KV_ID_NODE_CAPABILITIES:
last_key_id = kv->key.id;
}
- 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);
+ if (ne->vendor_name_kv) {
+ int error = device_create_file(&ne->device,
+ &dev_attr_ne_vendor_name_kv);
+
+ if (error && error != -EEXIST)
+ HPSB_ERR("Failed to add sysfs attribute");
+ }
}
#ifdef CONFIG_HOTPLUG
struct unit_directory *ud;
int i = 0;
int length = 0;
+ int retval = 0;
/* ieee1394:venNmoNspNverN */
char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
#define PUT_ENVP(fmt,val) \
do { \
- int printed; \
- envp[i++] = buffer; \
- printed = snprintf(buffer, buffer_size - length, \
- fmt, val); \
- if ((buffer_size - (length+printed) <= 0) || (i >= num_envp)) \
- return -ENOMEM; \
- length += printed+1; \
- buffer += printed+1; \
+ retval = add_uevent_var(envp, num_envp, &i, \
+ buffer, buffer_size, &length, \
+ fmt, val); \
+ if (retval) \
+ return retval; \
} while (0)
PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
#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 0;
+ /* 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)
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;
-
- /* 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);
- }
+ 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;
+
+ 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)
{
struct class_device *cdev;
ne->in_limbo = 1;
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) {
ud = container_of(cdev, struct unit_directory, class_dev);
-
if (ud->ne != ne)
continue;
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
device_release_driver(&ud->device);
}
- up_write(&ne->device.bus->subsys.rwsem);
+ up(&nodemgr_ud_class.sem);
}
ne->in_limbo = 0;
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) {
ud = container_of(cdev, struct unit_directory, class_dev);
-
if (ud->ne != ne)
continue;
if (ud->device.driver && ud->device.driver->resume)
ud->device.driver->resume(&ud->device);
}
- 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]",
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)
{
struct unit_directory *ud;
struct hpsb_protocol_driver *pdrv;
struct class_device *cdev;
+ down(&nodemgr_ud_class.sem);
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
ud = container_of(cdev, struct unit_directory, class_dev);
- if (ud->ne != ne || !ud->device.driver)
+ if (ud->ne != ne)
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);
+ 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(&nodemgr_ud_class.sem);
}
{
const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
quadlet_t bc_remote, bc_local;
- int ret;
+ int error;
if (!ne->host->is_irm || ne->generation != generation ||
ne->nodeid == ne->host->node_id)
bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
/* 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)
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)
{
struct device *dev;
static void nodemgr_node_probe(struct host_info *hi, int generation)
{
struct hpsb_host *host = hi->host;
- struct class *class = &nodemgr_ne_class;
struct class_device *cdev;
struct node_entry *ne;
* while probes are time-consuming. (Well, those probes need some
* 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);
if (!ne->needs_probe)
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);
if (ne->needs_probe)
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
* just removed. */
if (generation == get_hpsb_generation(host))
- WARN_ON(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)
{
struct hpsb_packet *packet;
- int ret = 1;
+ int error = -ENOMEM;
packet = hpsb_make_phypacket(host,
EXTPHYPACKET_TYPE_RESUME |
if (packet) {
packet->no_waiter = 1;
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",
host->id);
- return ret;
+ return error;
}
/* Perform a few high-level IRM responsibilities. */
for (;;) {
/* Sleep until next bus reset */
set_current_state(TASK_INTERRUPTIBLE);
- if (get_hpsb_generation(host) == generation)
+ if (get_hpsb_generation(host) == generation &&
+ !kthread_should_stop())
schedule();
__set_current_state(TASK_RUNNING);
return 0;
}
-int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
+/**
+ * nodemgr_for_each_host - call a function for each IEEE 1394 host
+ * @data: an address to supply to the callback
+ * @cb: function to call for each host
+ *
+ * Iterate the hosts, calling a given function with supplied data for each host.
+ * If the callback fails on a host, i.e. if it returns a non-zero value, the
+ * iteration is stopped.
+ *
+ * Return value: 0 on success, non-zero on failure (same as returned by last run
+ * of the callback).
+ */
+int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
{
- struct class *class = &hpsb_host_class;
struct class_device *cdev;
struct hpsb_host *host;
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);
- if ((error = cb(host, __data)))
+ if ((error = cb(host, data)))
break;
}
- up_read(&class->subsys.rwsem);
+ up(&hpsb_host_class.sem);
return error;
}
-/* The following four convenience functions use a struct node_entry
+/* The following two convenience functions use a struct node_entry
* for addressing a node on the bus. They are intended for use by any
* process context, not just the nodemgr thread, so we need to be a
* little careful when reading out the node ID and generation. The
* ID's.
*/
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
+/**
+ * hpsb_node_fill_packet - fill some destination information into a packet
+ * @ne: destination node
+ * @packet: packet to fill in
+ *
+ * This will fill in the given, pre-initialised hpsb_packet with the current
+ * information from the node entry (host, node ID, bus generation number).
+ */
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
{
- pkt->host = ne->host;
- pkt->generation = ne->generation;
+ packet->host = ne->host;
+ packet->generation = ne->generation;
barrier();
- pkt->node_id = ne->nodeid;
+ packet->node_id = ne->nodeid;
}
int hpsb_node_write(struct node_entry *ne, u64 addr,
int init_ieee1394_nodemgr(void)
{
- int ret;
+ int error;
- ret = class_register(&nodemgr_ne_class);
- if (ret < 0)
- return ret;
-
- ret = class_register(&nodemgr_ud_class);
- if (ret < 0) {
- class_unregister(&nodemgr_ne_class);
- return ret;
- }
+ error = class_register(&nodemgr_ne_class);
+ if (error)
+ goto fail_ne;
+ error = class_register(&nodemgr_ud_class);
+ if (error)
+ goto fail_ud;
+ error = driver_register(&nodemgr_mid_layer_driver);
+ if (error)
+ goto fail_ml;
+ /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
+ nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
hpsb_register_highlevel(&nodemgr_highlevel);
-
return 0;
+
+fail_ml:
+ class_unregister(&nodemgr_ud_class);
+fail_ud:
+ class_unregister(&nodemgr_ne_class);
+fail_ne:
+ return error;
}
void cleanup_ieee1394_nodemgr(void)
{
- hpsb_unregister_highlevel(&nodemgr_highlevel);
-
+ hpsb_unregister_highlevel(&nodemgr_highlevel);
+ driver_unregister(&nodemgr_mid_layer_driver);
class_unregister(&nodemgr_ud_class);
class_unregister(&nodemgr_ne_class);
}