diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 11:24:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 11:24:29 -0700 |
commit | eddeb0e2d863e3941d8768e70cb50c6120e61fa0 (patch) | |
tree | e30f2b6654e6eb397f9d7fb23a08d717cc19b12d | |
parent | 855d854a33fca71cf68bad258bd5e66e5b265d10 (diff) | |
parent | db8be076cad4b843aa743ef462c75022cddd9c63 (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: (43 commits)
firewire: cleanups
firewire: fix synchronization of gap counts
firewire: wait until PHY configuration packet was transmitted (fix bus reset loop)
firewire: remove unused struct member
firewire: use bitwise and to get reg in handle_registers
firewire: replace more hex values with defined csr constants
firewire: reread config ROM when device reset the bus
firewire: replace static ROM cache by allocated cache
firewire: fw-ohci: work around generation bug in TI controllers (fix AV/C and more)
firewire: fw-ohci: extend logging of bus generations and node ID
firewire: fw-ohci: conditionally log busReset interrupts
firewire: fw-ohci: don't append to AT context when it's not active
firewire: fw-ohci: log regAccessFail events
firewire: fw-ohci: make sure HCControl register LPS bit is set
firewire: fw-ohci: missing PPC PMac feature calls in failure path
firewire: fw-ohci: untangle a mixed unsigned/signed expression
firewire: debug interrupt events
firewire: fw-ohci: catch self_id_count == 0
firewire: fw-ohci: add self ID error check
firewire: fw-ohci: refactor probe, remove, suspend, resume
...
-rw-r--r-- | Documentation/debugging-via-ohci1394.txt | 16 | ||||
-rw-r--r-- | drivers/firewire/Kconfig | 5 | ||||
-rw-r--r-- | drivers/firewire/fw-card.c | 50 | ||||
-rw-r--r-- | drivers/firewire/fw-cdev.c | 13 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 263 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 38 | ||||
-rw-r--r-- | drivers/firewire/fw-iso.c | 5 | ||||
-rw-r--r-- | drivers/firewire/fw-ohci.c | 402 | ||||
-rw-r--r-- | drivers/firewire/fw-ohci.h | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 150 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.c | 10 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.h | 11 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 75 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 10 | ||||
-rw-r--r-- | drivers/ieee1394/csr.c | 6 | ||||
-rw-r--r-- | drivers/ieee1394/dv1394.c | 4 | ||||
-rw-r--r-- | drivers/ieee1394/highlevel.c | 6 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_core.c | 4 | ||||
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 6 | ||||
-rw-r--r-- | drivers/ieee1394/ohci1394.c | 229 | ||||
-rw-r--r-- | drivers/ieee1394/pcilynx.c | 15 | ||||
-rw-r--r-- | drivers/ieee1394/raw1394.c | 2 | ||||
-rw-r--r-- | drivers/ieee1394/sbp2.c | 11 | ||||
-rw-r--r-- | drivers/ieee1394/video1394.c | 4 | ||||
-rw-r--r-- | lib/Kconfig.debug | 13 |
25 files changed, 877 insertions, 473 deletions
diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt index c360d4e91b4..59a91e5c690 100644 --- a/Documentation/debugging-via-ohci1394.txt +++ b/Documentation/debugging-via-ohci1394.txt @@ -41,15 +41,19 @@ to a working state and enables physical DMA by default for all remote nodes. This can be turned off by ohci1394's module parameter phys_dma=0. The alternative firewire-ohci driver in drivers/firewire uses filtered physical -DMA, hence is not yet suitable for remote debugging. +DMA by default, which is more secure but not suitable for remote debugging. +Compile the driver with CONFIG_FIREWIRE_OHCI_REMOTE_DMA (Kernel hacking menu: +Remote debugging over FireWire with firewire-ohci) to get unfiltered physical +DMA. -Because ohci1394 depends on the PCI enumeration to be completed, an -initialization routine which runs pretty early (long before console_init() -which makes the printk buffer appear on the console can be called) was written. +Because ohci1394 and firewire-ohci depend on the PCI enumeration to be +completed, an initialization routine which runs pretty early has been +implemented for x86. This routine runs long before console_init() can be +called, i.e. before the printk buffer appears on the console. To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu: -Provide code for enabling DMA over FireWire early on boot) and pass the -parameter "ohci1394_dma=early" to the recompiled kernel on boot. +Remote debugging over FireWire early on boot) and pass the parameter +"ohci1394_dma=early" to the recompiled kernel on boot. Tools ----- diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 25bdc2dd9ce..fb4d391810b 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -54,6 +54,11 @@ config FIREWIRE_OHCI directive, use "install modulename /bin/true" for the modules to be blacklisted. +config FIREWIRE_OHCI_DEBUG + bool + depends on FIREWIRE_OHCI + default y + config FIREWIRE_SBP2 tristate "Support for storage devices (SBP-2 protocol driver)" depends on FIREWIRE && SCSI diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index a03462750b9..5b4c0d9f517 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -167,7 +167,6 @@ fw_core_add_descriptor(struct fw_descriptor *desc) return 0; } -EXPORT_SYMBOL(fw_core_add_descriptor); void fw_core_remove_descriptor(struct fw_descriptor *desc) @@ -182,7 +181,6 @@ fw_core_remove_descriptor(struct fw_descriptor *desc) mutex_unlock(&card_mutex); } -EXPORT_SYMBOL(fw_core_remove_descriptor); static const char gap_count_table[] = { 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 @@ -220,7 +218,7 @@ fw_card_bm_work(struct work_struct *work) struct bm_data bmd; unsigned long flags; int root_id, new_root_id, irm_id, gap_count, generation, grace; - int do_reset = 0; + bool do_reset = false; spin_lock_irqsave(&card->lock, flags); local_node = card->local_node; @@ -331,7 +329,7 @@ fw_card_bm_work(struct work_struct *work) */ spin_unlock_irqrestore(&card->lock, flags); goto out; - } else if (root_device->config_rom[2] & BIB_CMC) { + } else if (root_device->cmc) { /* * FIXME: I suppose we should set the cmstr bit in the * STATE_CLEAR register of this node, as described in @@ -360,14 +358,14 @@ fw_card_bm_work(struct work_struct *work) gap_count = 63; /* - * Finally, figure out if we should do a reset or not. If we've - * done less that 5 resets with the same physical topology and we + * Finally, figure out if we should do a reset or not. If we have + * done less than 5 resets with the same physical topology and we * have either a new root or a new gap count setting, let's do it. */ if (card->bm_retries++ < 5 && (card->gap_count != gap_count || new_root_id != root_id)) - do_reset = 1; + do_reset = true; spin_unlock_irqrestore(&card->lock, flags); @@ -398,7 +396,6 @@ fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, { static atomic_t index = ATOMIC_INIT(-1); - kref_init(&card->kref); atomic_set(&card->device_count, 0); card->index = atomic_inc_return(&index); card->driver = driver; @@ -429,12 +426,6 @@ fw_card_add(struct fw_card *card, card->link_speed = link_speed; card->guid = guid; - /* - * The subsystem grabs a reference when the card is added and - * drops it when the driver calls fw_core_remove_card. - */ - fw_card_get(card); - mutex_lock(&card_mutex); config_rom = generate_config_rom(card, &length); list_add_tail(&card->link, &card_list); @@ -540,40 +531,9 @@ fw_core_remove_card(struct fw_card *card) cancel_delayed_work_sync(&card->work); fw_flush_transactions(card); del_timer_sync(&card->flush_timer); - - fw_card_put(card); } EXPORT_SYMBOL(fw_core_remove_card); -struct fw_card * -fw_card_get(struct fw_card *card) -{ - kref_get(&card->kref); - - return card; -} -EXPORT_SYMBOL(fw_card_get); - -static void -release_card(struct kref *kref) -{ - struct fw_card *card = container_of(kref, struct fw_card, kref); - - kfree(card); -} - -/* - * An assumption for fw_card_put() is that the card driver allocates - * the fw_card struct with kalloc and that it has been shut down - * before the last ref is dropped. - */ -void -fw_card_put(struct fw_card *card) -{ - kref_put(&card->kref, release_card); -} -EXPORT_SYMBOL(fw_card_put); - int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset) { diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 46bc197a047..4a541921a14 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -269,21 +269,28 @@ static int ioctl_get_info(struct client *client, void *buffer) { struct fw_cdev_get_info *get_info = buffer; struct fw_cdev_event_bus_reset bus_reset; + unsigned long ret = 0; client->version = get_info->version; get_info->version = FW_CDEV_VERSION; + down_read(&fw_device_rwsem); + if (get_info->rom != 0) { void __user *uptr = u64_to_uptr(get_info->rom); size_t want = get_info->rom_length; size_t have = client->device->config_rom_length * 4; - if (copy_to_user(uptr, client->device->config_rom, - min(want, have))) - return -EFAULT; + ret = copy_to_user(uptr, client->device->config_rom, + min(want, have)); } get_info->rom_length = client->device->config_rom_length * 4; + up_read(&fw_device_rwsem); + + if (ret != 0) + return -EFAULT; + client->bus_reset_closure = get_info->bus_reset_closure; if (get_info->bus_reset != 0) { void __user *uptr = u64_to_uptr(get_info->bus_reset); diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 870125a3638..2d01bc1b975 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -25,7 +25,7 @@ #include <linux/device.h> #include <linux/delay.h> #include <linux/idr.h> -#include <linux/rwsem.h> +#include <linux/string.h> #include <asm/semaphore.h> #include <asm/system.h> #include <linux/ctype.h> @@ -160,9 +160,9 @@ static void fw_device_release(struct device *dev) * Take the card lock so we don't set this to NULL while a * FW_NODE_UPDATED callback is being handled. */ - spin_lock_irqsave(&device->card->lock, flags); + spin_lock_irqsave(&card->lock, flags); device->node->data = NULL; - spin_unlock_irqrestore(&device->card->lock, flags); + spin_unlock_irqrestore(&card->lock, flags); fw_node_put(device->node); kfree(device->config_rom); @@ -195,7 +195,9 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; u32 *dir; - int key, value; + int key, value, ret = -ENOENT; + + down_read(&fw_device_rwsem); if (is_fw_unit(dev)) dir = fw_unit(dev)->directory; @@ -204,11 +206,15 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) fw_csr_iterator_init(&ci, dir); while (fw_csr_iterator_next(&ci, &key, &value)) - if (attr->key == key) - return snprintf(buf, buf ? PAGE_SIZE : 0, - "0x%06x\n", value); + if (attr->key == key) { + ret = snprintf(buf, buf ? PAGE_SIZE : 0, + "0x%06x\n", value); + break; + } + + up_read(&fw_device_rwsem); - return -ENOENT; + return ret; } #define IMMEDIATE_ATTR(name, key) \ @@ -221,9 +227,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; u32 *dir, *block = NULL, *p, *end; - int length, key, value, last_key = 0; + int length, key, value, last_key = 0, ret = -ENOENT; char *b; + down_read(&fw_device_rwsem); + if (is_fw_unit(dev)) dir = fw_unit(dev)->directory; else @@ -238,18 +246,20 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) } if (block == NULL) - return -ENOENT; + goto out; length = min(block[0] >> 16, 256U); if (length < 3) - return -ENOENT; + goto out; if (block[1] != 0 || block[2] != 0) /* Unknown encoding. */ - return -ENOENT; + goto out; - if (buf == NULL) - return length * 4; + if (buf == NULL) { + ret = length * 4; + goto out; + } b = buf; end = &block[length + 1]; @@ -259,8 +269,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) /* Strip trailing whitespace and add newline. */ while (b--, (isspace(*b) || *b == '\0') && b > buf); strcpy(b + 1, "\n"); + ret = b + 2 - buf; + out: + up_read(&fw_device_rwsem); - return b + 2 - buf; + return ret; } #define TEXT_LEAF_ATTR(name, key) \ @@ -337,19 +350,28 @@ static ssize_t config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fw_device *device = fw_device(dev); + size_t length; - memcpy(buf, device->config_rom, device->config_rom_length * 4); + down_read(&fw_device_rwsem); + length = device->config_rom_length * 4; + memcpy(buf, device->config_rom, length); + up_read(&fw_device_rwsem); - return device->config_rom_length * 4; + return length; } static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fw_device *device = fw_device(dev); + int ret; + + down_read(&fw_device_rwsem); + ret = snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", + device->config_rom[3], device->config_rom[4]); + up_read(&fw_device_rwsem); - return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", - device->config_rom[3], device->config_rom[4]); + return ret; } static struct device_attribute fw_device_attributes[] = { @@ -388,7 +410,7 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) init_completion(&callback_data.done); - offset = 0xfffff0000400ULL + index * 4; + offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4; fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, device->node_id, generation, device->max_speed, offset, NULL, 4, complete_transaction, &callback_data); @@ -400,6 +422,9 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) return callback_data.rcode; } +#define READ_BIB_ROM_SIZE 256 +#define READ_BIB_STACK_SIZE 16 + /* * Read the bus info block, perform a speed probe, and read all of the rest of * the config ROM. We do all this with a cached bus generation. If the bus @@ -409,16 +434,23 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) */ static int read_bus_info_block(struct fw_device *device, int generation) { - static u32 rom[256]; - u32 stack[16], sp, key; - int i, end, length; + u32 *rom, *stack, *old_rom, *new_rom; + u32 sp, key; + int i, end, length, ret = -1; + + rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE + + sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); + if (rom == NULL) + return -ENOMEM; + + stack = &rom[READ_BIB_ROM_SIZE]; device->max_speed = SCODE_100; /* First read the bus info block. */ for (i = 0; i < 5; i++) { if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; /* * As per IEEE1212 7.2, during power-up, devices can * reply with a 0 for the first quadlet of the config @@ -428,7 +460,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) * retry mechanism will try again later. */ if (i == 0 && rom[i] == 0) - return -1; + goto out; } device->max_speed = device->node->max_speed; @@ -478,26 +510,26 @@ static int read_bus_info_block(struct fw_device *device, int generation) */ key = stack[--sp]; i = key & 0xffffff; - if (i >= ARRAY_SIZE(rom)) + if (i >= READ_BIB_ROM_SIZE) /* * The reference points outside the standard * config rom area, something's fishy. */ - return -1; + goto out; /* Read header quadlet for the block to get the length. */ if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; end = i + (rom[i] >> 16) + 1; i++; - if (end > ARRAY_SIZE(rom)) + if (end > READ_BIB_ROM_SIZE) /* * This block extends outside standard config * area (and the array we're reading it * into). That's broken, so ignore this * device. */ - return -1; + goto out; /* * Now read in the block. If this is a directory @@ -507,9 +539,9 @@ static int read_bus_info_block(struct fw_device *device, int generation) while (i < end) { if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) - return -1; + goto out; if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && - sp < ARRAY_SIZE(stack)) + sp < READ_BIB_STACK_SIZE) stack[sp++] = i + rom[i]; i++; } @@ -517,13 +549,23 @@ static int read_bus_info_block(struct fw_device *device, int generation) length = i; } - device->config_rom = kmalloc(length * 4, GFP_KERNEL); - if (device->config_rom == NULL) - return -1; - memcpy(device->config_rom, rom, length * 4); + old_rom = device->config_rom; + new_rom = kmemdup(rom, length * 4, GFP_KERNEL); + if (new_rom == NULL) + goto out; + + down_write(&fw_device_rwsem); + device->config_rom = new_rom; device->config_rom_length = length; + up_write(&fw_device_rwsem); - return 0; + kfree(old_rom); + ret = 0; + device->cmc = rom[2] & 1 << 30; + out: + kfree(rom); + + return ret; } static void fw_unit_release(struct device *dev) @@ -592,7 +634,14 @@ static int shutdown_unit(struct device *device, void *data) return 0; } -static DECLARE_RWSEM(idr_rwsem); +/* + * fw_device_rwsem acts as dual purpose mutex: + * - serializes accesses to fw_device_idr, + * - serializes accesses to fw_device.config_rom/.config_rom_length and + * fw_unit.directory, unless those accesses happen at safe occasions + */ +DECLARE_RWSEM(fw_device_rwsem); + static DEFINE_IDR(fw_device_idr); int fw_cdev_major; @@ -600,11 +649,11 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) { struct fw_device *device; - down_read(&idr_rwsem); + down_read(&fw_device_rwsem); device = idr_find(&fw_device_idr, MINOR(devt)); if (device) fw_device_get(device); - up_read(&idr_rwsem); + up_read(&fw_device_rwsem); return device; } @@ -619,9 +668,9 @@ static void fw_device_shutdown(struct work_struct *work) device_for_each_child(&device->device, NULL, shutdown_unit); device_unregister(&device->device); - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); idr_remove(&fw_device_idr, minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); fw_device_put(device); } @@ -674,10 +723,10 @@ static void fw_device_init(struct work_struct *work) err = -ENOMEM; fw_device_get(device); - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) err = idr_get_new(&fw_device_idr, device, &minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); if (err < 0) goto error; @@ -711,7 +760,7 @@ static void fw_device_init(struct work_struct *work) if (atomic_cmpxchg(&device->state, FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { - fw_device_shutdown(&device->work.work); + fw_device_shutdown(work); } else { if (device->config_rom_retries) fw_notify("created device %s: GUID %08x%08x, S%d00, " @@ -725,6 +774,7 @@ static void fw_device_init(struct work_struct *work) device->device.bus_id, device->config_rom[3], device->config_rom[4], 1 << device->max_speed); + device->config_rom_retries = 0; } /* @@ -739,9 +789,9 @@ static void fw_device_init(struct work_struct *work) return; error_with_cdev: - down_write(&idr_rwsem); + down_write(&fw_device_rwsem); idr_remove(&fw_device_idr, minor); - up_write(&idr_rwsem); + up_write(&fw_device_rwsem); error: fw_device_put(device); /* fw_device_idr's reference */ @@ -771,6 +821,106 @@ static void fw_device_update(struct work_struct *work) device_for_each_child(&device->device, NULL, update_unit); } +enum { + REREAD_BIB_ERROR, + REREAD_BIB_GONE, + REREAD_BIB_UNCHANGED, + REREAD_BIB_CHANGED, +}; + +/* Reread and compare bus info block and header of root directory */ +static int reread_bus_info_block(struct fw_device *device, int generation) +{ + u32 q; + int i; + + for (i = 0; i < 6; i++) { + if (read_rom(device, generation, i, &q) != RCODE_COMPLETE) + return REREAD_BIB_ERROR; + + if (i == 0 && q == 0) + return REREAD_BIB_GONE; + + if (i > device->config_rom_length || q != device->config_rom[i]) + return REREAD_BIB_CHANGED; + } + + return REREAD_BIB_UNCHANGED; +} + +static void fw_device_refresh(struct work_struct *work) +{ + struct fw_device *device = + container_of(work, struct fw_device, work.work); + struct fw_card *card = device->card; + int node_id = device->node_id; + + switch (reread_bus_info_block(device, device->generation)) { + case REREAD_BIB_ERROR: + if (device->config_rom_retries < MAX_RETRIES / 2 && + atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { + device->config_rom_retries++; + schedule_delayed_work(&device->work, RETRY_DELAY / 2); + + return; + } + goto give_up; + + case REREAD_BIB_GONE: + goto gone; + + case REREAD_BIB_UNCHANGED: + if (atomic_cmpxchg(&device->state, + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + goto gone; + + fw_device_update(work); + device->config_rom_retries = 0; + goto out; + + case REREAD_BIB_CHANGED: + break; + } + + /* + * Something changed. We keep things simple and don't investigate + * further. We just destroy all previous units and create new ones. + */ + device_for_each_child(&device->device, NULL, shutdown_unit); + + if (read_bus_info_block(device, device->generation) < 0) { + if (device->config_rom_retries < MAX_RETRIES && + atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { + device->config_rom_retries++; + schedule_delayed_work(&device->work, RETRY_DELAY); + + return; + } + goto give_up; + } + + create_units(device); + + if (atomic_cmpxchg(&device->state, + FW_DEVICE_INITIALIZING, + FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) + goto gone; + + fw_notify("refreshed device %s\n", device->device.bus_id); + device->config_rom_retries = 0; + goto out; + + give_up: + fw_notify("giving up on refresh of device %s\n", device->device.bus_id); + gone: + atomic_set(&device->state, FW_DEVICE_SHUTDOWN); + fw_device_shutdown(work); + out: + if (node_id == card->root_node->node_id) + schedule_delayed_work(&card->work, 0); +} + void fw_node_event(struct fw_card *card, struct fw_node *node, int event) { struct fw_device *device; @@ -780,7 +930,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) case FW_NODE_LINK_ON: if (!node->link_on) break; - + create: device = kzalloc(sizeof(*device), GFP_ATOMIC); if (device == NULL) break; @@ -819,6 +969,23 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) schedule_delayed_work(&device->work, INITIAL_DELAY); break; + case FW_NODE_INITIATED_RESET: + device = node->data; + if (device == NULL) + goto create; + + device->node_id = node->node_id; + smp_wmb(); /* update node_id before generation */ + device->generation = card->generation; + if (atomic_cmpxchg(&device->state, + FW_DEVICE_RUNNING, + FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { + PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); + schedule_delayed_work(&device->work, + node == card->local_node ? 0 : INITIAL_DELAY); + } + break; + case FW_NODE_UPDATED: if (!node->link_on || node->data == NULL) break; diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 78ecd3991b7..5f131f5129d 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -21,6 +21,7 @@ #include <linux/fs.h> #include <linux/cdev.h> +#include <linux/rwsem.h> #include <asm/atomic.h> enum fw_device_state { @@ -46,6 +47,11 @@ struct fw_attribute_group { * fw_device.node_id is guaranteed to be current too. * * The same applies to fw_device.card->node_id vs. fw_device.generation. + * + * fw_device.config_rom and fw_device.config_rom_length may be accessed during + * the lifetime of any fw_unit belonging to the fw_device, before device_del() + * was called on the last fw_unit. Alternatively, they may be accessed while + * holding fw_device_rwsem. */ struct fw_device { atomic_t state; @@ -53,6 +59,7 @@ struct fw_device { int node_id; int generation; unsigned max_speed; + bool cmc; struct fw_card *card; struct device device; struct list_head link; @@ -64,28 +71,24 @@ struct fw_device { struct fw_attribute_group attribute_group; }; -static inline struct fw_device * -fw_device(struct device *dev) +static inline struct fw_device *fw_device(struct device *dev) { return container_of(dev, struct fw_device, device); } -static inline int -fw_device_is_shutdown(struct fw_device *device) +static inline int fw_device_is_shutdown(struct fw_device *device) { return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN; } -static inline struct fw_device * -fw_device_get(struct fw_device *device) +static inline struct fw_device *fw_device_get(struct fw_device *device) { get_device(&device->device); return device; } -static inline void -fw_device_put(struct fw_device *device) +static inline void fw_device_put(struct fw_device *device) { put_device(&device->device); } @@ -96,20 +99,35 @@ int fw_device_enable_phys_dma(struct fw_device *device); void fw_device_cdev_update(struct fw_device *device); void fw_device_cdev_remove(struct fw_device *device); +extern struct rw_semaphore fw_device_rwsem; extern int fw_cdev_major; +/* + * fw_unit.directory must not be accessed after device_del(&fw_unit.device). + */ struct fw_unit { struct device device; u32 *directory; struct fw_attribute_group attribute_group; }; -static inline struct fw_unit * -fw_unit(struct device *dev) +static inline struct fw_unit *fw_unit(struct device *dev) { return container_of(dev, struct fw_unit, device); } +static inline struct fw_unit *fw_unit_get(struct fw_unit *unit) +{ + get_device(&unit->device); + + return unit; +} + +static inline void fw_unit_put(struct fw_unit *unit) +{ + put_device(&unit->device); +} + #define CSR_OFFSET 0x40 #define CSR_LEAF 0x80 #define CSR_DIRECTORY 0xc0 diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c index 2b640e9be6d..bcbe794a3ea 100644 --- a/drivers/firewire/fw-iso.c +++ b/drivers/firewire/fw-iso.c @@ -126,7 +126,6 @@ fw_iso_context_create(struct fw_card *card, int type, return ctx; } -EXPORT_SYMBOL(fw_iso_context_create); void fw_iso_context_destroy(struct fw_iso_context *ctx) { @@ -134,14 +133,12 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) card->driver->free_iso_context(ctx); } -EXPORT_SYMBOL(fw_iso_context_destroy); int fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags) { return ctx->card->driver->start_iso(ctx, cycle, sync, tags); } -EXPORT_SYMBOL(fw_iso_context_start); int fw_iso_context_queue(struct fw_iso_context *ctx, @@ -153,11 +150,9 @@ fw_iso_context_queue(struct fw_iso_context *ctx, return card->driver->queue_iso(ctx, packet, buffer, payload); } -EXPORT_SYMBOL(fw_iso_context_queue); int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); } -EXPORT_SYMBOL(fw_iso_context_stop); diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index ca6d51efd8b..4f02c55f13e 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/spinlock.h> @@ -177,9 +178,10 @@ struct fw_ohci { struct tasklet_struct bus_reset_tasklet; int node_id; int generation; - int request_generation; + int request_generation; /* for timestamping incoming requests */ u32 bus_seconds; bool old_uninorth; + bool bus_reset_packet_quirk; /* * Spinlock for accessing fw_ohci data. Never call out of @@ -237,6 +239,196 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; +#ifdef CONFIG_FIREWIRE_OHCI_DEBUG + +#define OHCI_PARAM_DEBUG_AT_AR 1 +#define OHCI_PARAM_DEBUG_SELFIDS 2 +#define OHCI_PARAM_DEBUG_IRQS 4 +#define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */ + +static int param_debug; +module_param_named(debug, param_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (default = 0" + ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) + ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) + ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) + ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSR |