#include "ieee1394_types.h"
#include "ieee1394.h"
+#include "ieee1394_core.h"
#include "hosts.h"
#include "ieee1394_transactions.h"
#include "highlevel.h"
#include "csr.h"
#include "nodemgr.h"
-static int ignore_drivers = 0;
+static int ignore_drivers;
module_param(ignore_drivers, int, 0444);
MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
int i, ret = 0;
- for (i = 0; i < 3; i++) {
+ for (i = 1; ; i++) {
ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
buffer, length);
- if (!ret)
+ if (!ret || i == 3)
break;
- set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout (HZ/3))
+ if (msleep_interruptible(334))
return -EINTR;
}
};
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+ char *buffer, int buffer_size);
static void nodemgr_resume_ne(struct node_entry *ne);
static void nodemgr_remove_ne(struct node_entry *ne);
static struct node_entry *find_entry_by_guid(u64 guid);
put_device(&container_of((class_dev), struct node_entry, class_dev)->device);
}
-struct class nodemgr_ne_class = {
+static struct class nodemgr_ne_class = {
.name = "ieee1394_node",
.release = ne_cls_release,
};
/* The name here is only so that unit directory hotplug works with old
* style hotplug, which only ever did unit directories anyway. */
-struct class nodemgr_ud_class = {
+static struct class nodemgr_ud_class = {
.name = "ieee1394",
.release = ud_cls_release,
- .hotplug = nodemgr_hotplug,
+ .uevent = nodemgr_uevent,
};
static struct hpsb_highlevel nodemgr_highlevel;
#define fw_attr(class, class_type, field, type, format_string) \
-static ssize_t fw_show_##class##_##field (struct device *dev, char *buf)\
+static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\
{ \
class_type *class; \
class = container_of(dev, class_type, device); \
};
#define fw_attr_td(class, class_type, td_kv) \
-static ssize_t fw_show_##class##_##td_kv (struct device *dev, char *buf)\
+static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\
{ \
int len; \
class_type *class = container_of(dev, class_type, device); \
};
-static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf)
+static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf)
+static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf)
+static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
return sprintf(buf, "%u\n", ne->tpool->allocations);
static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf)
+static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
#if (BITS_PER_LONG <= 32)
static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
-static ssize_t fw_set_ignore_driver(struct device *dev, const char *buf, size_t count)
+static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct unit_directory *ud = container_of(dev, struct unit_directory, device);
int state = simple_strtoul(buf, NULL, 10);
return count;
}
-static ssize_t fw_get_ignore_driver(struct device *dev, char *buf)
+static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf)
{
struct unit_directory *ud = container_of(dev, struct unit_directory, device);
put_device(dev);
}
+static int __nodemgr_remove_host_dev(struct device *dev, void *data)
+{
+ nodemgr_remove_ne(container_of(dev, struct node_entry, device));
+ return 0;
+}
static void nodemgr_remove_host_dev(struct device *dev)
{
- struct device *ne_dev, *next;
-
- list_for_each_entry_safe(ne_dev, next, &dev->children, node)
- nodemgr_remove_ne(container_of(ne_dev, struct node_entry, device));
-
+ device_for_each_child(dev, NULL, __nodemgr_remove_host_dev);
sysfs_remove_link(&dev->kobj, "irm_id");
sysfs_remove_link(&dev->kobj, "busmgr_id");
sysfs_remove_link(&dev->kobj, "host_id");
unsigned int generation)
{
struct hpsb_host *host = hi->host;
- struct node_entry *ne;
-
- ne = kmalloc(sizeof(struct node_entry), GFP_KERNEL);
- if (!ne) return NULL;
+ struct node_entry *ne;
- memset(ne, 0, sizeof(struct node_entry));
+ ne = kzalloc(sizeof(*ne), GFP_KERNEL);
+ if (!ne)
+ return NULL;
ne->tpool = &host->tpool[nodeid & NODE_MASK];
- ne->host = host;
- ne->nodeid = nodeid;
+ ne->host = host;
+ ne->nodeid = nodeid;
ne->generation = generation;
ne->needs_probe = 1;
- ne->guid = guid;
+ 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;
(host->node_id == nodeid) ? "Host" : "Node",
NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
- return ne;
+ return ne;
}
}
+static void nodemgr_register_device(struct node_entry *ne,
+ struct unit_directory *ud, struct device *parent)
+{
+ memcpy(&ud->device, &nodemgr_dev_template_ud,
+ sizeof(ud->device));
+
+ ud->device.parent = parent;
+
+ snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
+ ne->device.bus_id, ud->id);
+
+ ud->class_dev.dev = &ud->device;
+ ud->class_dev.class = &nodemgr_ud_class;
+ snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
+ ne->device.bus_id, ud->id);
+
+ device_register(&ud->device);
+ class_device_register(&ud->class_dev);
+ get_device(&ud->device);
+
+ if (ud->vendor_oui)
+ device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
+ nodemgr_create_ud_dev_files(ud);
+}
+
/* This implementation currently only scans the config rom and its
* immediate unit directories looking for software_id and
unsigned int *id, struct unit_directory *parent)
{
struct unit_directory *ud;
- struct unit_directory *ud_temp = NULL;
+ struct unit_directory *ud_child = NULL;
struct csr1212_dentry *dentry;
struct csr1212_keyval *kv;
u8 last_key_id = 0;
- ud = kmalloc(sizeof(struct unit_directory), GFP_KERNEL);
+ ud = kzalloc(sizeof(*ud), GFP_KERNEL);
if (!ud)
goto unit_directory_error;
- memset (ud, 0, sizeof(struct unit_directory));
-
ud->ne = ne;
ud->ignore_driver = ignore_drivers;
ud->address = ud_kv->offset + CSR1212_CONFIG_ROM_SPACE_BASE;
break;
case CSR1212_KV_ID_DEPENDENT_INFO:
- if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
+ /* 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);
+ 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;
+
+ ud->id = (*id)++;
+ }
+ ud->lun = kv->value.immediate;
+ ud->flags |= UNIT_DIRECTORY_HAS_LUN;
+
+ /* Logical Unit Directory */
+ } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
/* This should really be done in SBP2 as this is
- * doing SBP2 specific parsing. */
+ * doing SBP2 specific parsing.
+ */
+
+ /* first register the parent unit */
ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
- ud_temp = nodemgr_process_unit_directory(hi, ne, kv, id,
- parent);
+ if (ud->device.bus != &ieee1394_bus_type)
+ nodemgr_register_device(ne, ud, &ne->device);
+
+ /* process the child unit */
+ ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud);
- if (ud_temp == NULL)
+ if (ud_child == NULL)
break;
-
- /* inherit unspecified values */
- if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) &&
- !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID))
- {
- ud_temp->flags |= UNIT_DIRECTORY_VENDOR_ID;
- ud_temp->vendor_id = ud->vendor_id;
- ud_temp->vendor_oui = ud->vendor_oui;
- }
+
+ /* inherit unspecified values, the driver core picks it up */
if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
- !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID))
+ !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
{
- ud_temp->flags |= UNIT_DIRECTORY_MODEL_ID;
- ud_temp->model_id = ud->model_id;
+ ud_child->flags |= UNIT_DIRECTORY_MODEL_ID;
+ ud_child->model_id = ud->model_id;
}
if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
- !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID))
+ !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
{
- ud_temp->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
- ud_temp->specifier_id = ud->specifier_id;
+ ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
+ ud_child->specifier_id = ud->specifier_id;
}
if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
- !(ud_temp->flags & UNIT_DIRECTORY_VERSION))
+ !(ud_child->flags & UNIT_DIRECTORY_VERSION))
{
- ud_temp->flags |= UNIT_DIRECTORY_VERSION;
- ud_temp->version = ud->version;
+ ud_child->flags |= UNIT_DIRECTORY_VERSION;
+ ud_child->version = ud->version;
}
+
+ /* register the child unit */
+ ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
+ nodemgr_register_device(ne, ud_child, &ud->device);
}
break;
}
last_key_id = kv->key.id;
}
-
- memcpy(&ud->device, &nodemgr_dev_template_ud,
- sizeof(ud->device));
-
- if (parent) {
- ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
- ud->device.parent = &parent->device;
- } else
- ud->device.parent = &ne->device;
-
- snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
- ne->device.bus_id, ud->id);
-
- ud->class_dev.dev = &ud->device;
- ud->class_dev.class = &nodemgr_ud_class;
- snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
- ne->device.bus_id, ud->id);
-
- device_register(&ud->device);
- class_device_register(&ud->class_dev);
- get_device(&ud->device);
-
- if (ud->vendor_oui)
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
- nodemgr_create_ud_dev_files(ud);
+
+ /* do not process child units here and only if not already registered */
+ if (!parent && ud->device.bus != &ieee1394_bus_type)
+ nodemgr_register_device(ne, ud, &ne->device);
return ud;
unit_directory_error:
- if (ud != NULL)
- kfree(ud);
+ kfree(ud);
return NULL;
}
#ifdef CONFIG_HOTPLUG
-static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
{
struct unit_directory *ud;
int i = 0;
int length = 0;
+ /* ieee1394:venNmoNspNverN */
+ char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
if (!cdev)
return -ENODEV;
PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
PUT_ENVP("VERSION=%06x", ud->version);
+ snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+ ud->vendor_id,
+ ud->model_id,
+ ud->specifier_id,
+ ud->version);
+ PUT_ENVP("MODALIAS=%s", buf);
#undef PUT_ENVP
- envp[i] = 0;
+ envp[i] = NULL;
return 0;
}
#else
-static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
{
return -ENODEV;
}
/* Mark the node as new, so it gets re-probed */
ne->needs_probe = 1;
+ } else {
+ /* old cache is valid, so update its generation */
+ struct nodemgr_csr_info *ci = ne->csr->private;
+ ci->generation = generation;
+ /* free the partially filled now unneeded new cache */
+ kfree(csr->private);
+ csr1212_destroy_csr(csr);
}
if (ne->in_limbo)
struct csr1212_csr *csr;
struct nodemgr_csr_info *ci;
- ci = kmalloc(sizeof(struct nodemgr_csr_info), GFP_KERNEL);
+ ci = kmalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
return;
if (ud->device.driver &&
(!ud->device.driver->suspend ||
- ud->device.driver->suspend(&ud->device, 0, 0)))
+ ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
device_release_driver(&ud->device);
}
up_write(&ne->device.bus->subsys.rwsem);
continue;
if (ud->device.driver && ud->device.driver->resume)
- ud->device.driver->resume(&ud->device, 0);
+ ud->device.driver->resume(&ud->device);
}
up_read(&ne->device.bus->subsys.rwsem);
}
+/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3. This
+ * seems like an optional service but in the end it is practically mandatory
+ * as a consequence of these clauses.
+ *
+ * Note that we cannot do a broadcast write to all nodes at once because some
+ * pre-1394a devices would hang. */
+static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
+{
+ const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
+ quadlet_t bc_remote, bc_local;
+ int ret;
+
+ if (!ne->host->is_irm || ne->generation != generation ||
+ ne->nodeid == ne->host->node_id)
+ return;
+
+ 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) &&
+ bc_remote != bc_local)
+ hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
+}
+
+
static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
{
struct device *dev;
if (!dev)
return;
+ nodemgr_irm_write_bc(ne, generation);
+
/* If "needs_probe", then this is either a new or changed node we
* rescan totally. If the generation matches for an existing node
* (one that existed prior to the bus reset) we send update calls
struct hpsb_host *host = hi->host;
struct class *class = &nodemgr_ne_class;
struct class_device *cdev;
+ struct node_entry *ne;
/* Do some processing of the nodes we've probed. This pulls them
* into the sysfs layer if needed, and can result in processing of
* unit-directories, or just updating the node and it's
- * unit-directories. */
+ * unit-directories.
+ *
+ * Run updates before probes. Usually, updates are time-critical
+ * while probes are time-consuming. (Well, those probes need some
+ * improvement...) */
+
down_read(&class->subsys.rwsem);
- list_for_each_entry(cdev, &class->children, node)
- nodemgr_probe_ne(hi, container_of(cdev, struct node_entry, class_dev), generation);
+ list_for_each_entry(cdev, &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) {
+ ne = container_of(cdev, struct node_entry, class_dev);
+ if (ne->needs_probe)
+ nodemgr_probe_ne(hi, ne, generation);
+ }
up_read(&class->subsys.rwsem);
return;
}
-/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other
- * nodes of the broadcast channel. (Really we're only setting the validity
- * bit). Other IRM responsibilities go in here as well. */
+static int nodemgr_send_resume_packet(struct hpsb_host *host)
+{
+ struct hpsb_packet *packet;
+ int ret = 1;
+
+ packet = hpsb_make_phypacket(host,
+ EXTPHYPACKET_TYPE_RESUME |
+ NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
+ if (packet) {
+ packet->no_waiter = 1;
+ packet->generation = get_hpsb_generation(host);
+ ret = hpsb_send_packet(packet);
+ }
+ if (ret)
+ HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
+ host->id);
+ return ret;
+}
+
+/* Perform a few high-level IRM responsibilities. */
static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
{
quadlet_t bc;
if (!host->is_irm || host->irm_id == (nodeid_t)-1)
return 1;
- host->csr.broadcast_channel |= 0x40000000; /* set validity bit */
-
- bc = cpu_to_be32(host->csr.broadcast_channel);
-
- hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
- (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
- &bc, sizeof(quadlet_t));
+ /* We are a 1394a-2000 compliant IRM. Set the validity bit. */
+ host->csr.broadcast_channel |= 0x40000000;
/* If there is no bus manager then we should set the root node's
* force_root bit to promote bus stability per the 1394
if (host->busmgr_id == 0xffff && host->node_count > 1)
{
u16 root_node = host->node_count - 1;
- struct node_entry *ne = find_entry_by_nodeid(host, root_node | LOCAL_BUS);
- if (ne && ne->busopt.cmc)
+ /* get cycle master capability flag from root node */
+ if (host->is_cycmst ||
+ (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
+ (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
+ &bc, sizeof(quadlet_t)) &&
+ be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
hpsb_send_phy_config(host, root_node, -1);
else {
HPSB_DEBUG("The root node is not cycle master capable; "
}
}
+ /* Some devices suspend their ports while being connected to an inactive
+ * host adapter, i.e. if connected before the low-level driver is
+ * loaded. They become visible either when physically unplugged and
+ * replugged, or when receiving a resume packet. Send one once. */
+ if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
+ host->resume_packet_sent = 1;
+
return 1;
}
quadlet_t bc;
int status;
- if (host->is_irm)
+ if (hpsb_disable_irm || host->is_irm)
return 1;
status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
/* Sit and wait for a signal to probe the nodes on the bus. This
* happens when we get a bus reset. */
- while (!down_interruptible(&hi->reset_sem) &&
- !down_interruptible(&nodemgr_serialize)) {
+ while (1) {
unsigned int generation = 0;
int i;
- if (hi->kill_me)
+ if (down_interruptible(&hi->reset_sem) ||
+ down_interruptible(&nodemgr_serialize)) {
+ if (try_to_freeze())
+ continue;
+ printk("NodeMgr: received unexpected signal?!\n" );
break;
+ }
+
+ if (hi->kill_me) {
+ up(&nodemgr_serialize);
+ break;
+ }
/* Pause for 1/4 second in 1/16 second intervals,
* to make sure things settle down. */
for (i = 0; i < 4 ; i++) {
set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(HZ/16)) {
+ if (msleep_interruptible(63)) {
up(&nodemgr_serialize);
goto caught_signal;
}
* start the the waiting over again */
while (!down_trylock(&hi->reset_sem))
i = 0;
+
+ /* Check the kill_me again */
+ if (hi->kill_me) {
+ up(&nodemgr_serialize);
+ goto caught_signal;
+ }
}
- if (!nodemgr_check_irm_capability(host, reset_cycles)) {
+ if (!nodemgr_check_irm_capability(host, reset_cycles) ||
+ !nodemgr_do_irm_duties(host, reset_cycles)) {
reset_cycles++;
up(&nodemgr_serialize);
continue;
}
+ reset_cycles = 0;
/* Scan our nodes to get the bus options and create node
* entries. This does not do the sysfs stuff, since that
- * would trigger hotplug callbacks and such, which is a
- * bad idea at this point. */
+ * would trigger uevents and such, which is a bad idea at
+ * this point. */
nodemgr_node_scan(hi, generation);
- if (!nodemgr_do_irm_duties(host, reset_cycles)) {
- reset_cycles++;
- up(&nodemgr_serialize);
- continue;
- }
-
- reset_cycles = 0;
/* This actually does the full probe, with sysfs
* registration. */
complete_and_exit(&hi->exited, 0);
}
-struct node_entry *hpsb_guid_get_entry(u64 guid)
-{
- struct node_entry *ne;
-
- down(&nodemgr_serialize);
- ne = find_entry_by_guid(guid);
- up(&nodemgr_serialize);
-
- return ne;
-}
-
-struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid)
-{
- struct node_entry *ne;
-
- down(&nodemgr_serialize);
- ne = find_entry_by_nodeid(host, nodeid);
- up(&nodemgr_serialize);
-
- return ne;
-}
-
-
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
{
struct class *class = &hpsb_host_class;
pkt->node_id = ne->nodeid;
}
-int hpsb_node_read(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length)
-{
- unsigned int generation = ne->generation;
-
- barrier();
- return hpsb_read(ne->host, ne->nodeid, generation,
- addr, buffer, length);
-}
-
int hpsb_node_write(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length)
{
addr, buffer, length);
}
-int hpsb_node_lock(struct node_entry *ne, u64 addr,
- int extcode, quadlet_t *data, quadlet_t arg)
-{
- unsigned int generation = ne->generation;
-
- barrier();
- return hpsb_lock(ne->host, ne->nodeid, generation,
- addr, extcode, data, arg);
-}
-
static void nodemgr_add_host(struct hpsb_host *host)
{
struct host_info *hi;
.remove_host = nodemgr_remove_host,
};
-void init_ieee1394_nodemgr(void)
+int init_ieee1394_nodemgr(void)
{
- class_register(&nodemgr_ne_class);
- class_register(&nodemgr_ud_class);
+ int ret;
+
+ 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;
+ }
hpsb_register_highlevel(&nodemgr_highlevel);
+
+ return 0;
}
void cleanup_ieee1394_nodemgr(void)