diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-card.c | 33 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 31 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-ohci.c | 11 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 26 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.c | 16 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 5 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 15 |
8 files changed, 79 insertions, 60 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 418c18f07e9..6bd91a15d5e 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -75,7 +75,7 @@ generate_config_rom(struct fw_card *card, size_t *config_rom_length) * controller, block reads to the config rom accesses the host * memory, but quadlet read access the hardware bus info block * registers. That's just crack, but it means we should make - * sure the contents of bus info block in host memory mathces + * sure the contents of bus info block in host memory matches * the version stored in the OHCI registers. */ @@ -189,6 +189,17 @@ static const char gap_count_table[] = { 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 }; +void +fw_schedule_bm_work(struct fw_card *card, unsigned long delay) +{ + int scheduled; + + fw_card_get(card); + scheduled = schedule_delayed_work(&card->work, delay); + if (!scheduled) + fw_card_put(card); +} + static void fw_card_bm_work(struct work_struct *work) { @@ -198,6 +209,8 @@ fw_card_bm_work(struct work_struct *work) unsigned long flags; int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; bool do_reset = false; + bool root_device_is_running; + bool root_device_is_cmc; __be32 lock_data[2]; spin_lock_irqsave(&card->lock, flags); @@ -206,15 +219,16 @@ fw_card_bm_work(struct work_struct *work) if (local_node == NULL) { spin_unlock_irqrestore(&card->lock, flags); - return; + goto out_put_card; } fw_node_get(local_node); fw_node_get(root_node); generation = card->generation; root_device = root_node->data; - if (root_device) - fw_device_get(root_device); + root_device_is_running = root_device && + atomic_read(&root_device->state) == FW_DEVICE_RUNNING; + root_device_is_cmc = root_device && root_device->cmc; root_id = root_node->node_id; grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); @@ -280,7 +294,7 @@ fw_card_bm_work(struct work_struct *work) * this task 100ms from now. */ spin_unlock_irqrestore(&card->lock, flags); - schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10)); + fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 10)); goto out; } @@ -297,14 +311,14 @@ fw_card_bm_work(struct work_struct *work) * config rom. In either case, pick another root. */ new_root_id = local_node->node_id; - } else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) { + } else if (!root_device_is_running) { /* * If we haven't probed this device yet, bail out now * and let's try again once that's done. */ spin_unlock_irqrestore(&card->lock, flags); goto out; - } else if (root_device->cmc) { + } else if (root_device_is_cmc) { /* * FIXME: I suppose we should set the cmstr bit in the * STATE_CLEAR register of this node, as described in @@ -351,10 +365,10 @@ fw_card_bm_work(struct work_struct *work) fw_core_initiate_bus_reset(card, 1); } out: - if (root_device) - fw_device_put(root_device); fw_node_put(root_node); fw_node_put(local_node); + out_put_card: + fw_card_put(card); } static void @@ -510,7 +524,6 @@ fw_core_remove_card(struct fw_card *card) fw_card_put(card); wait_for_completion(&card->done); - cancel_delayed_work_sync(&card->work); WARN_ON(!list_empty(&card->transaction_list)); del_timer_sync(&card->flush_timer); } diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 6b9be42c7b9..2af5a8d1e01 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -159,7 +159,8 @@ 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. + * FW_NODE_UPDATED callback is being handled or while the + * bus manager work looks at this node. */ spin_lock_irqsave(&card->lock, flags); device->node->data = NULL; @@ -617,7 +618,7 @@ static int shutdown_unit(struct device *device, void *data) */ DECLARE_RWSEM(fw_device_rwsem); -static DEFINE_IDR(fw_device_idr); +DEFINE_IDR(fw_device_idr); int fw_cdev_major; struct fw_device *fw_device_get_by_devt(dev_t devt) @@ -689,18 +690,19 @@ static void fw_device_init(struct work_struct *work) fw_notify("giving up on config rom for node id %x\n", device->node_id); if (device->node == device->card->root_node) - schedule_delayed_work(&device->card->work, 0); + fw_schedule_bm_work(device->card, 0); fw_device_release(&device->device); } return; } - err = -ENOMEM; + device_initialize(&device->device); fw_device_get(device); down_write(&fw_device_rwsem); - if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) - err = idr_get_new(&fw_device_idr, device, &minor); + err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ? + idr_get_new(&fw_device_idr, device, &minor) : + -ENOMEM; up_write(&fw_device_rwsem); if (err < 0) @@ -758,7 +760,7 @@ static void fw_device_init(struct work_struct *work) * pretty harmless. */ if (device->node == device->card->root_node) - schedule_delayed_work(&device->card->work, 0); + fw_schedule_bm_work(device->card, 0); return; @@ -892,7 +894,7 @@ static void fw_device_refresh(struct work_struct *work) fw_device_shutdown(work); out: if (node_id == card->root_node->node_id) - schedule_delayed_work(&card->work, 0); + fw_schedule_bm_work(card, 0); } void fw_node_event(struct fw_card *card, struct fw_node *node, int event) @@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) /* * Do minimal intialization of the device here, the - * rest will happen in fw_device_init(). We need the - * card and node so we can read the config rom and we - * need to do device_initialize() now so - * device_for_each_child() in FW_NODE_UPDATED is - * doesn't freak out. + * rest will happen in fw_device_init(). + * + * Attention: A lot of things, even fw_device_get(), + * cannot be done before fw_device_init() finished! + * You can basically just check device->state and + * schedule work until then, but only while holding + * card->lock. */ - device_initialize(&device->device); atomic_set(&device->state, FW_DEVICE_INITIALIZING); device->card = fw_card_get(card); device->node = fw_node_get(node); diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 42305bbac72..df51732608d 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/idr.h> #include <linux/rwsem.h> #include <asm/atomic.h> @@ -99,6 +100,7 @@ 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 struct idr fw_device_idr; extern int fw_cdev_major; /* diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 46610b09041..ab9c01e462e 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -974,6 +974,7 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet) packet->ack = RCODE_SEND_ERROR; return -1; } + packet->payload_bus = payload_bus; d[2].req_count = cpu_to_le16(packet->payload_length); d[2].data_address = cpu_to_le32(payload_bus); @@ -1025,7 +1026,6 @@ static int handle_at_packet(struct context *context, struct driver_data *driver_data; struct fw_packet *packet; struct fw_ohci *ohci = context->ohci; - dma_addr_t payload_bus; int evt; if (last->transfer_status == 0) @@ -1038,9 +1038,8 @@ static int handle_at_packet(struct context *context, /* This packet was cancelled, just continue. */ return 1; - payload_bus = le32_to_cpu(last->data_address); - if (payload_bus != 0) - dma_unmap_single(ohci->card.device, payload_bus, + if (packet->payload_bus) + dma_unmap_single(ohci->card.device, packet->payload_bus, packet->payload_length, DMA_TO_DEVICE); evt = le16_to_cpu(last->transfer_status) & 0x1f; @@ -1697,6 +1696,10 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) if (packet->ack != 0) goto out; + if (packet->payload_bus) + dma_unmap_single(ohci->card.device, packet->payload_bus, + packet->payload_length, DMA_TO_DEVICE); + log_ar_at_event('T', packet->speed, packet->header, 0x20); driver_data->packet = NULL; packet->ack = RCODE_CANCELLED; diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 97df6dac3a8..e88d5067448 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -372,6 +372,11 @@ static const struct { }, /* iPod mini */ { .firmware_revision = 0x0a2700, + .model = 0x000022, + .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, + }, + /* iPod mini */ { + .firmware_revision = 0x0a2700, .model = 0x000023, .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, }, @@ -665,17 +670,6 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) &d, sizeof(d), complete_agent_reset_write_no_wait, t); } -static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation) -{ - struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card; - unsigned long flags; - - /* serialize with comparisons of lu->generation and card->generation */ - spin_lock_irqsave(&card->lock, flags); - lu->generation = generation; - spin_unlock_irqrestore(&card->lock, flags); -} - static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) { /* @@ -879,7 +873,7 @@ static void sbp2_login(struct work_struct *work) goto out; generation = device->generation; - smp_rmb(); /* node_id must not be older than generation */ + smp_rmb(); /* node IDs must not be older than generation */ node_id = device->node_id; local_node_id = device->card->node_id; @@ -903,7 +897,8 @@ static void sbp2_login(struct work_struct *work) tgt->node_id = node_id; tgt->address_high = local_node_id << 16; - sbp2_set_generation(lu, generation); + smp_wmb(); /* node IDs must not be older than generation */ + lu->generation = generation; lu->command_block_agent_address = ((u64)(be32_to_cpu(response.command_block_agent.high) & 0xffff) @@ -1196,7 +1191,7 @@ static void sbp2_reconnect(struct work_struct *work) goto out; generation = device->generation; - smp_rmb(); /* node_id must not be older than generation */ + smp_rmb(); /* node IDs must not be older than generation */ node_id = device->node_id; local_node_id = device->card->node_id; @@ -1223,7 +1218,8 @@ static void sbp2_reconnect(struct work_struct *work) tgt->node_id = node_id; tgt->address_high = local_node_id << 16; - sbp2_set_generation(lu, generation); + smp_wmb(); /* node IDs must not be older than generation */ + lu->generation = generation; fw_notify("%s: reconnected to LUN %04x (%d retries)\n", tgt->bus_id, lu->lun, lu->retries); diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index 5e204713002..c9be6e6948c 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c @@ -355,6 +355,9 @@ report_lost_node(struct fw_card *card, { fw_node_event(card, node, FW_NODE_DESTROYED); fw_node_put(node); + + /* Topology has changed - reset bus manager retry counter */ + card->bm_retries = 0; } static void @@ -374,6 +377,9 @@ report_found_node(struct fw_card *card, } fw_node_event(card, node, FW_NODE_CREATED); + + /* Topology has changed - reset bus manager retry counter */ + card->bm_retries = 0; } void fw_destroy_nodes(struct fw_card *card) @@ -514,14 +520,6 @@ fw_core_handle_bus_reset(struct fw_card *card, spin_lock_irqsave(&card->lock, flags); - /* - * If the new topology has a different self_id_count the topology - * changed, either nodes were added or removed. In that case we - * reset the IRM reset counter. - */ - if (card->self_id_count != self_id_count) - card->bm_retries = 0; - card->node_id = node_id; /* * Update node_id before generation to prevent anybody from using @@ -530,7 +528,7 @@ fw_core_handle_bus_reset(struct fw_card *card, smp_wmb(); card->generation = generation; card->reset_jiffies = jiffies; - schedule_delayed_work(&card->work, 0); + fw_schedule_bm_work(card, 0); local_node = build_tree(card, self_ids, self_id_count); diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 022ac4fabb6..699ac041f39 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c @@ -19,6 +19,7 @@ */ #include <linux/completion.h> +#include <linux/idr.h> #include <linux/kernel.h> #include <linux/kref.h> #include <linux/module.h> @@ -207,6 +208,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, packet->speed = speed; packet->generation = generation; packet->ack = 0; + packet->payload_bus = 0; } /** @@ -581,6 +583,8 @@ fw_fill_response(struct fw_packet *response, u32 *request_header, BUG(); return; } + + response->payload_bus = 0; } EXPORT_SYMBOL(fw_fill_response); @@ -968,6 +972,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); + idr_destroy(&fw_device_idr); } module_init(fw_core_init); diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index aed7dbb17cd..c9ab12a15f6 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/spinlock_types.h> #include <linux/timer.h> +#include <linux/types.h> #include <linux/workqueue.h> #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) @@ -153,6 +154,7 @@ struct fw_packet { size_t header_length; void *payload; size_t payload_length; + dma_addr_t payload_bus; u32 timestamp; /* @@ -235,14 +237,6 @@ struct fw_card { int link_speed; int config_rom_generation; - /* - * We need to store up to 4 self ID for a maximum of 63 - * devices plus 3 words for the topology map header. - */ - int self_id_count; - u32 topology_map[252 + 3]; - u32 broadcast_channel; - spinlock_t lock; /* Take this lock when handling the lists in * this struct. */ struct fw_node *local_node; @@ -260,6 +254,9 @@ struct fw_card { struct delayed_work work; int bm_retries; int bm_generation; + + u32 broadcast_channel; + u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4]; }; static inline struct fw_card *fw_card_get(struct fw_card *card) @@ -276,6 +273,8 @@ static inline void fw_card_put(struct fw_card *card) kref_put(&card->kref, fw_card_release); } +extern void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); + /* * The iso packet format allows for an immediate header/payload part * stored in 'header' immediately after the packet info plus an |