Skip to content

Commit

Permalink
Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/ieee1394/linux1394

Pull IEEE 1394 (FireWire) subsystem updates from Stefan Richter:

 - Fix mismatch between DMA mapping direction (was wrong) and DMA
   synchronization direction (was correct) of isochronous reception
   buffers of userspace drivers if vma-mapped for R/W access.  For
   example, libdc1394 was affected.

 - more consistent retry stategy in device discovery/ rediscovery, and
   improved failure diagnostics

 - various small cleanups, e.g. use SCSI layer's DMA mapping API in
   firewire-sbp2

* tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
  firewire: sbp2: document the absence of alignment requirements
  firewire: sbp2: remove superfluous blk_queue_max_segment_size() call
  firewire: sbp2: use scsi_dma_(un)map
  firewire: sbp2: give correct DMA device to scsi framework
  firewire: core: fw_device_refresh(): clean up error handling
  firewire: core: log config rom reading errors
  firewire: core: log error in case of failed bus manager lock
  firewire: move rcode_string() to core
  firewire: core: improve reread_config_rom() interface
  firewire: core: wait for inaccessible devices after bus reset
  firewire: ohci: omit spinlock IRQ flags where possible
  firewire: ohci: correct signedness of a local variable
  firewire: core: fix DMA mapping direction
  firewire: use module_pci_driver
  • Loading branch information
torvalds committed May 24, 2012
2 parents f2fde3a + 26c72e2 commit 2f78d8e
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 189 deletions.
4 changes: 2 additions & 2 deletions drivers/firewire/core-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,8 @@ static void bm_work(struct work_struct *work)
* root, and thus, IRM.
*/
new_root_id = local_id;
fw_notice(card, "%s, making local node (%02x) root\n",
"BM lock failed", new_root_id);
fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n",
fw_rcode_string(rcode), new_root_id);
goto pick_me;
}
} else if (card->bm_generation != generation) {
Expand Down
51 changes: 41 additions & 10 deletions drivers/firewire/core-cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/firewire.h>
#include <linux/firewire-cdev.h>
Expand Down Expand Up @@ -70,6 +71,7 @@ struct client {
u64 iso_closure;
struct fw_iso_buffer buffer;
unsigned long vm_start;
bool buffer_is_mapped;

struct list_head phy_receiver_link;
u64 phy_receiver_closure;
Expand Down Expand Up @@ -959,11 +961,20 @@ static void iso_mc_callback(struct fw_iso_context *context,
sizeof(e->interrupt), NULL, 0);
}

static enum dma_data_direction iso_dma_direction(struct fw_iso_context *context)
{
if (context->type == FW_ISO_CONTEXT_TRANSMIT)
return DMA_TO_DEVICE;
else
return DMA_FROM_DEVICE;
}

static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
struct fw_iso_context *context;
fw_iso_callback_t cb;
int ret;

BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT ||
FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE ||
Expand Down Expand Up @@ -1004,8 +1015,21 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
if (client->iso_context != NULL) {
spin_unlock_irq(&client->lock);
fw_iso_context_destroy(context);

return -EBUSY;
}
if (!client->buffer_is_mapped) {
ret = fw_iso_buffer_map_dma(&client->buffer,
client->device->card,
iso_dma_direction(context));
if (ret < 0) {
spin_unlock_irq(&client->lock);
fw_iso_context_destroy(context);

return ret;
}
client->buffer_is_mapped = true;
}
client->iso_closure = a->closure;
client->iso_context = context;
spin_unlock_irq(&client->lock);
Expand Down Expand Up @@ -1651,7 +1675,6 @@ static long fw_device_op_compat_ioctl(struct file *file,
static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
{
struct client *client = file->private_data;
enum dma_data_direction direction;
unsigned long size;
int page_count, ret;

Expand All @@ -1674,20 +1697,28 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
if (size & ~PAGE_MASK)
return -EINVAL;

if (vma->vm_flags & VM_WRITE)
direction = DMA_TO_DEVICE;
else
direction = DMA_FROM_DEVICE;

ret = fw_iso_buffer_init(&client->buffer, client->device->card,
page_count, direction);
ret = fw_iso_buffer_alloc(&client->buffer, page_count);
if (ret < 0)
return ret;

ret = fw_iso_buffer_map(&client->buffer, vma);
spin_lock_irq(&client->lock);
if (client->iso_context) {
ret = fw_iso_buffer_map_dma(&client->buffer,
client->device->card,
iso_dma_direction(client->iso_context));
client->buffer_is_mapped = (ret == 0);
}
spin_unlock_irq(&client->lock);
if (ret < 0)
fw_iso_buffer_destroy(&client->buffer, client->device->card);
goto fail;

ret = fw_iso_buffer_map_vma(&client->buffer, vma);
if (ret < 0)
goto fail;

return 0;
fail:
fw_iso_buffer_destroy(&client->buffer, client->device->card);
return ret;
}

Expand Down
116 changes: 57 additions & 59 deletions drivers/firewire/core-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,14 +481,15 @@ static int read_rom(struct fw_device *device,
* generation changes under us, read_config_rom 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.
* Returns either a result code or a negative error code.
*/
static int read_config_rom(struct fw_device *device, int generation)
{
struct fw_card *card = device->card;
const u32 *old_rom, *new_rom;
u32 *rom, *stack;
u32 sp, key;
int i, end, length, ret = -1;
int i, end, length, ret;

rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
Expand All @@ -502,18 +503,21 @@ static int read_config_rom(struct fw_device *device, int generation)

/* First read the bus info block. */
for (i = 0; i < 5; i++) {
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
ret = read_rom(device, generation, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;
/*
* As per IEEE1212 7.2, during power-up, devices can
* As per IEEE1212 7.2, during initialization, devices can
* reply with a 0 for the first quadlet of the config
* rom to indicate that they are booting (for example,
* if the firmware is on the disk of a external
* harddisk). In that case we just fail, and the
* retry mechanism will try again later.
*/
if (i == 0 && rom[i] == 0)
if (i == 0 && rom[i] == 0) {
ret = RCODE_BUSY;
goto out;
}
}

device->max_speed = device->node->max_speed;
Expand Down Expand Up @@ -563,11 +567,14 @@ static int read_config_rom(struct fw_device *device, int generation)
*/
key = stack[--sp];
i = key & 0xffffff;
if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) {
ret = -ENXIO;
goto out;
}

/* Read header quadlet for the block to get the length. */
if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
ret = read_rom(device, generation, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;
end = i + (rom[i] >> 16) + 1;
if (end > MAX_CONFIG_ROM_SIZE) {
Expand All @@ -590,8 +597,8 @@ static int read_config_rom(struct fw_device *device, int generation)
* it references another block, and push it in that case.
*/
for (; i < end; i++) {
if (read_rom(device, generation, i, &rom[i]) !=
RCODE_COMPLETE)
ret = read_rom(device, generation, i, &rom[i]);
if (ret != RCODE_COMPLETE)
goto out;

if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
Expand Down Expand Up @@ -619,16 +626,18 @@ static int read_config_rom(struct fw_device *device, int generation)

old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
if (new_rom == NULL)
if (new_rom == NULL) {
ret = -ENOMEM;
goto out;
}

down_write(&fw_device_rwsem);
device->config_rom = new_rom;
device->config_rom_length = length;
up_write(&fw_device_rwsem);

kfree(old_rom);
ret = 0;
ret = RCODE_COMPLETE;
device->max_rec = rom[2] >> 12 & 0xf;
device->cmc = rom[2] >> 30 & 1;
device->irmc = rom[2] >> 31 & 1;
Expand Down Expand Up @@ -967,15 +976,17 @@ static void fw_device_init(struct work_struct *work)
* device.
*/

if (read_config_rom(device, device->generation) < 0) {
ret = read_config_rom(device, device->generation);
if (ret != RCODE_COMPLETE) {
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
fw_schedule_device_work(device, RETRY_DELAY);
} else {
if (device->node->link_on)
fw_notice(card, "giving up on Config ROM for node id %x\n",
device->node_id);
fw_notice(card, "giving up on node %x: reading config rom failed: %s\n",
device->node_id,
fw_rcode_string(ret));
if (device->node == card->root_node)
fw_schedule_bm_work(card, 0);
fw_device_release(&device->device);
Expand Down Expand Up @@ -1069,55 +1080,45 @@ static void fw_device_init(struct work_struct *work)
put_device(&device->device); /* our reference */
}

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_config_rom(struct fw_device *device, int generation)
static int reread_config_rom(struct fw_device *device, int generation,
bool *changed)
{
u32 q;
int i;
int i, rcode;

for (i = 0; i < 6; i++) {
if (read_rom(device, generation, i, &q) != RCODE_COMPLETE)
return REREAD_BIB_ERROR;
rcode = read_rom(device, generation, i, &q);
if (rcode != RCODE_COMPLETE)
return rcode;

if (i == 0 && q == 0)
return REREAD_BIB_GONE;
/* inaccessible (see read_config_rom); retry later */
return RCODE_BUSY;

if (q != device->config_rom[i])
return REREAD_BIB_CHANGED;
if (q != device->config_rom[i]) {
*changed = true;
return RCODE_COMPLETE;
}
}

return REREAD_BIB_UNCHANGED;
*changed = false;
return RCODE_COMPLETE;
}

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_config_rom(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++;
fw_schedule_device_work(device, RETRY_DELAY / 2);

return;
}
goto give_up;
int ret, node_id = device->node_id;
bool changed;

case REREAD_BIB_GONE:
goto gone;
ret = reread_config_rom(device, device->generation, &changed);
if (ret != RCODE_COMPLETE)
goto failed_config_rom;

case REREAD_BIB_UNCHANGED:
if (!changed) {
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
Expand All @@ -1126,9 +1127,6 @@ static void fw_device_refresh(struct work_struct *work)
fw_device_update(work);
device->config_rom_retries = 0;
goto out;

case REREAD_BIB_CHANGED:
break;
}

/*
Expand All @@ -1137,16 +1135,9 @@ static void fw_device_refresh(struct work_struct *work)
*/
device_for_each_child(&device->device, NULL, shutdown_unit);

if (read_config_rom(device, device->generation) < 0) {
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
fw_schedule_device_work(device, RETRY_DELAY);

return;
}
goto give_up;
}
ret = read_config_rom(device, device->generation);
if (ret != RCODE_COMPLETE)
goto failed_config_rom;

fw_device_cdev_update(device);
create_units(device);
Expand All @@ -1163,9 +1154,16 @@ static void fw_device_refresh(struct work_struct *work)
device->config_rom_retries = 0;
goto out;

give_up:
fw_notice(card, "giving up on refresh of device %s\n",
dev_name(&device->device));
failed_config_rom:
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
fw_schedule_device_work(device, RETRY_DELAY);
return;
}

fw_notice(card, "giving up on refresh of device %s: %s\n",
dev_name(&device->device), fw_rcode_string(ret));
gone:
atomic_set(&device->state, FW_DEVICE_GONE);
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
Expand Down
Loading

0 comments on commit 2f78d8e

Please sign in to comment.