aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 16:18:46 -0800
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 16:18:46 -0800
commitc99767974ebd2a719d849fdeaaa1674456f5283f (patch)
tree571d49bd7872697ab28b0aeb4f79fe9c2a5cb9bd /drivers
parentea14fad0d416354a4e9bb1a04f32acba706f9548 (diff)
parentec9b7e1044d718723d16390179abc6d4c8d9b0a1 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (55 commits) ieee1394: sbp2: code formatting around work_struct stuff ieee1394: nodemgr: remove a kcalloc ieee1394: conditionally export ieee1394_bus_type ieee1394: Consolidate driver registering ieee1394: sbp2: convert from PCI DMA to generic DMA ieee1394: nodemgr: spaces to tabs ieee1394: nodemgr: fix deadlock in shutdown ieee1394: nodemgr: remove duplicate assignment sbp2: make 1bit bitfield unsigned ieee1394: schedule *_oui sysfs attributes for removal ieee1394: schedule unused symbol exports for removal ieee1394: dv1394: schedule for feature removal ieee1394: raw1394: defer feature removal of old isoch interface ieee1394: ohci1394: call PMac code in shutdown only for proper machines ieee1394: ohci1394: reformat PPC_PMAC platform code ieee1394: ohci1394: add PPC_PMAC platform code to driver probe ieee1394: sbp2: wrap two functions into one ieee1394: sbp2: update comment on things to do ieee1394: sbp2: use list_move_tail() ieee1394: sbp2: more concise names for types and variables ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ieee1394/Kconfig26
-rw-r--r--drivers/ieee1394/Makefile5
-rw-r--r--drivers/ieee1394/csr.c8
-rw-r--r--drivers/ieee1394/dv1394.c24
-rw-r--r--drivers/ieee1394/eth1394.c4
-rw-r--r--drivers/ieee1394/highlevel.h1
-rw-r--r--drivers/ieee1394/hosts.c41
-rw-r--r--drivers/ieee1394/ieee1394_core.c4
-rw-r--r--drivers/ieee1394/nodemgr.c465
-rw-r--r--drivers/ieee1394/nodemgr.h7
-rw-r--r--drivers/ieee1394/ohci1394.c140
-rw-r--r--drivers/ieee1394/pcilynx.c3
-rw-r--r--drivers/ieee1394/raw1394-private.h10
-rw-r--r--drivers/ieee1394/raw1394.c23
-rw-r--r--drivers/ieee1394/sbp2.c2190
-rw-r--r--drivers/ieee1394/sbp2.h311
-rw-r--r--drivers/ieee1394/video1394.c54
17 files changed, 1411 insertions, 1905 deletions
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 672b92ef9f2..e7d56573fe5 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -36,7 +36,7 @@ config IEEE1394_VERBOSEDEBUG
else says N.
config IEEE1394_OUI_DB
- bool "OUI Database built-in"
+ bool "OUI Database built-in (deprecated)"
depends on IEEE1394
help
If you say Y here, then an OUI list (vendor unique ID's) will be
@@ -67,16 +67,11 @@ config IEEE1394_CONFIG_ROM_IP1394
eth1394 option below.
config IEEE1394_EXPORT_FULL_API
- bool "Export all symbols of ieee1394's API"
+ bool "Export all symbols of ieee1394's API (deprecated)"
depends on IEEE1394
default n
help
- Export all symbols of ieee1394's driver programming interface, even
- those that are not currently used by the standard IEEE 1394 drivers.
-
- This option does not affect the interface to userspace applications.
- Say Y here if you want to compile externally developed drivers that
- make extended use of ieee1394's API. It is otherwise safe to say N.
+ This option will be removed soon. Don't worry, say N.
comment "Device Drivers"
depends on IEEE1394
@@ -125,7 +120,7 @@ comment "SBP-2 support (for storage devices) requires SCSI"
config IEEE1394_SBP2
tristate "SBP-2 support (Harddisks etc.)"
- depends on IEEE1394 && SCSI && (PCI || BROKEN)
+ depends on IEEE1394 && SCSI
help
This option enables you to use SBP-2 devices connected to an IEEE
1394 bus. SBP-2 devices include storage devices like harddisks and
@@ -161,17 +156,12 @@ config IEEE1394_ETH1394
MCAP, therefore multicast support is significantly limited.
config IEEE1394_DV1394
- tristate "OHCI-DV I/O support"
+ tristate "OHCI-DV I/O support (deprecated)"
depends on IEEE1394 && IEEE1394_OHCI1394
help
- This driver allows you to transmit and receive DV (digital video)
- streams on an OHCI-1394 card using a simple frame-oriented
- interface.
-
- The user-space API for dv1394 is documented in dv1394.h.
-
- To compile this driver as a module, say M here: the
- module will be called dv1394.
+ The dv1394 driver will be removed from Linux in a future release.
+ Its functionality is now provided by raw1394 together with libraries
+ such as libiec61883.
config IEEE1394_RAWIO
tristate "Raw IEEE1394 I/O support"
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index 6f53611fe25..d9650d3d77a 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -3,8 +3,11 @@
#
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
- highlevel.o csr.o nodemgr.o oui.o dma.o iso.o \
+ highlevel.o csr.o nodemgr.o dma.o iso.o \
csr1212.o config_roms.o
+ifdef CONFIG_IEEE1394_OUI_DB
+ieee1394-objs += oui.o
+endif
obj-$(CONFIG_IEEE1394) += ieee1394.o
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index ab0c80f61b9..52ac83e0ebe 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -158,12 +158,10 @@ static void host_reset(struct hpsb_host *host)
*/
static inline void calculate_expire(struct csr_control *csr)
{
- unsigned long usecs =
- (csr->split_timeout_hi & 0x07) * USEC_PER_SEC +
- (csr->split_timeout_lo >> 19) * 125L;
-
- csr->expire = usecs_to_jiffies(usecs > 100000L ? usecs : 100000L);
+ unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
+ (csr->split_timeout_lo >> 19) * 125;
+ csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
}
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 6c72f04b2b5..1084da4d88a 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -1536,27 +1536,20 @@ static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count
static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct video_card *video;
+ struct video_card *video = file_to_video_card(file);
unsigned long flags;
int ret = -EINVAL;
void __user *argp = (void __user *)arg;
DECLARE_WAITQUEUE(wait, current);
- lock_kernel();
- video = file_to_video_card(file);
-
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&video->mtx)) {
- unlock_kernel();
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
- }
} else {
- if (mutex_lock_interruptible(&video->mtx)) {
- unlock_kernel();
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
- }
}
switch(cmd)
@@ -1780,7 +1773,6 @@ static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
out:
mutex_unlock(&video->mtx);
- unlock_kernel();
return ret;
}
@@ -2188,12 +2180,8 @@ static struct ieee1394_device_id dv1394_id_table[] = {
MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
static struct hpsb_protocol_driver dv1394_driver = {
- .name = "DV/1394 Driver",
+ .name = "dv1394",
.id_table = dv1394_id_table,
- .driver = {
- .name = "dv1394",
- .bus = &ieee1394_bus_type,
- },
};
@@ -2587,6 +2575,10 @@ static int __init dv1394_init_module(void)
{
int ret;
+ printk(KERN_WARNING
+ "WARNING: The dv1394 driver is unsupported and will be removed "
+ "from Linux soon. Use raw1394 instead.\n");
+
cdev_init(&dv1394_cdev, &dv1394_fops);
dv1394_cdev.owner = THIS_MODULE;
kobject_set_name(&dv1394_cdev.kobj, "dv1394");
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 27d6c642415..97e5c3dd044 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -474,12 +474,10 @@ static struct ieee1394_device_id eth1394_id_table[] = {
MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
static struct hpsb_protocol_driver eth1394_proto_driver = {
- .name = "IPv4 over 1394 Driver",
+ .name = ETH1394_DRIVER_NAME,
.id_table = eth1394_id_table,
.update = eth1394_update,
.driver = {
- .name = ETH1394_DRIVER_NAME,
- .bus = &ieee1394_bus_type,
.probe = eth1394_probe,
.remove = eth1394_remove,
},
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index 50f2dd2c7e2..4b330117067 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -24,7 +24,6 @@ struct hpsb_address_serve {
/* Only the following structures are of interest to actual highlevel drivers. */
struct hpsb_highlevel {
- struct module *owner;
const char *name;
/* Any of the following pointers can legally be NULL, except for
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index b935e08695a..ee82a5320bf 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -44,9 +44,10 @@ static void delayed_reset_bus(struct work_struct *work)
CSR_SET_BUS_INFO_GENERATION(host->csr.rom, generation);
if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
- /* CSR image creation failed, reset generation field and do not
- * issue a bus reset. */
- CSR_SET_BUS_INFO_GENERATION(host->csr.rom, host->csr.generation);
+ /* CSR image creation failed.
+ * Reset generation field and do not issue a bus reset. */
+ CSR_SET_BUS_INFO_GENERATION(host->csr.rom,
+ host->csr.generation);
return;
}
@@ -54,7 +55,8 @@ static void delayed_reset_bus(struct work_struct *work)
host->update_config_rom = 0;
if (host->driver->set_hw_config_rom)
- host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
+ host->driver->set_hw_config_rom(host,
+ host->csr.rom->bus_info_data);
host->csr.gen_timestamp[host->csr.generation] = jiffies;
hpsb_reset_bus(host, SHORT_RESET);
@@ -70,7 +72,8 @@ static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
return -1;
}
-static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg)
+static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
+ unsigned long arg)
{
return -1;
}
@@ -128,10 +131,8 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
return NULL;
h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
- if (!h->csr.rom) {
- kfree(h);
- return NULL;
- }
+ if (!h->csr.rom)
+ goto fail;
h->hostdata = h + 1;
h->driver = drv;
@@ -151,16 +152,15 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
init_timer(&h->timeout);
h->timeout.data = (unsigned long) h;
h->timeout.function = abort_timedouts;
- h->timeout_interval = HZ / 20; // 50ms by default
+ h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
h->topology_map = h->csr.topology_map + 3;
h->speed_map = (u8 *)(h->csr.speed_map + 2);
mutex_lock(&host_num_alloc);
-
while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
hostnum++;
-
+ mutex_unlock(&host_num_alloc);
h->id = hostnum;
memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
@@ -171,13 +171,19 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
h->class_dev.class = &hpsb_host_class;
snprintf(h->class_dev.class_id, BUS_ID_SIZE, "fw-host%d", h->id);
- device_register(&h->device);
- class_device_register(&h->class_dev);
+ if (device_register(&h->device))
+ goto fail;
+ if (class_device_register(&h->class_dev)) {
+ device_unregister(&h->device);
+ goto fail;
+ }
get_device(&h->device);
- mutex_unlock(&host_num_alloc);
-
return h;
+
+fail:
+ kfree(h);
+ return NULL;
}
int hpsb_add_host(struct hpsb_host *host)
@@ -229,7 +235,8 @@ int hpsb_update_config_rom_image(struct hpsb_host *host)
if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
/* Wait 60 seconds from the last time this generation number was
* used. */
- reset_delay = (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
+ reset_delay =
+ (60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
else
/* Wait 1 second in case some other code wants to change the
* Config ROM in the near future. */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 5fccf9f7a1d..9a48ca20d1f 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1237,10 +1237,10 @@ EXPORT_SYMBOL(highlevel_remove_host);
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(hpsb_register_protocol);
+EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
-EXPORT_SYMBOL(ieee1394_bus_type);
#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
+EXPORT_SYMBOL(ieee1394_bus_type);
EXPORT_SYMBOL(nodemgr_for_each_host);
#endif
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index e829c9336b3..61307ca296a 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/freezer.h>
#include <asm/atomic.h>
@@ -67,7 +68,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
{
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;
@@ -79,9 +80,9 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
* 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;
@@ -95,19 +96,19 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
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;
}
@@ -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 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)
@@ -260,9 +261,20 @@ static struct device nodemgr_dev_template_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 = {
.bus = &ieee1394_bus_type,
.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);\
} \
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
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 */
@@ -374,11 +386,11 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute
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)
+ 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;
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 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)
- 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)
{
@@ -433,7 +448,7 @@ static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size
if (state == 1)
ignore_drivers = 1;
- else if (!state)
+ else if (state == 0)
ignore_drivers = 0;
return count;
@@ -526,7 +541,7 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
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;
@@ -583,7 +598,11 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
int 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;
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;
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)
{
@@ -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, "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)
@@ -642,32 +677,39 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
int 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)
- 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)
- 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) {
- 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) {
- 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)
{
- 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 */
@@ -675,55 +717,77 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
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_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 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)
@@ -748,7 +812,7 @@ static int __nodemgr_remove_host_dev(struct device *dev, void *data)
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, "busmgr_id");
sysfs_remove_link(&dev->kobj, "host_id");
@@ -762,16 +826,16 @@ static void nodemgr_update_bus_options(struct node_entry *ne)
#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",
@@ -792,7 +856,7 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
ne = kzalloc(sizeof(*ne), GFP_KERNEL);
if (!ne)
- return NULL;
+ goto fail_alloc;
ne->host = host;
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",
(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);
- 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_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);
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)
{
- 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) {
@@ -848,20 +926,20 @@ static struct node_entry *find_entry_by_guid(u64 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) {
@@ -869,7 +947,7 @@ static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t
break;
}
}
- up_read(&class->subsys.rwsem);
+ up(&nodemgr_ne_class.sem);
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",
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);
- if (ud->vendor_oui)
- device_create_file(&ud-&g