Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/ieee1394/linux1394-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (26 commits)
  firewire: fw-sbp2: Use sbp2 device-provided mgt orb timeout for logins
  firewire: fw-sbp2: increase login orb reply timeout, fix "failed to login"
  firewire: replace subtraction with bitwise and
  firewire: fw-core: react on bus resets while the config ROM is being fetched
  firewire: enforce access order between generation and node ID, fix "giving up on config rom"
  firewire: fw-cdev: use device generation, not card generation
  firewire: fw-sbp2: use device generation, not card generation
  firewire: fw-sbp2: try to increase reconnect_hold (speed up reconnection)
  firewire: fw-sbp2: skip unnecessary logout
  firewire vs. ieee1394: clarify MAINTAINERS
  firewire: fw-ohci: Dynamically allocate buffers for DMA descriptors
  firewire: fw-ohci: CycleTooLong interrupt management
  firewire: Fix extraction of source node id
  firewire: fw-ohci: Bug fixes for packet-per-buffer support
  firewire: fw-ohci: Fix for dualbuffer three-or-more buffers
  firewire: fw-sbp2: remove unused misleading macro
  firewire: fw-sbp2: prepare for s/g chaining
  firewire: fw-sbp2: refactor workq and kref handling
  ieee1394: ohci1394: don't schedule IT tasklets on IR events
  ieee1394: sbp2: raise default transfer size limit
  ...
  • Loading branch information
Linus Torvalds committed Jan 31, 2008
2 parents 5bdeae4 + 384170d commit 94ed294
Show file tree
Hide file tree
Showing 14 changed files with 424 additions and 336 deletions.
4 changes: 2 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ P: Alexander Viro
M: viro@zeniv.linux.org.uk
S: Maintained

FIREWIRE SUBSYSTEM
FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>)
P: Kristian Hoegsberg, Stefan Richter
M: krh@redhat.com, stefanr@s5r6.in-berlin.de
L: linux1394-devel@lists.sourceforge.net
Expand Down Expand Up @@ -1917,7 +1917,7 @@ L: linux-ide@vger.kernel.org
L: linux-scsi@vger.kernel.org
S: Orphan

IEEE 1394 SUBSYSTEM
IEEE 1394 SUBSYSTEM (drivers/ieee1394)
P: Ben Collins
M: ben.collins@ubuntu.com
P: Stefan Richter
Expand Down
3 changes: 2 additions & 1 deletion drivers/firewire/fw-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,13 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,

event->closure = client->bus_reset_closure;
event->type = FW_CDEV_EVENT_BUS_RESET;
event->generation = client->device->generation;
smp_rmb(); /* node_id must not be older than generation */
event->node_id = client->device->node_id;
event->local_node_id = card->local_node->node_id;
event->bm_node_id = 0; /* FIXME: We don't track the BM. */
event->irm_node_id = card->irm_node->node_id;
event->root_node_id = card->root_node->node_id;
event->generation = card->generation;
}

static void
Expand Down
38 changes: 29 additions & 9 deletions drivers/firewire/fw-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/idr.h>
#include <linux/rwsem.h>
#include <asm/semaphore.h>
#include <asm/system.h>
#include <linux/ctype.h>
#include "fw-transaction.h"
#include "fw-topology.h"
Expand Down Expand Up @@ -182,9 +183,14 @@ static void fw_device_release(struct device *dev)

int fw_device_enable_phys_dma(struct fw_device *device)
{
int generation = device->generation;

/* device->node_id, accessed below, must not be older than generation */
smp_rmb();

return device->card->driver->enable_phys_dma(device->card,
device->node_id,
device->generation);
generation);
}
EXPORT_SYMBOL(fw_device_enable_phys_dma);

Expand Down Expand Up @@ -384,17 +390,21 @@ complete_transaction(struct fw_card *card, int rcode,
complete(&callback_data->done);
}

static int read_rom(struct fw_device *device, int index, u32 * data)
static int
read_rom(struct fw_device *device, int generation, int index, u32 *data)
{
struct read_quadlet_callback_data callback_data;
struct fw_transaction t;
u64 offset;

/* device->node_id, accessed below, must not be older than generation */
smp_rmb();

init_completion(&callback_data.done);

offset = 0xfffff0000400ULL + index * 4;
fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST,
device->node_id, device->generation, device->max_speed,
device->node_id, generation, device->max_speed,
offset, NULL, 4, complete_transaction, &callback_data);

wait_for_completion(&callback_data.done);
Expand All @@ -404,7 +414,14 @@ static int read_rom(struct fw_device *device, int index, u32 * data)
return callback_data.rcode;
}

static int read_bus_info_block(struct fw_device *device)
/*
* 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
* generation changes under us, read_bus_info_block will fail and get retried.
* It's better to start all over in this case because the node from which we
* are reading the ROM may have changed the ROM during the reset.
*/
static int read_bus_info_block(struct fw_device *device, int generation)
{
static u32 rom[256];
u32 stack[16], sp, key;
Expand All @@ -414,7 +431,7 @@ static int read_bus_info_block(struct fw_device *device)

/* First read the bus info block. */
for (i = 0; i < 5; i++) {
if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
return -1;
/*
* As per IEEE1212 7.2, during power-up, devices can
Expand Down Expand Up @@ -449,7 +466,8 @@ static int read_bus_info_block(struct fw_device *device)
device->max_speed = device->card->link_speed;

while (device->max_speed > SCODE_100) {
if (read_rom(device, 0, &dummy) == RCODE_COMPLETE)
if (read_rom(device, generation, 0, &dummy) ==
RCODE_COMPLETE)
break;
device->max_speed--;
}
Expand Down Expand Up @@ -482,7 +500,7 @@ static int read_bus_info_block(struct fw_device *device)
return -1;

/* Read header quadlet for the block to get the length. */
if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
return -1;
end = i + (rom[i] >> 16) + 1;
i++;
Expand All @@ -501,7 +519,8 @@ static int read_bus_info_block(struct fw_device *device)
* it references another block, and push it in that case.
*/
while (i < end) {
if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
if (read_rom(device, generation, i, &rom[i]) !=
RCODE_COMPLETE)
return -1;
if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
sp < ARRAY_SIZE(stack))
Expand Down Expand Up @@ -648,7 +667,7 @@ static void fw_device_init(struct work_struct *work)
* device.
*/

if (read_bus_info_block(device) < 0) {
if (read_bus_info_block(device, device->generation) < 0) {
if (device->config_rom_retries < MAX_RETRIES) {
device->config_rom_retries++;
schedule_delayed_work(&device->work, RETRY_DELAY);
Expand Down Expand Up @@ -801,6 +820,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)

device = node->data;
device->node_id = node->node_id;
smp_wmb(); /* update node_id before generation */
device->generation = card->generation;
if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
PREPARE_DELAYED_WORK(&device->work, fw_device_update);
Expand Down
12 changes: 12 additions & 0 deletions drivers/firewire/fw-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ struct fw_attribute_group {
struct attribute *attrs[11];
};

/*
* Note, fw_device.generation always has to be read before fw_device.node_id.
* Use SMP memory barriers to ensure this. Otherwise requests will be sent
* to an outdated node_id if the generation was updated in the meantime due
* to a bus reset.
*
* Likewise, fw-core will take care to update .node_id before .generation so
* that whenever fw_device.generation is current WRT the actual bus generation,
* fw_device.node_id is guaranteed to be current too.
*
* The same applies to fw_device.card->node_id vs. fw_device.generation.
*/
struct fw_device {
atomic_t state;
struct fw_node *node;
Expand Down
Loading

0 comments on commit 94ed294

Please sign in to comment.