IEEE 1394 (FireWire) subsystem updates post v3.4:
- 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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.17 (GNU/Linux) iQIcBAABAgAGBQJPvoOWAAoJEHnzb7JUXXnQpG4P/j4u9kU+MDegDrRsAzZBdP+6 in2FW8opUzSXZyLSzU/JYcO7P0luEEdLIE65fkaVRbP1x6m7aAjgaAO/0zbqZQPD QVyIAOPa8zcbEIi1cEnI75KU/AMyQpMk/eU9Et4FrbQszgyFvJNe+hS+MocMooPt vukqmWJuIPfH/G3FsX0eQWEXS7GktkYxmLJM/k6z4JpngAVmelM/Ce45VFg7tbN+ IeV5N7+FF4zKmwgiKIpkw5tSO6If7mjoQQVH/Q8DiHJDhFlDUrKR9/TvaJesVtEg 5n97BbfvXc8mu6EE8lbl1ats2R1I00JDpMylHPt4J6G1XDjb1/GvqSjXYXwPT77J O4xZwqT4C5JKnG9h2a4npf6PgDHBbMnUK9cDBxfA5ZPkTeZmGXWuP05zYJqeNJm9 UrEusEjzEEspVWFqxOD+2/YLF/0rxqA/P1C7Luuw7Y9nIcCt3VskuW6iebYuf5Dk yNoykYVph8zDJE+Am7jtsgNCPfd4TomFttjMcc/0EVqNa1iVO/AuLlvYv+Ab75oU BpOUEg8Pq9nQeya3XjM585R0rF4PG5wsVrBe2ZzJ+cqNe6JH264/YuBgFv1bkUg3 UtHNIG633KAk71P1jl7PeuvAQksLnCYak2JOviZ/oB79Yamoxifhcm4mNkwTeCv7 paRqDNAzoaThqvqx723E =fulr -----END PGP SIGNATURE----- Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
commit
2f78d8e249
@ -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) {
|
||||
|
@ -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>
|
||||
@ -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;
|
||||
@ -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 ||
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -481,6 +481,7 @@ 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)
|
||||
{
|
||||
@ -488,7 +489,7 @@ static int read_config_rom(struct fw_device *device, int generation)
|
||||
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);
|
||||
@ -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;
|
||||
@ -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) {
|
||||
@ -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)
|
||||
@ -619,8 +626,10 @@ 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;
|
||||
@ -628,7 +637,7 @@ static int read_config_rom(struct fw_device *device, int generation)
|
||||
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;
|
||||
@ -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);
|
||||
@ -1069,31 +1080,30 @@ 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)
|
||||
@ -1101,23 +1111,14 @@ 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;
|
||||
int ret, node_id = device->node_id;
|
||||
bool changed;
|
||||
|
||||
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);
|
||||
ret = reread_config_rom(device, device->generation, &changed);
|
||||
if (ret != RCODE_COMPLETE)
|
||||
goto failed_config_rom;
|
||||
|
||||
return;
|
||||
}
|
||||
goto give_up;
|
||||
|
||||
case REREAD_BIB_GONE:
|
||||
goto gone;
|
||||
|
||||
case REREAD_BIB_UNCHANGED:
|
||||
if (!changed) {
|
||||
if (atomic_cmpxchg(&device->state,
|
||||
FW_DEVICE_INITIALIZING,
|
||||
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
@ -39,52 +39,73 @@
|
||||
* Isochronous DMA context management
|
||||
*/
|
||||
|
||||
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
int page_count, enum dma_data_direction direction)
|
||||
int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count)
|
||||
{
|
||||
int i, j;
|
||||
dma_addr_t address;
|
||||
|
||||
buffer->page_count = page_count;
|
||||
buffer->direction = direction;
|
||||
int i;
|
||||
|
||||
buffer->page_count = 0;
|
||||
buffer->page_count_mapped = 0;
|
||||
buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
|
||||
GFP_KERNEL);
|
||||
if (buffer->pages == NULL)
|
||||
goto out;
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < buffer->page_count; i++) {
|
||||
for (i = 0; i < page_count; i++) {
|
||||
buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
|
||||
if (buffer->pages[i] == NULL)
|
||||
goto out_pages;
|
||||
|
||||
address = dma_map_page(card->device, buffer->pages[i],
|
||||
0, PAGE_SIZE, direction);
|
||||
if (dma_mapping_error(card->device, address)) {
|
||||
__free_page(buffer->pages[i]);
|
||||
goto out_pages;
|
||||
}
|
||||
set_page_private(buffer->pages[i], address);
|
||||
break;
|
||||
}
|
||||
buffer->page_count = i;
|
||||
if (i < page_count) {
|
||||
fw_iso_buffer_destroy(buffer, NULL);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
out_pages:
|
||||
for (j = 0; j < i; j++) {
|
||||
address = page_private(buffer->pages[j]);
|
||||
dma_unmap_page(card->device, address,
|
||||
PAGE_SIZE, direction);
|
||||
__free_page(buffer->pages[j]);
|
||||
int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_addr_t address;
|
||||
int i;
|
||||
|
||||
buffer->direction = direction;
|
||||
|
||||
for (i = 0; i < buffer->page_count; i++) {
|
||||
address = dma_map_page(card->device, buffer->pages[i],
|
||||
0, PAGE_SIZE, direction);
|
||||
if (dma_mapping_error(card->device, address))
|
||||
break;
|
||||
|
||||
set_page_private(buffer->pages[i], address);
|
||||
}
|
||||
kfree(buffer->pages);
|
||||
out:
|
||||
buffer->pages = NULL;
|
||||
buffer->page_count_mapped = i;
|
||||
if (i < buffer->page_count)
|
||||
return -ENOMEM;
|
||||
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
int page_count, enum dma_data_direction direction)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fw_iso_buffer_alloc(buffer, page_count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = fw_iso_buffer_map_dma(buffer, card, direction);
|
||||
if (ret < 0)
|
||||
fw_iso_buffer_destroy(buffer, card);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_buffer_init);
|
||||
|
||||
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
|
||||
int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long uaddr;
|
||||
int i, err;
|
||||
@ -107,15 +128,18 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
|
||||
int i;
|
||||
dma_addr_t address;
|
||||
|
||||
for (i = 0; i < buffer->page_count; i++) {
|
||||
for (i = 0; i < buffer->page_count_mapped; i++) {
|
||||
address = page_private(buffer->pages[i]);
|
||||
dma_unmap_page(card->device, address,
|
||||
PAGE_SIZE, buffer->direction);
|
||||
__free_page(buffer->pages[i]);
|
||||
}
|
||||
for (i = 0; i < buffer->page_count; i++)
|
||||
__free_page(buffer->pages[i]);
|
||||
|
||||
kfree(buffer->pages);
|
||||
buffer->pages = NULL;
|
||||
buffer->page_count = 0;
|
||||
buffer->page_count_mapped = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fw_iso_buffer_destroy);
|
||||
|
||||
|
@ -1003,6 +1003,32 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
|
||||
}
|
||||
EXPORT_SYMBOL(fw_core_handle_response);
|
||||
|
||||
/**
|
||||
* fw_rcode_string - convert a firewire result code to an error description
|
||||
* @rcode: the result code
|
||||
*/
|
||||
const char *fw_rcode_string(int rcode)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
[RCODE_COMPLETE] = "no error",
|
||||
[RCODE_CONFLICT_ERROR] = "conflict error",
|
||||
[RCODE_DATA_ERROR] = "data error",
|
||||
[RCODE_TYPE_ERROR] = "type error",
|
||||
[RCODE_ADDRESS_ERROR] = "address error",
|
||||
[RCODE_SEND_ERROR] = "send error",
|
||||
[RCODE_CANCELLED] = "timeout",
|
||||
[RCODE_BUSY] = "busy",
|
||||
[RCODE_GENERATION] = "bus reset",
|
||||
[RCODE_NO_ACK] = "no ack",
|
||||
};
|
||||
|
||||
if ((unsigned int)rcode < ARRAY_SIZE(names) && names[rcode])
|
||||
return names[rcode];
|
||||
else
|
||||
return "unknown";
|
||||
}
|
||||
EXPORT_SYMBOL(fw_rcode_string);
|
||||
|
||||
static const struct fw_address_region topology_map_region =
|
||||
{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
|
||||
.end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/idr.h>
|
||||
@ -154,7 +155,11 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
|
||||
|
||||
/* -iso */
|
||||
|
||||
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
|
||||
int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count);
|
||||
int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
enum dma_data_direction direction);
|
||||
int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
|
||||
struct vm_area_struct *vma);
|
||||
|
||||
|
||||
/* -topology */
|
||||
|
@ -693,6 +693,8 @@ static struct pci_device_id pci_table[] __devinitdata = {
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, pci_table);
|
||||
|
||||
static struct pci_driver lynx_pci_driver = {
|
||||
.name = driver_name,
|
||||
.id_table = pci_table,
|
||||
@ -700,22 +702,8 @@ static struct pci_driver lynx_pci_driver = {
|
||||
.remove = remove_card,
|
||||
};
|
||||
|
||||
module_pci_driver(lynx_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Kristian Hoegsberg");
|
||||
MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pci, pci_table);
|
||||
|
||||
static int __init nosy_init(void)
|
||||
{
|
||||
return pci_register_driver(&lynx_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit nosy_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&lynx_pci_driver);
|
||||
|
||||
pr_info("Unloaded %s\n", driver_name);
|
||||
}
|
||||
|
||||
module_init(nosy_init);
|
||||
module_exit(nosy_cleanup);
|
||||
|
@ -1821,9 +1821,8 @@ static void bus_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct fw_ohci *ohci =
|
||||
container_of(work, struct fw_ohci, bus_reset_work);
|
||||
int self_id_count, i, j, reg;
|
||||
int generation, new_generation;
|
||||
unsigned long flags;
|
||||
int self_id_count, generation, new_generation, i, j;
|
||||
u32 reg;
|
||||
void *free_rom = NULL;
|
||||
dma_addr_t free_rom_bus = 0;
|
||||
bool is_new_root;
|
||||
@ -1930,13 +1929,13 @@ static void bus_reset_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* FIXME: Document how the locking works. */
|
||||
spin_lock_irqsave(&ohci->lock, flags);
|
||||
spin_lock_irq(&ohci->lock);
|
||||
|
||||
ohci->generation = -1; /* prevent AT packet queueing */
|
||||
context_stop(&ohci->at_request_ctx);
|
||||
context_stop(&ohci->at_response_ctx);
|
||||
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
/*
|
||||
* Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
|
||||
@ -1946,7 +1945,7 @@ static void bus_reset_work(struct work_struct *work)
|
||||
at_context_flush(&ohci->at_request_ctx);
|
||||
at_context_flush(&ohci->at_response_ctx);
|
||||
|
||||
spin_lock_irqsave(&ohci->lock, flags);
|
||||
spin_lock_irq(&ohci->lock);
|
||||
|
||||
ohci->generation = generation;
|
||||
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
|
||||
@ -1990,7 +1989,7 @@ static void bus_reset_work(struct work_struct *work)
|
||||
reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
if (free_rom)
|
||||
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
|
||||
@ -2402,7 +2401,6 @@ static int ohci_set_config_rom(struct fw_card *card,
|
||||
const __be32 *config_rom, size_t length)
|
||||
{
|
||||
struct fw_ohci *ohci;
|
||||
unsigned long flags;
|
||||
__be32 *next_config_rom;
|
||||
dma_addr_t uninitialized_var(next_config_rom_bus);
|
||||
|
||||
@ -2441,7 +2439,7 @@ static int ohci_set_config_rom(struct fw_card *card,
|
||||
if (next_config_rom == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&ohci->lock, flags);
|
||||
spin_lock_irq(&ohci->lock);
|
||||
|
||||
/*
|
||||
* If there is not an already pending config_rom update,
|
||||
@ -2467,7 +2465,7 @@ static int ohci_set_config_rom(struct fw_card *card,
|
||||
|
||||
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
|
||||
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
/* If we didn't use the DMA allocation, delete it. */
|
||||
if (next_config_rom != NULL)
|
||||
@ -2891,10 +2889,9 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
|
||||
descriptor_callback_t uninitialized_var(callback);
|
||||
u64 *uninitialized_var(channels);
|
||||
u32 *uninitialized_var(mask), uninitialized_var(regs);
|
||||
unsigned long flags;
|
||||
int index, ret = -EBUSY;
|
||||
|
||||
spin_lock_irqsave(&ohci->lock, flags);
|
||||
spin_lock_irq(&ohci->lock);
|
||||
|
||||
switch (type) {
|
||||
case FW_ISO_CONTEXT_TRANSMIT:
|
||||
@ -2938,7 +2935,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
if (index < 0)
|
||||
return ERR_PTR(ret);
|
||||
@ -2964,7 +2961,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
|
||||
out_with_header:
|
||||
free_page((unsigned long)ctx->header);
|
||||
out:
|
||||
spin_lock_irqsave(&ohci->lock, flags);
|
||||
spin_lock_irq(&ohci->lock);
|
||||
|
||||
switch (type) {
|
||||
case FW_ISO_CONTEXT_RECEIVE:
|
||||
@ -2977,7 +2974,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
|
||||
}
|
||||
*mask |= 1 << index;
|
||||
|
||||
spin_unlock_irqrestore(&ohci->lock, flags);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
@ -3789,6 +3786,8 @@ static struct pci_driver fw_ohci_pci_driver = {
|
||||
#endif
|
||||
};
|
||||
|
||||
module_pci_driver(fw_ohci_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
||||
MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
|
||||
MODULE_LICENSE("GPL");
|
||||
@ -3797,16 +3796,3 @@ MODULE_LICENSE("GPL");
|
||||
#ifndef CONFIG_IEEE1394_OHCI1394_MODULE
|
||||
MODULE_ALIAS("ohci1394");
|
||||
#endif
|
||||
|
||||
static int __init fw_ohci_init(void)
|
||||
{
|
||||
return pci_register_driver(&fw_ohci_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit fw_ohci_cleanup(void)
|
||||
{
|
||||
pci_unregister_driver(&fw_ohci_pci_driver);
|
||||
}
|
||||
|
||||
module_init(fw_ohci_init);
|
||||
module_exit(fw_ohci_cleanup);
|
||||
|
@ -207,9 +207,8 @@ static const struct device *lu_dev(const struct sbp2_logical_unit *lu)
|
||||
#define SBP2_MAX_CDB_SIZE 16
|
||||
|
||||
/*
|
||||
* The default maximum s/g segment size of a FireWire controller is
|
||||
* usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
|
||||
* be quadlet-aligned, we set the length limit to 0xffff & ~3.
|
||||
* The maximum SBP-2 data buffer size is 0xffff. We quadlet-align this
|
||||
* for compatibility with earlier versions of this driver.
|
||||
*/
|
||||
#define SBP2_MAX_SEG_SIZE 0xfffc
|
||||
|
||||
@ -1163,7 +1162,8 @@ static int sbp2_probe(struct device *dev)
|
||||
|
||||
shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
|
||||
|
||||
if (scsi_add_host(shost, &unit->device) < 0)
|
||||
if (scsi_add_host_with_dma(shost, &unit->device,
|
||||
device->card->device) < 0)
|
||||
goto fail_shost_put;
|
||||
|
||||
/* implicit directory ID */
|
||||
@ -1295,10 +1295,7 @@ static struct fw_driver sbp2_driver = {
|
||||
static void sbp2_unmap_scatterlist(struct device *card_device,
|
||||
struct sbp2_command_orb *orb)
|
||||
{
|
||||
if (scsi_sg_count(orb->cmd))
|
||||
dma_unmap_sg(card_device, scsi_sglist(orb->cmd),
|
||||
scsi_sg_count(orb->cmd),
|
||||
orb->cmd->sc_data_direction);
|
||||
scsi_dma_unmap(orb->cmd);
|
||||
|
||||
if (orb->request.misc & cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT))
|
||||
dma_unmap_single(card_device, orb->page_table_bus,
|
||||
@ -1404,9 +1401,8 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
|
||||
struct scatterlist *sg = scsi_sglist(orb->cmd);
|
||||
int i, n;
|
||||
|
||||
n = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
|
||||
orb->cmd->sc_data_direction);
|
||||
if (n == 0)
|
||||
n = scsi_dma_map(orb->cmd);
|
||||
if (n <= 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
@ -1452,8 +1448,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
|
||||
return 0;
|
||||
|
||||
fail_page_table:
|
||||
dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
|
||||
scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction);
|
||||
scsi_dma_unmap(orb->cmd);
|
||||
fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1534,7 +1529,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
|
||||
|
||||
sdev->allow_restart = 1;
|
||||
|
||||
/* SBP-2 requires quadlet alignment of the data buffers. */
|
||||
/*
|
||||
* SBP-2 does not require any alignment, but we set it anyway
|
||||
* for compatibility with earlier versions of this driver.
|
||||
*/
|
||||
blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
|
||||
|
||||
if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
|
||||
@ -1568,8 +1566,6 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
|
||||
if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
|
||||
blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
|
||||
|
||||
blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -349,6 +349,7 @@ int fw_cancel_transaction(struct fw_card *card,
|
||||
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
|
||||
int generation, int speed, unsigned long long offset,
|
||||
void *payload, size_t length);
|
||||
const char *fw_rcode_string(int rcode);
|
||||
|
||||
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
|
||||
{
|
||||
@ -406,6 +407,7 @@ struct fw_iso_buffer {
|
||||
enum dma_data_direction direction;
|
||||
struct page **pages;
|
||||
int page_count;
|
||||
int page_count_mapped;
|
||||
};
|
||||
|
||||
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
|
@ -84,7 +84,7 @@ static int pcr_modify(struct cmp_connection *c,
|
||||
return 0;
|
||||
|
||||
io_error:
|
||||
cmp_error(c, "transaction failed: %s\n", rcode_string(rcode));
|
||||
cmp_error(c, "transaction failed: %s\n", fw_rcode_string(rcode));
|
||||
return -EIO;
|
||||
|
||||
bus_reset:
|
||||
|
@ -13,32 +13,6 @@
|
||||
|
||||
#define ERROR_RETRY_DELAY_MS 5
|
||||
|
||||
/**
|
||||
* rcode_string - convert a firewire result code to a string
|
||||
* @rcode: the result
|
||||
*/
|
||||
const char *rcode_string(unsigned int rcode)
|
||||
{
|
||||
static const char *const names[] = {
|
||||
[RCODE_COMPLETE] = "complete",
|
||||
[RCODE_CONFLICT_ERROR] = "conflict error",
|
||||
[RCODE_DATA_ERROR] = "data error",
|
||||
[RCODE_TYPE_ERROR] = "type error",
|
||||
[RCODE_ADDRESS_ERROR] = "address error",
|
||||
[RCODE_SEND_ERROR] = "send error",
|
||||
[RCODE_CANCELLED] = "cancelled",
|
||||
[RCODE_BUSY] = "busy",
|
||||
[RCODE_GENERATION] = "generation",
|
||||
[RCODE_NO_ACK] = "no ack",
|
||||
};
|
||||
|
||||
if (rcode < ARRAY_SIZE(names) && names[rcode])
|
||||
return names[rcode];
|
||||
else
|
||||
return "unknown";
|
||||
}
|
||||
EXPORT_SYMBOL(rcode_string);
|
||||
|
||||
/**
|
||||
* snd_fw_transaction - send a request and wait for its completion
|
||||
* @unit: the driver's unit on the target device
|
||||
@ -71,7 +45,7 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode,
|
||||
|
||||
if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
|
||||
dev_err(&unit->device, "transaction failed: %s\n",
|
||||
rcode_string(rcode));
|
||||
fw_rcode_string(rcode));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ struct fw_unit;
|
||||
|
||||
int snd_fw_transaction(struct fw_unit *unit, int tcode,
|
||||
u64 offset, void *buffer, size_t length);
|
||||
const char *rcode_string(unsigned int rcode);
|
||||
|
||||
/* returns true if retrying the transaction would not make sense */
|
||||
static inline bool rcode_is_permanent_error(int rcode)
|
||||
|
Loading…
Reference in New Issue
Block a user