diff options
Diffstat (limited to 'drivers/firewire')
| -rw-r--r-- | drivers/firewire/Kconfig | 50 | ||||
| -rw-r--r-- | drivers/firewire/Makefile | 2 | ||||
| -rw-r--r-- | drivers/firewire/core-card.c | 363 | ||||
| -rw-r--r-- | drivers/firewire/core-cdev.c | 991 | ||||
| -rw-r--r-- | drivers/firewire/core-device.c | 581 | ||||
| -rw-r--r-- | drivers/firewire/core-iso.c | 187 | ||||
| -rw-r--r-- | drivers/firewire/core-topology.c | 44 | ||||
| -rw-r--r-- | drivers/firewire/core-transaction.c | 569 | ||||
| -rw-r--r-- | drivers/firewire/core.h | 84 | ||||
| -rw-r--r-- | drivers/firewire/init_ohci1394_dma.c | 309 | ||||
| -rw-r--r-- | drivers/firewire/net.c | 874 | ||||
| -rw-r--r-- | drivers/firewire/nosy-user.h | 25 | ||||
| -rw-r--r-- | drivers/firewire/nosy.c | 709 | ||||
| -rw-r--r-- | drivers/firewire/nosy.h | 237 | ||||
| -rw-r--r-- | drivers/firewire/ohci.c | 2675 | ||||
| -rw-r--r-- | drivers/firewire/ohci.h | 3 | ||||
| -rw-r--r-- | drivers/firewire/sbp2.c | 498 |
17 files changed, 5836 insertions, 2365 deletions
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index a9371b36a9b..145974f9662 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -1,11 +1,9 @@ menu "IEEE 1394 (FireWire) support" - depends on PCI || BROKEN + depends on HAS_DMA + depends on PCI || COMPILE_TEST # firewire-core does not depend on PCI but is # not useful without PCI controller driver -comment "You can enable one or both FireWire driver stacks." -comment "The newer stack is recommended." - config FIREWIRE tristate "FireWire driver stack" select CRC_ITU_T @@ -22,7 +20,7 @@ config FIREWIRE config FIREWIRE_OHCI tristate "OHCI-1394 controllers" - depends on PCI && FIREWIRE + depends on PCI && FIREWIRE && MMU help Enable this driver if you have a FireWire controller based on the OHCI specification. For all practical purposes, this @@ -31,11 +29,6 @@ config FIREWIRE_OHCI To compile this driver as a module, say M here: The module will be called firewire-ohci. -config FIREWIRE_OHCI_DEBUG - bool - depends on FIREWIRE_OHCI - default y - config FIREWIRE_SBP2 tristate "Storage devices (SBP-2 protocol)" depends on FIREWIRE && SCSI @@ -52,18 +45,39 @@ config FIREWIRE_SBP2 configuration section. config FIREWIRE_NET - tristate "IP networking over 1394 (EXPERIMENTAL)" - depends on FIREWIRE && INET && EXPERIMENTAL + tristate "IP networking over 1394" + depends on FIREWIRE && INET help - This enables IPv4 over IEEE 1394, providing IP connectivity with - other implementations of RFC 2734 as found on several operating - systems. Multicast support is currently limited. - - NOTE, this driver is not stable yet! + This enables IPv4/IPv6 over IEEE 1394, providing IP connectivity + with other implementations of RFC 2734/3146 as found on several + operating systems. Multicast support is currently limited. To compile this driver as a module, say M here: The module will be called firewire-net. -source "drivers/ieee1394/Kconfig" +config FIREWIRE_NOSY + tristate "Nosy - a FireWire traffic sniffer for PCILynx cards" + depends on PCI + help + Nosy is an IEEE 1394 packet sniffer that is used for protocol + analysis and in development of IEEE 1394 drivers, applications, + or firmwares. + + This driver lets you use a Texas Instruments PCILynx 1394 to PCI + link layer controller TSB12LV21/A/B as a low-budget bus analyzer. + PCILynx is a nowadays very rare IEEE 1394 controller which is + not OHCI 1394 compliant. + + The following cards are known to be based on PCILynx or PCILynx-2: + IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2 + (PCI card), Newer Technology FireWire 2 Go (CardBus card), + Apple Power Mac G3 blue & white and G4 with PCI graphics + (onboard controller). + + To compile this driver as a module, say M here: The module will be + called nosy. Source code of a userspace interface to nosy, called + nosy-dump, can be found in tools/firewire/ of the kernel sources. + + If unsure, say N. endmenu diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index a8f9bb6d9fd..e3870d5c43d 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_FIREWIRE) += firewire-core.o obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o +obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o +obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 7083bcc1b9c..57ea7f46417 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -30,14 +30,29 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/spinlock.h> -#include <linux/timer.h> #include <linux/workqueue.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/byteorder.h> #include "core.h" +#define define_fw_printk_level(func, kern_level) \ +void func(const struct fw_card *card, const char *fmt, ...) \ +{ \ + struct va_format vaf; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.fmt = fmt; \ + vaf.va = &args; \ + printk(kern_level KBUILD_MODNAME " %s: %pV", \ + dev_name(card->device), &vaf); \ + va_end(args); \ +} +define_fw_printk_level(fw_err, KERN_ERR); +define_fw_printk_level(fw_notice, KERN_NOTICE); + int fw_compute_block_crc(__be32 *block) { int length; @@ -57,11 +72,13 @@ static LIST_HEAD(descriptor_list); static int descriptor_count; static __be32 tmp_config_rom[256]; +/* ROM header, bus info block, root dir header, capabilities = 7 quadlets */ +static size_t config_rom_length = 1 + 4 + 1 + 1; #define BIB_CRC(v) ((v) << 0) #define BIB_CRC_LENGTH(v) ((v) << 16) #define BIB_INFO_LENGTH(v) ((v) << 24) - +#define BIB_BUS_NAME 0x31333934 /* "1394" */ #define BIB_LINK_SPEED(v) ((v) << 0) #define BIB_GENERATION(v) ((v) << 4) #define BIB_MAX_ROM(v) ((v) << 8) @@ -71,9 +88,19 @@ static __be32 tmp_config_rom[256]; #define BIB_BMC ((1) << 28) #define BIB_ISC ((1) << 29) #define BIB_CMC ((1) << 30) -#define BIB_IMC ((1) << 31) +#define BIB_IRMC ((1) << 31) +#define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */ + +/* + * IEEE-1394 specifies a default SPLIT_TIMEOUT value of 800 cycles (100 ms), + * but we have to make it longer because there are many devices whose firmware + * is just too slow for that. + */ +#define DEFAULT_SPLIT_TIMEOUT (2 * 8000) + +#define CANON_OUI 0x000085 -static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom) +static void generate_config_rom(struct fw_card *card, __be32 *config_rom) { struct fw_descriptor *desc; int i, j, k, length; @@ -89,18 +116,18 @@ static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom) config_rom[0] = cpu_to_be32( BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0)); - config_rom[1] = cpu_to_be32(0x31333934); + config_rom[1] = cpu_to_be32(BIB_BUS_NAME); config_rom[2] = cpu_to_be32( BIB_LINK_SPEED(card->link_speed) | BIB_GENERATION(card->config_rom_generation++ % 14 + 2) | BIB_MAX_ROM(2) | BIB_MAX_RECEIVE(card->max_receive) | - BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC); + BIB_BMC | BIB_ISC | BIB_CMC | BIB_IRMC); config_rom[3] = cpu_to_be32(card->guid >> 32); config_rom[4] = cpu_to_be32(card->guid); /* Generate root directory. */ - config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */ + config_rom[6] = cpu_to_be32(NODE_CAPABILITIES); i = 7; j = 7 + descriptor_count; @@ -130,23 +157,30 @@ static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom) for (i = 0; i < j; i += length + 1) length = fw_compute_block_crc(config_rom + i); - return j; + WARN_ON(j != config_rom_length); } static void update_config_roms(void) { struct fw_card *card; - size_t length; list_for_each_entry (card, &card_list, link) { - length = generate_config_rom(card, tmp_config_rom); - card->driver->set_config_rom(card, tmp_config_rom, length); + generate_config_rom(card, tmp_config_rom); + card->driver->set_config_rom(card, tmp_config_rom, + config_rom_length); } } +static size_t required_space(struct fw_descriptor *desc) +{ + /* descriptor + entry into root dir + optional immediate entry */ + return desc->length + 1 + (desc->immediate > 0 ? 1 : 0); +} + int fw_core_add_descriptor(struct fw_descriptor *desc) { size_t i; + int ret; /* * Check descriptor is valid; the length of all blocks in the @@ -162,15 +196,21 @@ int fw_core_add_descriptor(struct fw_descriptor *desc) mutex_lock(&card_mutex); - list_add_tail(&desc->link, &descriptor_list); - descriptor_count++; - if (desc->immediate > 0) + if (config_rom_length + required_space(desc) > 256) { + ret = -EBUSY; + } else { + list_add_tail(&desc->link, &descriptor_list); + config_rom_length += required_space(desc); descriptor_count++; - update_config_roms(); + if (desc->immediate > 0) + descriptor_count++; + update_config_roms(); + ret = 0; + } mutex_unlock(&card_mutex); - return 0; + return ret; } EXPORT_SYMBOL(fw_core_add_descriptor); @@ -179,6 +219,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) mutex_lock(&card_mutex); list_del(&desc->link); + config_rom_length -= required_space(desc); descriptor_count--; if (desc->immediate > 0) descriptor_count--; @@ -188,17 +229,61 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) } EXPORT_SYMBOL(fw_core_remove_descriptor); +static int reset_bus(struct fw_card *card, bool short_reset) +{ + int reg = short_reset ? 5 : 1; + int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET; + + return card->driver->update_phy_reg(card, reg, 0, bit); +} + +void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) +{ + /* We don't try hard to sort out requests of long vs. short resets. */ + card->br_short = short_reset; + + /* Use an arbitrary short delay to combine multiple reset requests. */ + fw_card_get(card); + if (!queue_delayed_work(fw_workqueue, &card->br_work, + delayed ? DIV_ROUND_UP(HZ, 100) : 0)) + fw_card_put(card); +} +EXPORT_SYMBOL(fw_schedule_bus_reset); + +static void br_work(struct work_struct *work) +{ + struct fw_card *card = container_of(work, struct fw_card, br_work.work); + + /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ + if (card->reset_jiffies != 0 && + time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { + if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) + fw_card_put(card); + return; + } + + fw_send_phy_config(card, FW_PHY_CONFIG_NO_NODE_ID, card->generation, + FW_PHY_CONFIG_CURRENT_GAP_COUNT); + reset_bus(card, card->br_short); + fw_card_put(card); +} + static void allocate_broadcast_channel(struct fw_card *card, int generation) { int channel, bandwidth = 0; - fw_iso_resource_manage(card, generation, 1ULL << 31, &channel, - &bandwidth, true, card->bm_transaction_data); - if (channel == 31) { + if (!card->broadcast_channel_allocated) { + fw_iso_resource_manage(card, generation, 1ULL << 31, + &channel, &bandwidth, true); + if (channel != 31) { + fw_notice(card, "failed to allocate broadcast channel\n"); + return; + } card->broadcast_channel_allocated = true; - device_for_each_child(card->device, (void *)(long)generation, - fw_device_set_broadcast_channel); } + + device_for_each_child(card->device, (void *)(long)generation, + fw_device_set_broadcast_channel); } static const char gap_count_table[] = { @@ -208,43 +293,57 @@ static const char gap_count_table[] = { void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) { fw_card_get(card); - if (!schedule_delayed_work(&card->work, delay)) + if (!schedule_delayed_work(&card->bm_work, delay)) fw_card_put(card); } -static void fw_card_bm_work(struct work_struct *work) +static void bm_work(struct work_struct *work) { - struct fw_card *card = container_of(work, struct fw_card, work.work); - struct fw_device *root_device; + struct fw_card *card = container_of(work, struct fw_card, bm_work.work); + struct fw_device *root_device, *irm_device; struct fw_node *root_node; - unsigned long flags; - int root_id, new_root_id, irm_id, local_id; + int root_id, new_root_id, irm_id, bm_id, local_id; int gap_count, generation, grace, rcode; bool do_reset = false; bool root_device_is_running; bool root_device_is_cmc; + bool irm_is_1394_1995_only; + bool keep_this_irm; + __be32 transaction_data[2]; - spin_lock_irqsave(&card->lock, flags); + spin_lock_irq(&card->lock); if (card->local_node == NULL) { - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); goto out_put_card; } generation = card->generation; + root_node = card->root_node; fw_node_get(root_node); root_device = root_node->data; root_device_is_running = root_device && atomic_read(&root_device->state) == FW_DEVICE_RUNNING; root_device_is_cmc = root_device && root_device->cmc; + + irm_device = card->irm_node->data; + irm_is_1394_1995_only = irm_device && irm_device->config_rom && + (irm_device->config_rom[2] & 0x000000f0) == 0; + + /* Canon MV5i works unreliably if it is not root node. */ + keep_this_irm = irm_device && irm_device->config_rom && + irm_device->config_rom[3] >> 8 == CANON_OUI; + root_id = root_node->node_id; irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; - grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8)); + grace = time_after64(get_jiffies_64(), + card->reset_jiffies + DIV_ROUND_UP(HZ, 8)); - if (is_next_generation(generation, card->bm_generation) || + if ((is_next_generation(generation, card->bm_generation) && + !card->bm_abdicate) || (card->bm_generation != generation && grace)) { /* * This first step is to figure out who is IRM and @@ -260,29 +359,41 @@ static void fw_card_bm_work(struct work_struct *work) if (!card->irm_node->link_on) { new_root_id = local_id; - fw_notify("IRM has link off, making local node (%02x) root.\n", - new_root_id); + fw_notice(card, "%s, making local node (%02x) root\n", + "IRM has link off", new_root_id); + goto pick_me; + } + + if (irm_is_1394_1995_only && !keep_this_irm) { + new_root_id = local_id; + fw_notice(card, "%s, making local node (%02x) root\n", + "IRM is not 1394a compliant", new_root_id); goto pick_me; } - card->bm_transaction_data[0] = cpu_to_be32(0x3f); - card->bm_transaction_data[1] = cpu_to_be32(local_id); + transaction_data[0] = cpu_to_be32(0x3f); + transaction_data[1] = cpu_to_be32(local_id); - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - card->bm_transaction_data, - sizeof(card->bm_transaction_data)); + transaction_data, 8); if (rcode == RCODE_GENERATION) /* Another bus reset, BM work has been rescheduled. */ goto out; - if (rcode == RCODE_COMPLETE && - card->bm_transaction_data[0] != cpu_to_be32(0x3f)) { + bm_id = be32_to_cpu(transaction_data[0]); + + spin_lock_irq(&card->lock); + if (rcode == RCODE_COMPLETE && generation == card->generation) + card->bm_node_id = + bm_id == 0x3f ? local_id : 0xffc0 | bm_id; + spin_unlock_irq(&card->lock); + if (rcode == RCODE_COMPLETE && bm_id != 0x3f) { /* Somebody else is BM. Only act as IRM. */ if (local_id == irm_id) allocate_broadcast_channel(card, generation); @@ -290,9 +401,19 @@ static void fw_card_bm_work(struct work_struct *work) goto out; } - spin_lock_irqsave(&card->lock, flags); + if (rcode == RCODE_SEND_ERROR) { + /* + * We have been unable to send the lock request due to + * some local problem. Let's try again later and hope + * that the problem has gone away by then. + */ + fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8)); + goto out; + } + + spin_lock_irq(&card->lock); - if (rcode != RCODE_COMPLETE) { + if (rcode != RCODE_COMPLETE && !keep_this_irm) { /* * The lock request failed, maybe the IRM * isn't really IRM capable after all. Let's @@ -300,8 +421,8 @@ static void fw_card_bm_work(struct work_struct *work) * root, and thus, IRM. */ new_root_id = local_id; - fw_notify("BM lock failed, making local node (%02x) root.\n", - 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) { @@ -309,7 +430,7 @@ static void fw_card_bm_work(struct work_struct *work) * We weren't BM in the last generation, and the last * bus reset is less than 125ms ago. Reschedule this job. */ - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 8)); goto out; } @@ -332,14 +453,12 @@ static void fw_card_bm_work(struct work_struct *work) * 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); + spin_unlock_irq(&card->lock); goto out; } 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 - * 1394-1995, 8.4.2.6. Also, send out a force root - * packet for this node. + * We will send out a force root packet for this + * node as part of the gap count optimization. */ new_root_id = root_id; } else { @@ -372,32 +491,39 @@ static void fw_card_bm_work(struct work_struct *work) (card->gap_count != gap_count || new_root_id != root_id)) do_reset = true; - spin_unlock_irqrestore(&card->lock, flags); + spin_unlock_irq(&card->lock); if (do_reset) { - fw_notify("phy config: card %d, new root=%x, gap_count=%d\n", - card->index, new_root_id, gap_count); + fw_notice(card, "phy config: new root=%x, gap_count=%d\n", + new_root_id, gap_count); fw_send_phy_config(card, new_root_id, generation, gap_count); - fw_core_initiate_bus_reset(card, 1); + reset_bus(card, true); /* Will allocate broadcast channel after the reset. */ - } else { - if (local_id == irm_id) - allocate_broadcast_channel(card, generation); + goto out; } + if (root_device_is_cmc) { + /* + * Make sure that the cycle master sends cycle start packets. + */ + transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR); + rcode = fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST, + root_id, generation, SCODE_100, + CSR_REGISTER_BASE + CSR_STATE_SET, + transaction_data, 4); + if (rcode == RCODE_GENERATION) + goto out; + } + + if (local_id == irm_id) + allocate_broadcast_channel(card, generation); + out: fw_node_put(root_node); out_put_card: fw_card_put(card); } -static void flush_timer_callback(unsigned long data) -{ - struct fw_card *card = (struct fw_card *)data; - - fw_flush_transactions(card); -} - void fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver, struct device *device) @@ -409,26 +535,30 @@ void fw_card_initialize(struct fw_card *card, card->device = device; card->current_tlabel = 0; card->tlabel_mask = 0; + card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000; + card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19; + card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT; + card->split_timeout_jiffies = + DIV_ROUND_UP(DEFAULT_SPLIT_TIMEOUT * HZ, 8000); card->color = 0; card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; kref_init(&card->kref); init_completion(&card->done); INIT_LIST_HEAD(&card->transaction_list); + INIT_LIST_HEAD(&card->phy_receiver_list); spin_lock_init(&card->lock); - setup_timer(&card->flush_timer, - flush_timer_callback, (unsigned long)card); card->local_node = NULL; - INIT_DELAYED_WORK(&card->work, fw_card_bm_work); + INIT_DELAYED_WORK(&card->br_work, br_work); + INIT_DELAYED_WORK(&card->bm_work, bm_work); } EXPORT_SYMBOL(fw_card_initialize); int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid) { - size_t length; int ret; card->max_receive = max_receive; @@ -437,8 +567,8 @@ int fw_card_add(struct fw_card *card, mutex_lock(&card_mutex); - length = generate_config_rom(card, tmp_config_rom); - ret = card->driver->enable(card, tmp_config_rom, length); + generate_config_rom(card, tmp_config_rom); + ret = card->driver->enable(card, tmp_config_rom, config_rom_length); if (ret == 0) list_add_tail(&card->link, &card_list); @@ -448,20 +578,22 @@ int fw_card_add(struct fw_card *card, } EXPORT_SYMBOL(fw_card_add); - /* * The next few functions implement a dummy driver that is used once a card * driver shuts down an fw_card. This allows the driver to cleanly unload, * as all IO to the card will be handled (and failed) by the dummy driver * instead of calling into the module. Only functions for iso context * shutdown still need to be provided by the card driver. + * + * .read/write_csr() should never be called anymore after the dummy driver + * was bound since they are only used within request handler context. + * .set_config_rom() is never called since the card is taken out of card_list + * before switching to the dummy driver. */ -static int dummy_enable(struct fw_card *card, - const __be32 *config_rom, size_t length) +static int dummy_read_phy_reg(struct fw_card *card, int address) { - BUG(); - return -1; + return -ENODEV; } static int dummy_update_phy_reg(struct fw_card *card, int address, @@ -470,25 +602,14 @@ static int dummy_update_phy_reg(struct fw_card *card, int address, return -ENODEV; } -static int dummy_set_config_rom(struct fw_card *card, - const __be32 *config_rom, size_t length) -{ - /* - * We take the card out of card_list before setting the dummy - * driver, so this should never get called. - */ - BUG(); - return -1; -} - static void dummy_send_request(struct fw_card *card, struct fw_packet *packet) { - packet->callback(packet, card, -ENODEV); + packet->callback(packet, card, RCODE_CANCELLED); } static void dummy_send_response(struct fw_card *card, struct fw_packet *packet) { - packet->callback(packet, card, -ENODEV); + packet->callback(packet, card, RCODE_CANCELLED); } static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet) @@ -502,14 +623,51 @@ static int dummy_enable_phys_dma(struct fw_card *card, return -ENODEV; } +static struct fw_iso_context *dummy_allocate_iso_context(struct fw_card *card, + int type, int channel, size_t header_size) +{ + return ERR_PTR(-ENODEV); +} + +static int dummy_start_iso(struct fw_iso_context *ctx, + s32 cycle, u32 sync, u32 tags) +{ + return -ENODEV; +} + +static int dummy_set_iso_channels(struct fw_iso_context *ctx, u64 *channels) +{ + return -ENODEV; +} + +static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p, + struct fw_iso_buffer *buffer, unsigned long payload) +{ + return -ENODEV; +} + +static void dummy_flush_queue_iso(struct fw_iso_context *ctx) +{ +} + +static int dummy_flush_iso_completions(struct fw_iso_context *ctx) +{ + return -ENODEV; +} + static const struct fw_card_driver dummy_driver_template = { - .enable = dummy_enable, - .update_phy_reg = dummy_update_phy_reg, - .set_config_rom = dummy_set_config_rom, - .send_request = dummy_send_request, - .cancel_packet = dummy_cancel_packet, - .send_response = dummy_send_response, - .enable_phys_dma = dummy_enable_phys_dma, + .read_phy_reg = dummy_read_phy_reg, + .update_phy_reg = dummy_update_phy_reg, + .send_request = dummy_send_request, + .send_response = dummy_send_response, + .cancel_packet = dummy_cancel_packet, + .enable_phys_dma = dummy_enable_phys_dma, + .allocate_iso_context = dummy_allocate_iso_context, + .start_iso = dummy_start_iso, + .set_iso_channels = dummy_set_iso_channels, + .queue_iso = dummy_queue_iso, + .flush_queue_iso = dummy_flush_queue_iso, + .flush_iso_completions = dummy_flush_iso_completions, }; void fw_card_release(struct kref *kref) @@ -518,6 +676,7 @@ void fw_card_release(struct kref *kref) complete(&card->done); } +EXPORT_SYMBOL_GPL(fw_card_release); void fw_core_remove_card(struct fw_card *card) { @@ -525,7 +684,7 @@ void fw_core_remove_card(struct fw_card *card) card->driver->update_phy_reg(card, 4, PHY_LINK_ACTIVE | PHY_CONTENDER, 0); - fw_core_initiate_bus_reset(card, 1); + fw_schedule_bus_reset(card, false, true); mutex_lock(&card_mutex); list_del_init(&card->link); @@ -543,15 +702,5 @@ void fw_core_remove_card(struct fw_card *card) wait_for_completion(&card->done); WARN_ON(!list_empty(&card->transaction_list)); - del_timer_sync(&card->flush_timer); } EXPORT_SYMBOL(fw_core_remove_card); - -int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset) -{ - int reg = short_reset ? 5 : 1; - int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET; - - return card->driver->update_phy_reg(card, reg, 0, bit); -} -EXPORT_SYMBOL(fw_core_initiate_bus_reset); diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index e6d63849e78..d7d5c8af92b 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -18,13 +18,16 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/bug.h> #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> #include <linux/idr.h> +#include <linux/irqflags.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/kref.h> @@ -32,19 +35,27 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/poll.h> -#include <linux/preempt.h> -#include <linux/sched.h> +#include <linux/sched.h> /* required for linux/wait.h */ +#include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/string.h> #include <linux/time.h> #include <linux/uaccess.h> #include <linux/vmalloc.h> #include <linux/wait.h> #include <linux/workqueue.h> -#include <asm/system.h> #include "core.h" +/* + * ABI version history is documented in linux/firewire-cdev.h. + */ +#define FW_CDEV_KERNEL_VERSION 5 +#define FW_CDEV_VERSION_EVENT_REQUEST2 4 +#define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 +#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5 + struct client { u32 version; struct fw_device *device; @@ -54,12 +65,17 @@ struct client { struct idr resource_idr; struct list_head event_list; wait_queue_head_t wait; + wait_queue_head_t tx_flush_wait; u64 bus_reset_closure; struct fw_iso_context *iso_context; 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; struct list_head link; struct kref kref; @@ -105,6 +121,7 @@ struct outbound_transaction_resource { struct inbound_transaction_resource { struct client_resource resource; + struct fw_card *card; struct fw_request *request; void *data; size_t length; @@ -126,7 +143,6 @@ struct iso_resource { int generation; u64 channels; s32 bandwidth; - __be32 transaction_data[2]; struct iso_resource_event *e_alloc, *e_dealloc; }; @@ -135,7 +151,7 @@ static void release_iso_resource(struct client *, struct client_resource *); static void schedule_iso_resource(struct iso_resource *r, unsigned long delay) { client_get(r->client); - if (!schedule_delayed_work(&r->work, delay)) + if (!queue_delayed_work(fw_workqueue, &r->work, delay)) client_put(r->client); } @@ -169,7 +185,10 @@ struct outbound_transaction_event { struct inbound_transaction_event { struct event event; - struct fw_cdev_event_request request; + union { + struct fw_cdev_event_request request; + struct fw_cdev_event_request2 request2; + } req; }; struct iso_interrupt_event { @@ -177,20 +196,55 @@ struct iso_interrupt_event { struct fw_cdev_event_iso_interrupt interrupt; }; +struct iso_interrupt_mc_event { + struct event event; + struct fw_cdev_event_iso_interrupt_mc interrupt; +}; + struct iso_resource_event { struct event event; struct fw_cdev_event_iso_resource iso_resource; }; -static inline void __user *u64_to_uptr(__u64 value) +struct outbound_phy_packet_event { + struct event event; + struct client *client; + struct fw_packet p; + struct fw_cdev_event_phy_packet phy_packet; +}; + +struct inbound_phy_packet_event { + struct event event; + struct fw_cdev_event_phy_packet phy_packet; +}; + +#ifdef CONFIG_COMPAT +static void __user *u64_to_uptr(u64 value) +{ + if (is_compat_task()) + return compat_ptr(value); + else + return (void __user *)(unsigned long)value; +} + +static u64 uptr_to_u64(void __user *ptr) +{ + if (is_compat_task()) + return ptr_to_compat(ptr); + else + return (u64)(unsigned long)ptr; +} +#else +static inline void __user *u64_to_uptr(u64 value) { return (void __user *)(unsigned long)value; } -static inline __u64 uptr_to_u64(void __user *ptr) +static inline u64 uptr_to_u64(void __user *ptr) { - return (__u64)(unsigned long)ptr; + return (u64)(unsigned long)ptr; } +#endif /* CONFIG_COMPAT */ static int fw_device_op_open(struct inode *inode, struct file *file) { @@ -217,15 +271,14 @@ static int fw_device_op_open(struct inode *inode, struct file *file) idr_init(&client->resource_idr); INIT_LIST_HEAD(&client->event_list); init_waitqueue_head(&client->wait); + init_waitqueue_head(&client->tx_flush_wait); + INIT_LIST_HEAD(&client->phy_receiver_link); + INIT_LIST_HEAD(&client->link); kref_init(&client->kref); file->private_data = client; - mutex_lock(&device->client_list_mutex); - list_add_tail(&client->link, &device->client_list); - mutex_unlock(&device->client_list_mutex); - - return 0; + return nonseekable_open(inode, file); } static void queue_event(struct client *client, struct event *event, @@ -307,7 +360,7 @@ static void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, event->generation = client->device->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->bm_node_id = card->bm_node_id; event->irm_node_id = card->irm_node->node_id; event->root_node_id = card->root_node->node_id; @@ -337,10 +390,8 @@ static void queue_bus_reset_event(struct client *client) struct bus_reset_event *e; e = kzalloc(sizeof(*e), GFP_KERNEL); - if (e == NULL) { - fw_notify("Out of memory when allocating bus reset event\n"); + if (e == NULL) return; - } fill_bus_reset_event(&e->reset, client); @@ -367,69 +418,96 @@ void fw_device_cdev_remove(struct fw_device *device) for_each_client(device, wake_up_client); } -static int ioctl_get_info(struct client *client, void *buffer) +union ioctl_arg { + struct fw_cdev_get_info get_info; + struct fw_cdev_send_request send_request; + struct fw_cdev_allocate allocate; + struct fw_cdev_deallocate deallocate; + struct fw_cdev_send_response send_response; + struct fw_cdev_initiate_bus_reset initiate_bus_reset; + struct fw_cdev_add_descriptor add_descriptor; + struct fw_cdev_remove_descriptor remove_descriptor; + struct fw_cdev_create_iso_context create_iso_context; + struct fw_cdev_queue_iso queue_iso; + struct fw_cdev_start_iso start_iso; + struct fw_cdev_stop_iso stop_iso; + struct fw_cdev_get_cycle_timer get_cycle_timer; + struct fw_cdev_allocate_iso_resource allocate_iso_resource; + struct fw_cdev_send_stream_packet send_stream_packet; + struct fw_cdev_get_cycle_timer2 get_cycle_timer2; + struct fw_cdev_send_phy_packet send_phy_packet; + struct fw_cdev_receive_phy_packets receive_phy_packets; + struct fw_cdev_set_iso_channels set_iso_channels; + struct fw_cdev_flush_iso flush_iso; +}; + +static int ioctl_get_info(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_get_info *get_info = buffer; + struct fw_cdev_get_info *a = &arg->get_info; struct fw_cdev_event_bus_reset bus_reset; unsigned long ret = 0; - client->version = get_info->version; - get_info->version = FW_CDEV_VERSION; - get_info->card = client->device->card->index; + client->version = a->version; + a->version = FW_CDEV_KERNEL_VERSION; + a->card = client->device->card->index; 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; + if (a->rom != 0) { + size_t want = a->rom_length; size_t have = client->device->config_rom_length * 4; - ret = copy_to_user(uptr, client->device->config_rom, - min(want, have)); + ret = copy_to_user(u64_to_uptr(a->rom), + client->device->config_rom, min(want, have)); } - get_info->rom_length = client->device->config_rom_length * 4; + a->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); + mutex_lock(&client->device->client_list_mutex); + client->bus_reset_closure = a->bus_reset_closure; + if (a->bus_reset != 0) { fill_bus_reset_event(&bus_reset, client); - if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) - return -EFAULT; + /* unaligned size of bus_reset is 36 bytes */ + ret = copy_to_user(u64_to_uptr(a->bus_reset), &bus_reset, 36); } + if (ret == 0 && list_empty(&client->link)) + list_add_tail(&client->link, &client->device->client_list); - return 0; + mutex_unlock(&client->device->client_list_mutex); + + return ret ? -EFAULT : 0; } static int add_client_resource(struct client *client, struct client_resource *resource, gfp_t gfp_mask) { + bool preload = !!(gfp_mask & __GFP_WAIT); unsigned long flags; int ret; - retry: - if (idr_pre_get(&client->resource_idr, gfp_mask) == 0) - return -ENOMEM; - + if (preload) + idr_preload(gfp_mask); spin_lock_irqsave(&client->lock, flags); + if (client->in_shutdown) ret = -ECANCELED; else - ret = idr_get_new(&client->resource_idr, resource, - &resource->handle); + ret = idr_alloc(&client->resource_idr, resource, 0, 0, + GFP_NOWAIT); if (ret >= 0) { + resource->handle = ret; client_get(client); schedule_if_iso_resource(resource); } - spin_unlock_irqrestore(&client->lock, flags); - if (ret == -EAGAIN) - goto retry; + spin_unlock_irqrestore(&client->lock, flags); + if (preload) + idr_preload_end(); return ret < 0 ? ret : 0; } @@ -465,10 +543,6 @@ static int release_client_resource(struct client *client, u32 handle, static void release_transaction(struct client *client, struct client_resource *resource) { - struct outbound_transaction_resource *r = container_of(resource, - struct outbound_transaction_resource, resource); - - fw_cancel_transaction(client->device->card, &r->transaction); } static void complete_transaction(struct fw_card *card, int rcode, @@ -485,22 +559,9 @@ static void complete_transaction(struct fw_card *card, int rcode, memcpy(rsp->data, payload, rsp->length); spin_lock_irqsave(&client->lock, flags); - /* - * 1. If called while in shutdown, the idr tree must be left untouched. - * The idr handle will be removed and the client reference will be - * dropped later. - * 2. If the call chain was release_client_resource -> - * release_transaction -> complete_transaction (instead of a normal - * conclusion of the transaction), i.e. if this resource was already - * unregistered from the idr, the client reference will be dropped - * by release_client_resource and we must not drop it here. - */ - if (!client->in_shutdown && - idr_find(&client->resource_idr, e->r.resource.handle)) { - idr_remove(&client->resource_idr, e->r.resource.handle); - /* Drop the idr's reference */ - client_put(client); - } + idr_remove(&client->resource_idr, e->r.resource.handle); + if (client->in_shutdown) + wake_up(&client->tx_flush_wait); spin_unlock_irqrestore(&client->lock, flags); rsp->type = FW_CDEV_EVENT_RESPONSE; @@ -520,7 +581,7 @@ static void complete_transaction(struct fw_card *card, int rcode, queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, NULL, 0); - /* Drop the transaction callback's reference */ + /* Drop the idr's reference */ client_put(client); } @@ -535,6 +596,10 @@ static int init_request(struct client *client, (request->length > 4096 || request->length > 512 << speed)) return -EIO; + if (request->tcode == TCODE_WRITE_QUADLET_REQUEST && + request->length < 4) + return -EINVAL; + e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); if (e == NULL) return -ENOMEM; @@ -555,9 +620,6 @@ static int init_request(struct client *client, if (ret < 0) goto failed; - /* Get a reference for the transaction callback */ - client_get(client); - fw_send_request(client->device->card, &e->r.transaction, request->tcode, destination_id, request->generation, speed, request->offset, e->response.data, @@ -570,11 +632,9 @@ static int init_request(struct client *client, return ret; } -static int ioctl_send_request(struct client *client, void *buffer) +static int ioctl_send_request(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_send_request *request = buffer; - - switch (request->tcode) { + switch (arg->send_request.tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: case TCODE_READ_QUADLET_REQUEST: @@ -591,63 +651,114 @@ static int ioctl_send_request(struct client *client, void *buffer) return -EINVAL; } - return init_request(client, request, client->device->node_id, + return init_request(client, &arg->send_request, client->device->node_id, client->device->max_speed); } +static inline bool is_fcp_request(struct fw_request *request) +{ + return request == NULL; +} + static void release_request(struct client *client, struct client_resource *resource) { struct inbound_transaction_resource *r = container_of(resource, struct inbound_transaction_resource, resource); - if (r->request) - fw_send_response(client->device->card, r->request, - RCODE_CONFLICT_ERROR); + if (is_fcp_request(r->request)) + kfree(r->data); + else + fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR); + + fw_card_put(r->card); kfree(r); } static void handle_request(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, - int generation, int speed, - unsigned long long offset, + int generation, unsigned long long offset, void *payload, size_t length, void *callback_data) { struct address_handler_resource *handler = callback_data; struct inbound_transaction_resource *r; struct inbound_transaction_event *e; + size_t event_size0; + void *fcp_frame = NULL; int ret; + /* card may be different from handler->client->device->card */ + fw_card_get(card); + r = kmalloc(sizeof(*r), GFP_ATOMIC); e = kmalloc(sizeof(*e), GFP_ATOMIC); if (r == NULL || e == NULL) goto failed; + r->card = card; r->request = request; r->data = payload; r->length = length; + if (is_fcp_request(request)) { + /* + * FIXME: Let core-transaction.c manage a + * single reference-counted copy? + */ + fcp_frame = kmemdup(payload, length, GFP_ATOMIC); + if (fcp_frame == NULL) + goto failed; + + r->data = fcp_frame; + } + r->resource.release = release_request; ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); if (ret < 0) goto failed; - e->request.type = FW_CDEV_EVENT_REQUEST; - e->request.tcode = tcode; - e->request.offset = offset; - e->request.length = length; - e->request.handle = r->resource.handle; - e->request.closure = handler->closure; + if (handler->client->version < FW_CDEV_VERSION_EVENT_REQUEST2) { + struct fw_cdev_event_request *req = &e->req.request; + + if (tcode & 0x10) + tcode = TCODE_LOCK_REQUEST; + + req->type = FW_CDEV_EVENT_REQUEST; + req->tcode = tcode; + req->offset = offset; + req->length = length; + req->handle = r->resource.handle; + req->closure = handler->closure; + event_size0 = sizeof(*req); + } else { + struct fw_cdev_event_request2 *req = &e->req.request2; + + req->type = FW_CDEV_EVENT_REQUEST2; + req->tcode = tcode; + req->offset = offset; + req->source_node_id = source; + req->destination_node_id = destination; + req->card = card->index; + req->generation = generation; + req->length = length; + req->handle = r->resource.handle; + req->closure = handler->closure; + event_size0 = sizeof(*req); + } queue_event(handler->client, &e->event, - &e->request, sizeof(e->request), payload, length); + &e->req, event_size0, r->data, length); return; failed: kfree(r); kfree(e); - if (request) + kfree(fcp_frame); + + if (!is_fcp_request(request)) fw_send_response(card, request, RCODE_CONFLICT_ERROR); + + fw_card_put(card); } static void release_address_handler(struct client *client, @@ -660,9 +771,9 @@ static void release_address_handler(struct client *client, kfree(r); } -static int ioctl_allocate(struct client *client, void *buffer) +static int ioctl_allocate(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_allocate *request = buffer; + struct fw_cdev_allocate *a = &arg->allocate; struct address_handler_resource *r; struct fw_address_region region; int ret; @@ -671,19 +782,24 @@ static int ioctl_allocate(struct client *client, void *buffer) if (r == NULL) return -ENOMEM; - region.start = request->offset; - region.end = request->offset + request->length; - r->handler.length = request->length; + region.start = a->offset; + if (client->version < FW_CDEV_VERSION_ALLOCATE_REGION_END) + region.end = a->offset + a->length; + else + region.end = a->region_end; + + r->handler.length = a->length; r->handler.address_callback = handle_request; - r->handler.callback_data = r; - r->closure = request->closure; - r->client = client; + r->handler.callback_data = r; + r->closure = a->closure; + r->client = client; ret = fw_core_add_address_handler(&r->handler, ®ion); if (ret < 0) { kfree(r); return ret; } + a->offset = r->handler.offset; r->resource.release = release_address_handler; ret = add_client_resource(client, &r->resource, GFP_KERNEL); @@ -691,58 +807,56 @@ static int ioctl_allocate(struct client *client, void *buffer) release_address_handler(client, &r->resource); return ret; } - request->handle = r->resource.handle; + a->handle = r->resource.handle; return 0; } -static int ioctl_deallocate(struct client *client, void *buffer) +static int ioctl_deallocate(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_deallocate *request = buffer; - - return release_client_resource(client, request->handle, + return release_client_resource(client, arg->deallocate.handle, release_address_handler, NULL); } -static int ioctl_send_response(struct client *client, void *buffer) +static int ioctl_send_response(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_send_response *request = buffer; + struct fw_cdev_send_response *a = &arg->send_response; struct client_resource *resource; struct inbound_transaction_resource *r; int ret = 0; - if (release_client_resource(client, request->handle, + if (release_client_resource(client, a->handle, release_request, &resource) < 0) return -EINVAL; r = container_of(resource, struct inbound_transaction_resource, resource); - if (r->request) { - if (request->length < r->length) - r->length = request->length; - if (copy_from_user(r->data, u64_to_uptr(request->data), - r->length)) { - ret = -EFAULT; - kfree(r->request); - goto out; - } - fw_send_response(client->device->card, r->request, - request->rcode); + if (is_fcp_request(r->request)) + goto out; + + if (a->length != fw_get_response_length(r->request)) { + ret = -EINVAL; + kfree(r->request); + goto out; + } + if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) { + ret = -EFAULT; + kfree(r->request); + goto out; } + fw_send_response(r->card, r->request, a->rcode); out: + fw_card_put(r->card); kfree(r); return ret; } -static int ioctl_initiate_bus_reset(struct client *client, void *buffer) +static int ioctl_initiate_bus_reset(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_initiate_bus_reset *request = buffer; - int short_reset; - - short_reset = (request->type == FW_CDEV_SHORT_RESET); - - return fw_core_initiate_bus_reset(client->device->card, short_reset); + fw_schedule_bus_reset(client->device->card, true, + arg->initiate_bus_reset.type == FW_CDEV_SHORT_RESET); + return 0; } static void release_descriptor(struct client *client, @@ -755,9 +869,9 @@ static void release_descriptor(struct client *client, kfree(r); } -static int ioctl_add_descriptor(struct client *client, void *buffer) +static int ioctl_add_descriptor(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_add_descriptor *request = buffer; + struct fw_cdev_add_descriptor *a = &arg->add_descriptor; struct descriptor_resource *r; int ret; @@ -765,22 +879,21 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) if (!client->device->is_local) return -ENOSYS; - if (request->length > 256) + if (a->length > 256) return -EINVAL; - r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL); + r = kmalloc(sizeof(*r) + a->length * 4, GFP_KERNEL); if (r == NULL) return -ENOMEM; - if (copy_from_user(r->data, - u64_to_uptr(request->data), request->length * 4)) { + if (copy_from_user(r->data, u64_to_uptr(a->data), a->length * 4)) { ret = -EFAULT; goto failed; } - r->descriptor.length = request->length; - r->descriptor.immediate = request->immediate; - r->descriptor.key = request->key; + r->descriptor.length = a->length; + r->descriptor.immediate = a->immediate; + r->descriptor.key = a->key; r->descriptor.data = r->data; ret = fw_core_add_descriptor(&r->descriptor); @@ -793,7 +906,7 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) fw_core_remove_descriptor(&r->descriptor); goto failed; } - request->handle = r->resource.handle; + a->handle = r->resource.handle; return 0; failed: @@ -802,11 +915,9 @@ static int ioctl_add_descriptor(struct client *client, void *buffer) return ret; } -static int ioctl_remove_descriptor(struct client *client, void *buffer) +static int ioctl_remove_descriptor(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_remove_descriptor *request = buffer; - - return release_client_resource(client, request->handle, + return release_client_resource(client, arg->remove_descriptor.handle, release_descriptor, NULL); } @@ -816,7 +927,7 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, struct client *client = data; struct iso_interrupt_event *e; - e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC); + e = kmalloc(sizeof(*e) + header_length, GFP_ATOMIC); if (e == NULL) return; @@ -829,53 +940,115 @@ static void iso_callback(struct fw_iso_context *context, u32 cycle, sizeof(e->interrupt) + header_length, NULL, 0); } -static int ioctl_create_iso_context(struct client *client, void *buffer) +static void iso_mc_callback(struct fw_iso_context *context, + dma_addr_t completed, void *data) { - struct fw_cdev_create_iso_context *request = buffer; - struct fw_iso_context *context; + struct client *client = data; + struct iso_interrupt_mc_event *e; - /* We only support one context at this time. */ - if (client->iso_context != NULL) - return -EBUSY; + e = kmalloc(sizeof(*e), GFP_ATOMIC); + if (e == NULL) + return; - if (request->channel > 63) - return -EINVAL; + e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT_MULTICHANNEL; + e->interrupt.closure = client->iso_closure; + e->interrupt.completed = fw_iso_buffer_lookup(&client->buffer, + completed); + queue_event(client, &e->event, &e->interrupt, + sizeof(e->interrupt), NULL, 0); +} - switch (request->type) { - case FW_ISO_CONTEXT_RECEIVE: - if (request->header_size < 4 || (request->header_size & 3)) +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 || + FW_CDEV_ISO_CONTEXT_RECEIVE_MULTICHANNEL != + FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL); + + switch (a->type) { + case FW_ISO_CONTEXT_TRANSMIT: + if (a->speed > SCODE_3200 || a->channel > 63) return -EINVAL; + cb = iso_callback; break; - case FW_ISO_CONTEXT_TRANSMIT: - if (request->speed > SCODE_3200) + case FW_ISO_CONTEXT_RECEIVE: + if (a->header_size < 4 || (a->header_size & 3) || + a->channel > 63) return -EINVAL; + cb = iso_callback; + break; + + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + cb = (fw_iso_callback_t)iso_mc_callback; break; default: return -EINVAL; } - context = fw_iso_context_create(client->device->card, - request->type, - request->channel, - request->speed, - request->header_size, - iso_callback, client); + context = fw_iso_context_create(client->device->card, a->type, + a->channel, a->speed, a->header_size, cb, client); if (IS_ERR(context)) return PTR_ERR(context); + if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW) + context->drop_overflow_headers = true; + + /* We only support one context at this time. */ + spin_lock_irq(&client->lock); + if (client->iso_context != NULL) { + spin_unlock_irq(&client->lock); + fw_iso_context_destroy(context); - client->iso_closure = request->closure; + 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); - /* We only support one context at this time. */ - request->handle = 0; + a->handle = 0; return 0; } +static int ioctl_set_iso_channels(struct client *client, union ioctl_arg *arg) +{ + struct fw_cdev_set_iso_channels *a = &arg->set_iso_channels; + struct fw_iso_context *ctx = client->iso_context; + + if (ctx == NULL || a->handle != 0) + return -EINVAL; + + return fw_iso_context_set_channels(ctx, &a->channels); +} + /* Macros for decoding the iso packet control header. */ #define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff) #define GET_INTERRUPT(v) (((v) >> 16) & 0x01) @@ -884,12 +1057,12 @@ static int ioctl_create_iso_context(struct client *client, void *buffer) #define GET_SY(v) (((v) >> 20) & 0x0f) #define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff) -static int ioctl_queue_iso(struct client *client, void *buffer) +static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_queue_iso *request = buffer; + struct fw_cdev_queue_iso *a = &arg->queue_iso; struct fw_cdev_iso_packet __user *p, *end, *next; struct fw_iso_context *ctx = client->iso_context; - unsigned long payload, buffer_end, header_length; + unsigned long payload, buffer_end, transmit_header_bytes = 0; u32 control; int count; struct { @@ -897,7 +1070,7 @@ static int ioctl_queue_iso(struct client *client, void *buffer) u8 header[256]; } u; - if (ctx == NULL || request->handle != 0) + if (ctx == NULL || a->handle != 0) return -EINVAL; /* @@ -907,23 +1080,24 @@ static int ioctl_queue_iso(struct client *client, void *buffer) * set them both to 0, which will still let packets with * payload_length == 0 through. In other words, if no packets * use the indirect payload, the iso buffer need not be mapped - * and the request->data pointer is ignored. + * and the a->data pointer is ignored. */ - - payload = (unsigned long)request->data - client->vm_start; + payload = (unsigned long)a->data - client->vm_start; buffer_end = client->buffer.page_count << PAGE_SHIFT; - if (request->data == 0 || client->buffer.pages == NULL || + if (a->data == 0 || client->buffer.pages == NULL || payload >= buffer_end) { payload = 0; buffer_end = 0; } - p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets); + if (ctx->type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL && payload & 3) + return -EINVAL; - if (!access_ok(VERIFY_READ, p, request->size)) + p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(a->packets); + if (!access_ok(VERIFY_READ, p, a->size)) return -EFAULT; - end = (void __user *)p + request->size; + end = (void __user *)p + a->size; count = 0; while (p < end) { if (get_user(control, &p->control)) @@ -935,28 +1109,32 @@ static int ioctl_queue_iso(struct client *client, void *buffer) u.packet.sy = GET_SY(control); u.packet.header_length = GET_HEADER_LENGTH(control); - if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) { - header_length = u.packet.header_length; - } else { - /* - * We require that header_length is a multiple of - * the fixed header size, ctx->header_size. - */ - if (ctx->header_size == 0) { - if (u.packet.header_length > 0) - return -EINVAL; - } else if (u.packet.header_length % ctx->header_size != 0) { + switch (ctx->type) { + case FW_ISO_CONTEXT_TRANSMIT: + if (u.packet.header_length & 3) + return -EINVAL; + transmit_header_bytes = u.packet.header_length; + break; + + case FW_ISO_CONTEXT_RECEIVE: + if (u.packet.header_length == 0 || + u.packet.header_length % ctx->header_size != 0) + return -EINVAL; + break; + + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + if (u.packet.payload_length == 0 || + u.packet.payload_length & 3) return -EINVAL; - } - header_length = 0; + break; } next = (struct fw_cdev_iso_packet __user *) - &p->header[header_length / 4]; + &p->header[transmit_header_bytes / 4]; if (next > end) return -EINVAL; if (__copy_from_user - (u.packet.header, p->header, header_length)) + (u.packet.header, p->header, transmit_header_bytes)) return -EFAULT; if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT && u.packet.header_length + u.packet.payload_length > 0) @@ -972,62 +1150,97 @@ static int ioctl_queue_iso(struct client *client, void *buffer) payload += u.packet.payload_length; count++; } + fw_iso_context_queue_flush(ctx); - request->size -= uptr_to_u64(p) - request->packets; - request->packets = uptr_to_u64(p); - request->data = client->vm_start + payload; + a->size -= uptr_to_u64(p) - a->packets; + a->packets = uptr_to_u64(p); + a->data = client->vm_start + payload; return count; } -static int ioctl_start_iso(struct client *client, void *buffer) +static int ioctl_start_iso(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_start_iso *request = buffer; + struct fw_cdev_start_iso *a = &arg->start_iso; - if (client->iso_context == NULL || request->handle != 0) - return -EINVAL; + BUILD_BUG_ON( + FW_CDEV_ISO_CONTEXT_MATCH_TAG0 != FW_ISO_CONTEXT_MATCH_TAG0 || + FW_CDEV_ISO_CONTEXT_MATCH_TAG1 != FW_ISO_CONTEXT_MATCH_TAG1 || + FW_CDEV_ISO_CONTEXT_MATCH_TAG2 != FW_ISO_CONTEXT_MATCH_TAG2 || + FW_CDEV_ISO_CONTEXT_MATCH_TAG3 != FW_ISO_CONTEXT_MATCH_TAG3 || + FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS != FW_ISO_CONTEXT_MATCH_ALL_TAGS); - if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) { - if (request->tags == 0 || request->tags > 15) - return -EINVAL; + if (client->iso_context == NULL || a->handle != 0) + return -EINVAL; - if (request->sync > 15) - return -EINVAL; - } + if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE && + (a->tags == 0 || a->tags > 15 || a->sync > 15)) + return -EINVAL; - return fw_iso_context_start(client->iso_context, request->cycle, - request->sync, request->tags); + return fw_iso_context_start(client->iso_context, + a->cycle, a->sync, a->tags); } -static int ioctl_stop_iso(struct client *client, void *buffer) +static int ioctl_stop_iso(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_stop_iso *request = buffer; + struct fw_cdev_stop_iso *a = &arg->stop_iso; - if (client->iso_context == NULL || request->handle != 0) + if (client->iso_context == NULL || a->handle != 0) return -EINVAL; return fw_iso_context_stop(client->iso_context); } -static int ioctl_get_cycle_timer(struct client *client, void *buffer) +static int ioctl_flush_iso(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_get_cycle_timer *request = buffer; + struct fw_cdev_flush_iso *a = &arg->flush_iso; + + if (client->iso_context == NULL || a->handle != 0) + return -EINVAL; + + return fw_iso_context_flush_completions(client->iso_context); +} + +static int ioctl_get_cycle_timer2(struct client *client, union ioctl_arg *arg) +{ + struct fw_cdev_get_cycle_timer2 *a = &arg->get_cycle_timer2; struct fw_card *card = client->device->card; - unsigned long long bus_time; - struct timeval tv; - unsigned long flags; + struct timespec ts = {0, 0}; + u32 cycle_time; + int ret = 0; - preempt_disable(); - local_irq_save(flags); + local_irq_disable(); - bus_time = card->driver->get_bus_time(card); - do_gettimeofday(&tv); + cycle_time = card->driver->read_csr(card, CSR_CYCLE_TIME); - local_irq_restore(flags); - preempt_enable(); + switch (a->clk_id) { + case CLOCK_REALTIME: getnstimeofday(&ts); break; + case CLOCK_MONOTONIC: do_posix_clock_monotonic_gettime(&ts); break; + case CLOCK_MONOTONIC_RAW: getrawmonotonic(&ts); break; + default: + ret = -EINVAL; + } + + local_irq_enable(); + + a->tv_sec = ts.tv_sec; + a->tv_nsec = ts.tv_nsec; + a->cycle_timer = cycle_time; + + return ret; +} + +static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg) +{ + struct fw_cdev_get_cycle_timer *a = &arg->get_cycle_timer; + struct fw_cdev_get_cycle_timer2 ct2; + + ct2.clk_id = CLOCK_REALTIME; + ioctl_get_cycle_timer2(client, (union ioctl_arg *)&ct2); + + a->local_time = ct2.tv_sec * USEC_PER_SEC + ct2.tv_nsec / NSEC_PER_USEC; + a->cycle_timer = ct2.cycle_timer; - request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec; - request->cycle_timer = bus_time & 0xffffffff; return 0; } @@ -1045,7 +1258,8 @@ static void iso_resource_work(struct work_struct *work) todo = r->todo; /* Allow 1000ms grace period for other reallocations. */ if (todo == ISO_RES_ALLOC && - time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { + time_before64(get_jiffies_64(), + client->device->card->reset_jiffies + HZ)) { schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3)); skip = true; } else { @@ -1068,8 +1282,7 @@ static void iso_resource_work(struct work_struct *work) r->channels, &channel, &bandwidth, todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC || - todo == ISO_RES_ALLOC_ONCE, - r->transaction_data); + todo == ISO_RES_ALLOC_ONCE); /* * Is this generation outdated already? As long as this resource sticks * in the idr, it will be scheduled again for a newer generation or at @@ -1151,8 +1364,7 @@ static int init_iso_resource(struct client *client, int ret; if ((request->channels == 0 && request->bandwidth == 0) || - request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL || - request->bandwidth < 0) + request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL) return -EINVAL; r = kmalloc(sizeof(*r), GFP_KERNEL); @@ -1198,33 +1410,32 @@ static int init_iso_resource(struct client *client, return ret; } -static int ioctl_allocate_iso_resource(struct client *client, void *buffer) +static int ioctl_allocate_iso_resource(struct client *client, + union ioctl_arg *arg) { - struct fw_cdev_allocate_iso_resource *request = buffer; - - return init_iso_resource(client, request, ISO_RES_ALLOC); + return init_iso_resource(client, + &arg->allocate_iso_resource, ISO_RES_ALLOC); } -static int ioctl_deallocate_iso_resource(struct client *client, void *buffer) +static int ioctl_deallocate_iso_resource(struct client *client, + union ioctl_arg *arg) { - struct fw_cdev_deallocate *request = buffer; - - return release_client_resource(client, request->handle, - release_iso_resource, NULL); + return release_client_resource(client, + arg->deallocate.handle, release_iso_resource, NULL); } -static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer) +static int ioctl_allocate_iso_resource_once(struct client *client, + union ioctl_arg *arg) { - struct fw_cdev_allocate_iso_resource *request = buffer; - - return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE); + return init_iso_resource(client, + &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE); } -static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer) +static int ioctl_deallocate_iso_resource_once(struct client *client, + union ioctl_arg *arg) { - struct fw_cdev_allocate_iso_resource *request = buffer; - - return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE); + return init_iso_resource(client, + &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE); } /* @@ -1232,16 +1443,17 @@ static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffe * limited by the device's link speed, the local node's link speed, * and all PHY port speeds between the two links. */ -static int ioctl_get_speed(struct client *client, void *buffer) +static int ioctl_get_speed(struct client *client, union ioctl_arg *arg) { return client->device->max_speed; } -static int ioctl_send_broadcast_request(struct client *client, void *buffer) +static int ioctl_send_broadcast_request(struct client *client, + union ioctl_arg *arg) { - struct fw_cdev_send_request *request = buffer; + struct fw_cdev_send_request *a = &arg->send_request; - switch (request->tcode) { + switch (a->tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: break; @@ -1250,99 +1462,195 @@ static int ioctl_send_broadcast_request(struct client *client, void *buffer) } /* Security policy: Only allow accesses to Units Space. */ - if (request->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) + if (a->offset < CSR_REGISTER_BASE + CSR_CONFIG_ROM_END) return -EACCES; - return init_request(client, request, LOCAL_BUS | 0x3f, SCODE_100); + return init_request(client, a, LOCAL_BUS | 0x3f, SCODE_100); } -static int ioctl_send_stream_packet(struct client *client, void *buffer) +static int ioctl_send_stream_packet(struct client *client, union ioctl_arg *arg) { - struct fw_cdev_send_stream_packet *p = buffer; + struct fw_cdev_send_stream_packet *a = &arg->send_stream_packet; struct fw_cdev_send_request request; int dest; - if (p->speed > client->device->card->link_speed || - p->length > 1024 << p->speed) + if (a->speed > client->device->card->link_speed || + a->length > 1024 << a->speed) return -EIO; - if (p->tag > 3 || p->channel > 63 || p->sy > 15) + if (a->tag > 3 || a->channel > 63 || a->sy > 15) return -EINVAL; - dest = fw_stream_packet_destination_id(p->tag, p->channel, p->sy); + dest = fw_stream_packet_destination_id(a->tag, a->channel, a->sy); request.tcode = TCODE_STREAM_DATA; - request.length = p->length; - request.closure = p->closure; - request.data = p->data; - request.generation = p->generation; - - return init_request(client, &request, dest, p->speed); -} - -static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { - ioctl_get_info, - ioctl_send_request, - ioctl_allocate, - ioctl_deallocate, - ioctl_send_response, - ioctl_initiate_bus_reset, - ioctl_add_descriptor, - ioctl_remove_descriptor, - ioctl_create_iso_context, - ioctl_queue_iso, - ioctl_start_iso, - ioctl_stop_iso, - ioctl_get_cycle_timer, - ioctl_allocate_iso_resource, - ioctl_deallocate_iso_resource, - ioctl_allocate_iso_resource_once, - ioctl_deallocate_iso_resource_once, - ioctl_get_speed, - ioctl_send_broadcast_request, - ioctl_send_stream_packet, + request.length = a->length; + request.closure = a->closure; + request.data = a->data; + request.generation = a->generation; + + return init_request(client, &request, dest, a->speed); +} + +static void outbound_phy_packet_callback(struct fw_packet *packet, + struct fw_card *card, int status) +{ + struct outbound_phy_packet_event *e = + container_of(packet, struct outbound_phy_packet_event, p); + + switch (status) { + /* expected: */ + case ACK_COMPLETE: e->phy_packet.rcode = RCODE_COMPLETE; break; + /* should never happen with PHY packets: */ + case ACK_PENDING: e->phy_packet.rcode = RCODE_COMPLETE; break; + case ACK_BUSY_X: + case ACK_BUSY_A: + case ACK_BUSY_B: e->phy_packet.rcode = RCODE_BUSY; break; + case ACK_DATA_ERROR: e->phy_packet.rcode = RCODE_DATA_ERROR; break; + case ACK_TYPE_ERROR: e->phy_packet.rcode = RCODE_TYPE_ERROR; break; + /* stale generation; cancelled; on certain controllers: no ack */ + default: e->phy_packet.rcode = status; break; + } + e->phy_packet.data[0] = packet->timestamp; + + queue_event(e->client, &e->event, &e->phy_packet, + sizeof(e->phy_packet) + e->phy_packet.length, NULL, 0); + client_put(e->client); +} + +static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) +{ + struct fw_cdev_send_phy_packet *a = &arg->send_phy_packet; + struct fw_card *card = client->device->card; + struct outbound_phy_packet_event *e; + + /* Access policy: Allow this ioctl only on local nodes' device files. */ + if (!client->device->is_local) + return -ENOSYS; + + e = kzalloc(sizeof(*e) + 4, GFP_KERNEL); + if (e == NULL) + return -ENOMEM; + + client_get(client); + e->client = client; + e->p.speed = SCODE_100; + e->p.generation = a->generation; + e->p.header[0] = TCODE_LINK_INTERNAL << 4; + e->p.header[1] = a->data[0]; + e->p.header[2] = a->data[1]; + e->p.header_length = 12; + e->p.callback = outbound_phy_packet_callback; + e->phy_packet.closure = a->closure; + e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_SENT; + if (is_ping_packet(a->data)) + e->phy_packet.length = 4; + + card->driver->send_request(card, &e->p); + + return 0; +} + +static int ioctl_receive_phy_packets(struct client *client, union ioctl_arg *arg) +{ + struct fw_cdev_receive_phy_packets *a = &arg->receive_phy_packets; + struct fw_card *card = client->device->card; + + /* Access policy: Allow this ioctl only on local nodes' device files. */ + if (!client->device->is_local) + return -ENOSYS; + + spin_lock_irq(&card->lock); + + list_move_tail(&client->phy_receiver_link, &card->phy_receiver_list); + client->phy_receiver_closure = a->closure; + + spin_unlock_irq(&card->lock); + + return 0; +} + +void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p) +{ + struct client *client; + struct inbound_phy_packet_event *e; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + list_for_each_entry(client, &card->phy_receiver_list, phy_receiver_link) { + e = kmalloc(sizeof(*e) + 8, GFP_ATOMIC); + if (e == NULL) + break; + + e->phy_packet.closure = client->phy_receiver_closure; + e->phy_packet.type = FW_CDEV_EVENT_PHY_PACKET_RECEIVED; + e->phy_packet.rcode = RCODE_COMPLETE; + e->phy_packet.length = 8; + e->phy_packet.data[0] = p->header[1]; + e->phy_packet.data[1] = p->header[2]; + queue_event(client, &e->event, + &e->phy_packet, sizeof(e->phy_packet) + 8, NULL, 0); + } + + spin_unlock_irqrestore(&card->lock, flags); +} + +static int (* const ioctl_handlers[])(struct client *, union ioctl_arg *) = { + [0x00] = ioctl_get_info, + [0x01] = ioctl_send_request, + [0x02] = ioctl_allocate, + [0x03] = ioctl_deallocate, + [0x04] = ioctl_send_response, + [0x05] = ioctl_initiate_bus_reset, + [0x06] = ioctl_add_descriptor, + [0x07] = ioctl_remove_descriptor, + [0x08] = ioctl_create_iso_context, + [0x09] = ioctl_queue_iso, + [0x0a] = ioctl_start_iso, + [0x0b] = ioctl_stop_iso, + [0x0c] = ioctl_get_cycle_timer, + [0x0d] = ioctl_allocate_iso_resource, + [0x0e] = ioctl_deallocate_iso_resource, + [0x0f] = ioctl_allocate_iso_resource_once, + [0x10] = ioctl_deallocate_iso_resource_once, + [0x11] = ioctl_get_speed, + [0x12] = ioctl_send_broadcast_request, + [0x13] = ioctl_send_stream_packet, + [0x14] = ioctl_get_cycle_timer2, + [0x15] = ioctl_send_phy_packet, + [0x16] = ioctl_receive_phy_packets, + [0x17] = ioctl_set_iso_channels, + [0x18] = ioctl_flush_iso, }; static int dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg) { - char buffer[sizeof(union { - struct fw_cdev_get_info _00; - struct fw_cdev_send_request _01; - struct fw_cdev_allocate _02; - struct fw_cdev_deallocate _03; - struct fw_cdev_send_response _04; - struct fw_cdev_initiate_bus_reset _05; - struct fw_cdev_add_descriptor _06; - struct fw_cdev_remove_descriptor _07; - struct fw_cdev_create_iso_context _08; - struct fw_cdev_queue_iso _09; - struct fw_cdev_start_iso _0a; - struct fw_cdev_stop_iso _0b; - struct fw_cdev_get_cycle_timer _0c; - struct fw_cdev_allocate_iso_resource _0d; - struct fw_cdev_send_stream_packet _13; - })]; + union ioctl_arg buffer; int ret; + if (fw_device_is_shutdown(client->device)) + return -ENODEV; + if (_IOC_TYPE(cmd) != '#' || - _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers)) - return -EINVAL; + _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers) || + _IOC_SIZE(cmd) > sizeof(buffer)) + return -ENOTTY; - if (_IOC_DIR(cmd) & _IOC_WRITE) { - if (_IOC_SIZE(cmd) > sizeof(buffer) || - copy_from_user(buffer, arg, _IOC_SIZE(cmd))) + if (_IOC_DIR(cmd) == _IOC_READ) + memset(&buffer, 0, _IOC_SIZE(cmd)); + + if (_IOC_DIR(cmd) & _IOC_WRITE) + if (copy_from_user(&buffer, arg, _IOC_SIZE(cmd))) return -EFAULT; - } - ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer); + ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer); if (ret < 0) return ret; - if (_IOC_DIR(cmd) & _IOC_READ) { - if (_IOC_SIZE(cmd) > sizeof(buffer) || - copy_to_user(arg, buffer, _IOC_SIZE(cmd))) + if (_IOC_DIR(cmd) & _IOC_READ) + if (copy_to_user(arg, &buffer, _IOC_SIZE(cmd))) return -EFAULT; - } return ret; } @@ -1350,31 +1658,20 @@ static int dispatch_ioctl(struct client *client, static long fw_device_op_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct client *client = file->private_data; - - if (fw_device_is_shutdown(client->device)) - return -ENODEV; - - return dispatch_ioctl(client, cmd, (void __user *) arg); + return dispatch_ioctl(file->private_data, cmd, (void __user *)arg); } #ifdef CONFIG_COMPAT static long fw_device_op_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct client *client = file->private_data; - - if (fw_device_is_shutdown(client->device)) - return -ENODEV; - - return dispatch_ioctl(client, cmd, compat_ptr(arg)); + return dispatch_ioctl(file->private_data, cmd, compat_ptr(arg)); } #endif 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; @@ -1397,19 +1694,46 @@ 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) + goto fail; + + ret = fw_iso_buffer_map_vma(&client->buffer, vma); if (ret < 0) - fw_iso_buffer_destroy(&client->buffer, client->device->card); + goto fail; + + return 0; + fail: + fw_iso_buffer_destroy(&client->buffer, client->device->card); + return ret; +} + +static int is_outbound_transaction_resource(int id, void *p, void *data) +{ + struct client_resource *resource = p; + + return resource->release == release_transaction; +} + +static int has_outbound_transactions(struct client *client) +{ + int ret; + + spin_lock_irq(&client->lock); + ret = idr_for_each(&client->resource_idr, + is_outbound_transaction_resource, NULL); + spin_unlock_irq(&client->lock); return ret; } @@ -1430,6 +1754,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file) struct client *client = file->private_data; struct event *event, *next_event; + spin_lock_irq(&client->device->card->lock); + list_del(&client->phy_receiver_link); + spin_unlock_irq(&client->device->card->lock); + mutex_lock(&client->device->client_list_mutex); list_del(&client->link); mutex_unlock(&client->device->client_list_mutex); @@ -1445,8 +1773,9 @@ static int fw_device_op_release(struct inode *inode, struct file *file) client->in_shutdown = true; spin_unlock_irq(&client->lock); + wait_event(client->tx_flush_wait, !has_outbound_transactions(client)); + idr_for_each(&client->resource_idr, shutdown_resource, client); - idr_remove_all(&client->resource_idr); idr_destroy(&client->resource_idr); list_for_each_entry_safe(event, next_event, &client->event_list, link) @@ -1474,13 +1803,13 @@ static unsigned int fw_device_op_poll(struct file *file, poll_table * pt) const struct file_operations fw_device_ops = { .owner = THIS_MODULE, + .llseek = no_llseek, .open = fw_device_op_open, .read = fw_device_op_read, .unlocked_ioctl = fw_device_op_ioctl, - .poll = fw_device_op_poll, - .release = fw_device_op_release, .mmap = fw_device_op_mmap, - + .release = fw_device_op_release, + .poll = fw_device_op_poll, #ifdef CONFIG_COMPAT .compat_ioctl = fw_device_op_compat_ioctl, #endif diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 9d0dfcbe2c1..2c6d5e118ac 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -18,6 +18,7 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/bug.h> #include <linux/ctype.h> #include <linux/delay.h> #include <linux/device.h> @@ -31,19 +32,19 @@ #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/random.h> #include <linux/rwsem.h> -#include <linux/semaphore.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> #include <linux/workqueue.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/byteorder.h> -#include <asm/system.h> #include "core.h" -void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p) +void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p) { ci->p = p + 1; ci->end = ci->p + (p[0] >> 16); @@ -59,97 +60,160 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) } EXPORT_SYMBOL(fw_csr_iterator_next); -static bool is_fw_unit(struct device *dev); - -static int match_unit_directory(u32 *directory, u32 match_flags, - const struct ieee1394_device_id *id) +static const u32 *search_leaf(const u32 *directory, int search_key) { struct fw_csr_iterator ci; - int key, value, match; + int last_key = 0, key, value; - match = 0; fw_csr_iterator_init(&ci, directory); while (fw_csr_iterator_next(&ci, &key, &value)) { - if (key == CSR_VENDOR && value == id->vendor_id) - match |= IEEE1394_MATCH_VENDOR_ID; - if (key == CSR_MODEL && value == id->model_id) - match |= IEEE1394_MATCH_MODEL_ID; - if (key == CSR_SPECIFIER_ID && value == id->specifier_id) - match |= IEEE1394_MATCH_SPECIFIER_ID; - if (key == CSR_VERSION && value == id->version) - match |= IEEE1394_MATCH_VERSION; + if (last_key == search_key && + key == (CSR_DESCRIPTOR | CSR_LEAF)) + return ci.p - 1 + value; + + last_key = key; } - return (match & match_flags) == match_flags; + return NULL; } -static int fw_unit_match(struct device *dev, struct device_driver *drv) +static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) { - struct fw_unit *unit = fw_unit(dev); - struct fw_device *device; - const struct ieee1394_device_id *id; - - /* We only allow binding to fw_units. */ - if (!is_fw_unit(dev)) - return 0; + unsigned int quadlets, i; + char c; - device = fw_parent_device(unit); - id = container_of(drv, struct fw_driver, driver)->id_table; + if (!size || !buf) + return -EINVAL; - for (; id->match_flags != 0; id++) { - if (match_unit_directory(unit->directory, id->match_flags, id)) - return 1; + quadlets = min(block[0] >> 16, 256U); + if (quadlets < 2) + return -ENODATA; - /* Also check vendor ID in the root directory. */ - if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && - match_unit_directory(&device->config_rom[5], - IEEE1394_MATCH_VENDOR_ID, id) && - match_unit_directory(unit->directory, id->match_flags - & ~IEEE1394_MATCH_VENDOR_ID, id)) - return 1; + if (block[1] != 0 || block[2] != 0) + /* unknown language/character set */ + return -ENODATA; + + block += 3; + quadlets -= 2; + for (i = 0; i < quadlets * 4 && i < size - 1; i++) { + c = block[i / 4] >> (24 - 8 * (i % 4)); + if (c == '\0') + break; + buf[i] = c; } + buf[i] = '\0'; - return 0; + return i; } -static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) +/** + * fw_csr_string() - reads a string from the configuration ROM + * @directory: e.g. root directory or unit directory + * @key: the key of the preceding directory entry + * @buf: where to put the string + * @size: size of @buf, in bytes + * + * The string is taken from a minimal ASCII text descriptor leaf after + * the immediate entry with @key. The string is zero-terminated. + * Returns strlen(buf) or a negative error code. + */ +int fw_csr_string(const u32 *directory, int key, char *buf, size_t size) { - struct fw_device *device = fw_parent_device(unit); - struct fw_csr_iterator ci; + const u32 *leaf = search_leaf(directory, key); + if (!leaf) + return -ENOENT; + return textual_leaf_to_string(leaf, buf, size); +} +EXPORT_SYMBOL(fw_csr_string); + +static void get_ids(const u32 *directory, int *id) +{ + struct fw_csr_iterator ci; int key, value; - int vendor = 0; - int model = 0; - int specifier_id = 0; - int version = 0; - fw_csr_iterator_init(&ci, &device->config_rom[5]); + fw_csr_iterator_init(&ci, directory); while (fw_csr_iterator_next(&ci, &key, &value)) { switch (key) { - case CSR_VENDOR: - vendor = value; - break; - case CSR_MODEL: - model = value; - break; + case CSR_VENDOR: id[0] = value; break; + case CSR_MODEL: id[1] = value; break; + case CSR_SPECIFIER_ID: id[2] = value; break; + case CSR_VERSION: id[3] = value; break; } } +} - fw_csr_iterator_init(&ci, unit->directory); - while (fw_csr_iterator_next(&ci, &key, &value)) { - switch (key) { - case CSR_SPECIFIER_ID: - specifier_id = value; - break; - case CSR_VERSION: - version = value; - break; - } - } +static void get_modalias_ids(struct fw_unit *unit, int *id) +{ + get_ids(&fw_parent_device(unit)->config_rom[5], id); + get_ids(unit->directory, id); +} + +static bool match_ids(const struct ieee1394_device_id *id_table, int *id) +{ + int match = 0; + + if (id[0] == id_table->vendor_id) + match |= IEEE1394_MATCH_VENDOR_ID; + if (id[1] == id_table->model_id) + match |= IEEE1394_MATCH_MODEL_ID; + if (id[2] == id_table->specifier_id) + match |= IEEE1394_MATCH_SPECIFIER_ID; + if (id[3] == id_table->version) + match |= IEEE1394_MATCH_VERSION; + + return (match & id_table->match_flags) == id_table->match_flags; +} + +static const struct ieee1394_device_id *unit_match(struct device *dev, + struct device_driver *drv) +{ + const struct ieee1394_device_id *id_table = + container_of(drv, struct fw_driver, driver)->id_table; + int id[] = {0, 0, 0, 0}; + + get_modalias_ids(fw_unit(dev), id); + + for (; id_table->match_flags != 0; id_table++) + if (match_ids(id_table, id)) + return id_table; + + return NULL; +} + +static bool is_fw_unit(struct device *dev); + +static int fw_unit_match(struct device *dev, struct device_driver *drv) +{ + /* We only allow binding to fw_units. */ + return is_fw_unit(dev) && unit_match(dev, drv) != NULL; +} + +static int fw_unit_probe(struct device *dev) +{ + struct fw_driver *driver = + container_of(dev->driver, struct fw_driver, driver); + + return driver->probe(fw_unit(dev), unit_match(dev, dev->driver)); +} + +static int fw_unit_remove(struct device *dev) +{ + struct fw_driver *driver = + container_of(dev->driver, struct fw_driver, driver); + + return driver->remove(fw_unit(dev)), 0; +} + +static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size) +{ + int id[] = {0, 0, 0, 0}; + + get_modalias_ids(unit, id); return snprintf(buffer, buffer_size, "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", - vendor, model, specifier_id, version); + id[0], id[1], id[2], id[3]); } static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) @@ -168,6 +232,8 @@ static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env) struct bus_type fw_bus_type = { .name = "firewire", .match = fw_unit_match, + .probe = fw_unit_probe, + .remove = fw_unit_remove, }; EXPORT_SYMBOL(fw_bus_type); @@ -195,7 +261,7 @@ static ssize_t show_immediate(struct device *dev, struct config_rom_attribute *attr = container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; - u32 *dir; + const u32 *dir; int key, value, ret = -ENOENT; down_read(&fw_device_rwsem); @@ -226,10 +292,10 @@ static ssize_t show_text_leaf(struct device *dev, { struct config_rom_attribute *attr = 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, ret = -ENOENT; - char *b; + const u32 *dir; + size_t bufsize; + char dummy_buf[2]; + int ret; down_read(&fw_device_rwsem); @@ -238,40 +304,23 @@ static ssize_t show_text_leaf(struct device *dev, else dir = fw_device(dev)->config_rom + 5; - fw_csr_iterator_init(&ci, dir); - while (fw_csr_iterator_next(&ci, &key, &value)) { - if (attr->key == last_key && - key == (CSR_DESCRIPTOR | CSR_LEAF)) - block = ci.p - 1 + value; - last_key = key; + if (buf) { + bufsize = PAGE_SIZE - 1; + } else { + buf = dummy_buf; + bufsize = 1; } - if (block == NULL) - goto out; - - length = min(block[0] >> 16, 256U); - if (length < 3) - goto out; + ret = fw_csr_string(dir, attr->key, buf, bufsize); - if (block[1] != 0 || block[2] != 0) - /* Unknown encoding. */ - goto out; - - if (buf == NULL) { - ret = length * 4; - goto out; + if (ret >= 0) { + /* Strip trailing whitespace and add newline. */ + while (ret > 0 && isspace(buf[ret - 1])) + ret--; + strcpy(buf + ret, "\n"); + ret++; } - b = buf; - end = &block[length + 1]; - for (p = &block[3]; p < end; p++, b += 4) - * (u32 *) b = (__force u32) __cpu_to_be32(*p); - - /* 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 ret; @@ -371,7 +420,15 @@ static ssize_t guid_show(struct device *dev, return ret; } -static int units_sprintf(char *buf, u32 *directory) +static ssize_t is_local_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fw_device *device = fw_device(dev); + + return sprintf(buf, "%u\n", device->is_local); +} + +static int units_sprintf(char *buf, const u32 *directory) { struct fw_csr_iterator ci; int key, value; @@ -420,6 +477,7 @@ static ssize_t units_show(struct device *dev, static struct device_attribute fw_device_attributes[] = { __ATTR_RO(config_rom), __ATTR_RO(guid), + __ATTR_RO(is_local), __ATTR_RO(units), __ATTR_NULL, }; @@ -427,59 +485,70 @@ static struct device_attribute fw_device_attributes[] = { static int read_rom(struct fw_device *device, int generation, int index, u32 *data) { - int rcode; + u64 offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4; + int i, rcode; /* device->node_id, accessed below, must not be older than generation */ smp_rmb(); - rcode = fw_run_transaction(device->card, TCODE_READ_QUADLET_REQUEST, - device->node_id, generation, device->max_speed, - (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4, - data, 4); + for (i = 10; i < 100; i += 10) { + rcode = fw_run_transaction(device->card, + TCODE_READ_QUADLET_REQUEST, device->node_id, + generation, device->max_speed, offset, data, 4); + if (rcode != RCODE_BUSY) + break; + msleep(i); + } be32_to_cpus(data); return rcode; } -#define READ_BIB_ROM_SIZE 256 -#define READ_BIB_STACK_SIZE 16 +#define MAX_CONFIG_ROM_SIZE 256 /* * 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. + * 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_bus_info_block(struct fw_device *device, int generation) +static int read_config_rom(struct fw_device *device, int generation) { - u32 *rom, *stack, *old_rom, *new_rom; + 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) * READ_BIB_ROM_SIZE + - sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); + rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE + + sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL); if (rom == NULL) return -ENOMEM; - stack = &rom[READ_BIB_ROM_SIZE]; + stack = &rom[MAX_CONFIG_ROM_SIZE]; + memset(rom, 0, sizeof(*rom) * MAX_CONFIG_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) + 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; @@ -495,12 +564,12 @@ static int read_bus_info_block(struct fw_device *device, int generation) */ if ((rom[2] & 0x7) < device->max_speed || device->max_speed == SCODE_BETA || - device->card->beta_repeaters_present) { + card->beta_repeaters_present) { u32 dummy; /* for S1600 and S3200 */ if (device->max_speed == SCODE_BETA) - device->max_speed = device->card->link_speed; + device->max_speed = card->link_speed; while (device->max_speed > SCODE_100) { if (read_rom(device, generation, 0, &dummy) == @@ -529,40 +598,58 @@ static int read_bus_info_block(struct fw_device *device, int generation) */ key = stack[--sp]; i = key & 0xffffff; - if (i >= READ_BIB_ROM_SIZE) - /* - * The reference points outside the standard - * config rom area, something's fishy. - */ + 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; - i++; - if (end > READ_BIB_ROM_SIZE) + if (end > MAX_CONFIG_ROM_SIZE) { /* - * This block extends outside standard config - * area (and the array we're reading it - * into). That's broken, so ignore this - * device. + * This block extends outside the config ROM which is + * a firmware bug. Ignore this whole block, i.e. + * simply set a fake block length of 0. */ - goto out; + fw_err(card, "skipped invalid ROM block %x at %llx\n", + rom[i], + i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM); + rom[i] = 0; + end = i; + } + i++; /* * Now read in the block. If this is a directory * block, check the entries as we read them to see if * it references another block, and push it in that case. */ - while (i < end) { - if (read_rom(device, generation, i, &rom[i]) != - RCODE_COMPLETE) + for (; i < end; i++) { + ret = read_rom(device, generation, i, &rom[i]); + if (ret != RCODE_COMPLETE) goto out; - if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && - sp < READ_BIB_STACK_SIZE) - stack[sp++] = i + rom[i]; - i++; + + if ((key >> 30) != 3 || (rom[i] >> 30) < 2) + continue; + /* + * Offset points outside the ROM. May be a firmware + * bug or an Extended ROM entry (IEEE 1212-2001 clause + * 7.7.18). Simply overwrite this pointer here by a + * fake immediate entry so that later iterators over + * the ROM don't have to check offsets all the time. + */ + if (i + (rom[i] & 0xffffff) >= MAX_CONFIG_ROM_SIZE) { + fw_err(card, + "skipped unsupported ROM entry %x at %llx\n", + rom[i], + i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM); + rom[i] = 0; + continue; + } + stack[sp++] = i + rom[i]; } if (length < i) length = i; @@ -570,8 +657,10 @@ static int read_bus_info_block(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; @@ -579,7 +668,7 @@ static int read_bus_info_block(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; @@ -593,6 +682,7 @@ static void fw_unit_release(struct device *dev) { struct fw_unit *unit = fw_unit(dev); + fw_device_put(fw_parent_device(unit)); kfree(unit); } @@ -623,10 +713,8 @@ static void create_units(struct fw_device *device) * match the drivers id_tables against it. */ unit = kzalloc(sizeof(*unit), GFP_KERNEL); - if (unit == NULL) { - fw_error("failed to allocate memory for unit\n"); + if (unit == NULL) continue; - } unit->directory = ci.p + value - 1; unit->device.bus = &fw_bus_type; @@ -644,6 +732,7 @@ static void create_units(struct fw_device *device) if (device_register(&unit->device) < 0) goto skip_unit; + fw_device_get(device); continue; skip_unit: @@ -682,6 +771,15 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) return device; } +struct workqueue_struct *fw_workqueue; +EXPORT_SYMBOL(fw_workqueue); + +static void fw_schedule_device_work(struct fw_device *device, + unsigned long delay) +{ + queue_delayed_work(fw_workqueue, &device->work, delay); +} + /* * These defines control the retry behavior for reading the config * rom. It shouldn't be necessary to tweak these; if the device @@ -704,9 +802,10 @@ static void fw_device_shutdown(struct work_struct *work) container_of(work, struct fw_device, work.work); int minor = MINOR(device->device.devt); - if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY) + if (time_before64(get_jiffies_64(), + device->card->reset_jiffies + SHUTDOWN_DELAY) && !list_empty(&device->card->link)) { - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + fw_schedule_device_work(device, SHUTDOWN_DELAY); return; } @@ -762,9 +861,9 @@ static int update_unit(struct device *dev, void *data) struct fw_driver *driver = (struct fw_driver *)dev->driver; if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) { - down(&dev->sem); + device_lock(dev); driver->update(unit); - up(&dev->sem); + device_unlock(dev); } return 0; @@ -815,10 +914,10 @@ static int lookup_existing_device(struct device *dev, void *data) smp_wmb(); /* update node_id before generation */ old->generation = card->generation; old->config_rom_retries = 0; - fw_notify("rediscovered device %s\n", dev_name(dev)); + fw_notice(card, "rediscovered device %s\n", dev_name(dev)); - PREPARE_DELAYED_WORK(&old->work, fw_device_update); - schedule_delayed_work(&old->work, 0); + old->workfn = fw_device_update; + fw_schedule_device_work(old, 0); if (current_node == card->root_node) fw_schedule_bm_work(card, 0); @@ -896,6 +995,7 @@ static void fw_device_init(struct work_struct *work) { struct fw_device *device = container_of(work, struct fw_device, work.work); + struct fw_card *card = device->card; struct device *revived_dev; int minor, ret; @@ -905,22 +1005,25 @@ static void fw_device_init(struct work_struct *work) * device. */ - if (read_bus_info_block(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++; - schedule_delayed_work(&device->work, RETRY_DELAY); + fw_schedule_device_work(device, RETRY_DELAY); } else { - fw_notify("giving up on config rom for node id %x\n", - device->node_id); - if (device->node == device->card->root_node) - fw_schedule_bm_work(device->card, 0); + if (device->node->link_on) + 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); } return; } - revived_dev = device_find_child(device->card->device, + revived_dev = device_find_child(card->device, device, lookup_existing_device); if (revived_dev) { put_device(revived_dev); @@ -933,17 +1036,16 @@ static void fw_device_init(struct work_struct *work) fw_device_get(device); down_write(&fw_device_rwsem); - ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ? - idr_get_new(&fw_device_idr, device, &minor) : - -ENOMEM; + minor = idr_alloc(&fw_device_idr, device, 0, 1 << MINORBITS, + GFP_KERNEL); up_write(&fw_device_rwsem); - if (ret < 0) + if (minor < 0) goto error; device->device.bus = &fw_bus_type; device->device.type = &fw_device_type; - device->device.parent = device->card->device; + device->device.parent = card->device; device->device.devt = MKDEV(fw_cdev_major, minor); dev_set_name(&device->device, "fw%d", minor); @@ -955,7 +1057,7 @@ static void fw_device_init(struct work_struct *work) &device->attribute_group); if (device_add(&device->device)) { - fw_error("Failed to add device.\n"); + fw_err(card, "failed to add device\n"); goto error_with_cdev; } @@ -973,24 +1075,18 @@ static void fw_device_init(struct work_struct *work) if (atomic_cmpxchg(&device->state, FW_DEVICE_INITIALIZING, FW_DEVICE_RUNNING) == FW_DEVICE_GONE) { - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + device->workfn = fw_device_shutdown; + fw_schedule_device_work(device, SHUTDOWN_DELAY); } else { - if (device->config_rom_retries) - fw_notify("created device %s: GUID %08x%08x, S%d00, " - "%d config ROM retries\n", - dev_name(&device->device), - device->config_rom[3], device->config_rom[4], - 1 << device->max_speed, - device->config_rom_retries); - else - fw_notify("created device %s: GUID %08x%08x, S%d00\n", - dev_name(&device->device), - device->config_rom[3], device->config_rom[4], - 1 << device->max_speed); + fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n", + dev_name(&device->device), + device->config_rom[3], device->config_rom[4], + 1 << device->max_speed); device->config_rom_retries = 0; set_broadcast_channel(device, device->generation); + + add_device_randomness(&device->config_rom[3], 8); } /* @@ -999,8 +1095,8 @@ static void fw_device_init(struct work_struct *work) * just end up running the IRM work a couple of extra times - * pretty harmless. */ - if (device->node == device->card->root_node) - fw_schedule_bm_work(device->card, 0); + if (device->node == card->root_node) + fw_schedule_bm_work(card, 0); return; @@ -1014,31 +1110,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_bus_info_block(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) @@ -1046,23 +1141,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_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; + 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) @@ -1071,9 +1157,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; } /* @@ -1082,17 +1165,11 @@ static void fw_device_refresh(struct work_struct *work) */ 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; - } + ret = read_config_rom(device, device->generation); + if (ret != RCODE_COMPLETE) + goto failed_config_rom; + fw_device_cdev_update(device); create_units(device); /* Userspace may want to re-read attributes. */ @@ -1103,30 +1180,48 @@ static void fw_device_refresh(struct work_struct *work) FW_DEVICE_RUNNING) == FW_DEVICE_GONE) goto gone; - fw_notify("refreshed device %s\n", dev_name(&device->device)); + fw_notice(card, "refreshed device %s\n", dev_name(&device->device)); device->config_rom_retries = 0; goto out; - give_up: - fw_notify("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); - schedule_delayed_work(&device->work, SHUTDOWN_DELAY); + device->workfn = fw_device_shutdown; + fw_schedule_device_work(device, SHUTDOWN_DELAY); out: if (node_id == card->root_node->node_id) fw_schedule_bm_work(card, 0); } +static void fw_device_workfn(struct work_struct *work) +{ + struct fw_device *device = container_of(to_delayed_work(work), + struct fw_device, work); + device->workfn(work); +} + void fw_node_event(struct fw_card *card, struct fw_node *node, int event) { struct fw_device *device; switch (event) { case FW_NODE_CREATED: - case FW_NODE_LINK_ON: - if (!node->link_on) - break; + /* + * Attempt to scan the node, regardless whether its self ID has + * the L (link active) flag set or not. Some broken devices + * send L=0 but have an up-and-running link; others send L=1 + * without actually having a link. + */ create: device = kzalloc(sizeof(*device), GFP_ATOMIC); if (device == NULL) @@ -1164,11 +1259,13 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) * power-up after getting plugged in. We schedule the * first config rom scan half a second after bus reset. */ - INIT_DELAYED_WORK(&device->work, fw_device_init); - schedule_delayed_work(&device->work, INITIAL_DELAY); + device->workfn = fw_device_init; + INIT_DELAYED_WORK(&device->work, fw_device_workfn); + fw_schedule_device_work(device, INITIAL_DELAY); break; case FW_NODE_INITIATED_RESET: + case FW_NODE_LINK_ON: device = node->data; if (device == NULL) goto create; @@ -1179,23 +1276,23 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) 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, + device->workfn = fw_device_refresh; + fw_schedule_device_work(device, device->is_local ? 0 : INITIAL_DELAY); } break; case FW_NODE_UPDATED: - if (!node->link_on || node->data == NULL) + device = node->data; + if (device == NULL) break; - 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); - schedule_delayed_work(&device->work, 0); + device->workfn = fw_device_update; + fw_schedule_device_work(device, 0); } break; @@ -1219,8 +1316,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) device = node->data; if (atomic_xchg(&device->state, FW_DEVICE_GONE) == FW_DEVICE_RUNNING) { - PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown); - schedule_delayed_work(&device->work, + device->workfn = fw_device_shutdown; + fw_schedule_device_work(device, list_empty(&card->link) ? 0 : SHUTDOWN_DELAY); } break; diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 1c0b504a42f..38c0aa60b2c 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -26,8 +26,10 @@ #include <linux/firewire-constants.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <asm/byteorder.h> @@ -37,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; + break; + } + buffer->page_count = i; + if (i < page_count) { + fw_iso_buffer_destroy(buffer, NULL); + return -ENOMEM; + } + + return 0; +} + +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)) { - __free_page(buffer->pages[i]); - goto out_pages; - } + if (dma_mapping_error(card->device, address)) + break; + set_page_private(buffer->pages[i], address); } + buffer->page_count_mapped = i; + if (i < buffer->page_count) + 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]); - } - kfree(buffer->pages); - out: - buffer->pages = NULL; +int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, + int page_count, enum dma_data_direction direction) +{ + int ret; - return -ENOMEM; + 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; @@ -105,18 +128,38 @@ 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); +/* Convert DMA address to offset into virtually contiguous buffer. */ +size_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed) +{ + size_t i; + dma_addr_t address; + ssize_t offset; + + for (i = 0; i < buffer->page_count; i++) { + address = page_private(buffer->pages[i]); + offset = (ssize_t)completed - (ssize_t)address; + if (offset > 0 && offset <= PAGE_SIZE) + return (i << PAGE_SHIFT) + offset; + } + + return 0; +} + struct fw_iso_context *fw_iso_context_create(struct fw_card *card, int type, int channel, int speed, size_t header_size, fw_iso_callback_t callback, void *callback_data) @@ -133,7 +176,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, ctx->channel = channel; ctx->speed = speed; ctx->header_size = header_size; - ctx->callback = callback; + ctx->callback.sc = callback; ctx->callback_data = callback_data; return ctx; @@ -142,9 +185,7 @@ EXPORT_SYMBOL(fw_iso_context_create); void fw_iso_context_destroy(struct fw_iso_context *ctx) { - struct fw_card *card = ctx->card; - - card->driver->free_iso_context(ctx); + ctx->card->driver->free_iso_context(ctx); } EXPORT_SYMBOL(fw_iso_context_destroy); @@ -155,17 +196,32 @@ int fw_iso_context_start(struct fw_iso_context *ctx, } EXPORT_SYMBOL(fw_iso_context_start); +int fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels) +{ + return ctx->card->driver->set_iso_channels(ctx, channels); +} + int fw_iso_context_queue(struct fw_iso_context *ctx, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload) { - struct fw_card *card = ctx->card; - - return card->driver->queue_iso(ctx, packet, buffer, payload); + return ctx->card->driver->queue_iso(ctx, packet, buffer, payload); } EXPORT_SYMBOL(fw_iso_context_queue); +void fw_iso_context_queue_flush(struct fw_iso_context *ctx) +{ + ctx->card->driver->flush_queue_iso(ctx); +} +EXPORT_SYMBOL(fw_iso_context_queue_flush); + +int fw_iso_context_flush_completions(struct fw_iso_context *ctx) +{ + return ctx->card->driver->flush_iso_completions(ctx); +} +EXPORT_SYMBOL(fw_iso_context_flush_completions); + int fw_iso_context_stop(struct fw_iso_context *ctx) { return ctx->card->driver->stop_iso(ctx); @@ -177,9 +233,10 @@ EXPORT_SYMBOL(fw_iso_context_stop); */ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, - int bandwidth, bool allocate, __be32 data[2]) + int bandwidth, bool allocate) { int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0; + __be32 data[2]; /* * On a 1394a IRM with low contention, try < 1 is enough. @@ -189,7 +246,7 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, for (try = 0; try < 5; try++) { new = allocate ? old - bandwidth : old + bandwidth; if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL) - break; + return -EBUSY; data[0] = cpu_to_be32(old); data[1] = cpu_to_be32(new); @@ -214,52 +271,59 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, } static int manage_channel(struct fw_card *card, int irm_id, int generation, - u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) + u32 channels_mask, u64 offset, bool allocate) { - __be32 c, all, old; - int i, retry = 5; + __be32 bit, all, old; + __be32 data[2]; + int channel, ret = -EIO, retry = 5; old = all = allocate ? cpu_to_be32(~0) : 0; - for (i = 0; i < 32; i++) { - if (!(channels_mask & 1 << i)) + for (channel = 0; channel < 32; channel++) { + if (!(channels_mask & 1 << channel)) continue; - c = cpu_to_be32(1 << (31 - i)); - if ((old & c) != (all & c)) + ret = -EBUSY; + + bit = cpu_to_be32(1 << (31 - channel)); + if ((old & bit) != (all & bit)) continue; data[0] = old; - data[1] = old ^ c; + data[1] = old ^ bit; switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_id, generation, SCODE_100, offset, data, 8)) { case RCODE_GENERATION: /* A generation change frees all channels. */ - return allocate ? -EAGAIN : i; + return allocate ? -EAGAIN : channel; case RCODE_COMPLETE: if (data[0] == old) - return i; + return channel; old = data[0]; /* Is the IRM 1394a-2000 compliant? */ - if ((data[0] & c) == (data[1] & c)) + if ((data[0] & bit) == (data[1] & bit)) continue; /* 1394-1995 IRM, fall through to retry. */ default: - if (retry--) - i--; + if (retry) { + retry--; + channel--; + } else { + ret = -EIO; + } } } - return -EIO; + return ret; } static void deallocate_channel(struct fw_card *card, int irm_id, - int generation, int channel, __be32 buffer[2]) + int generation, int channel) { u32 mask; u64 offset; @@ -268,11 +332,11 @@ static void deallocate_channel(struct fw_card *card, int irm_id, offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; - manage_channel(card, irm_id, generation, mask, offset, false, buffer); + manage_channel(card, irm_id, generation, mask, offset, false); } /** - * fw_iso_resource_manage - Allocate or deallocate a channel and/or bandwidth + * fw_iso_resource_manage() - Allocate or deallocate a channel and/or bandwidth * * In parameters: card, generation, channels_mask, bandwidth, allocate * Out parameters: channel, bandwidth @@ -297,7 +361,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id, */ void fw_iso_resource_manage(struct fw_card *card, int generation, u64 channels_mask, int *channel, int *bandwidth, - bool allocate, __be32 buffer[2]) + bool allocate) { u32 channels_hi = channels_mask; /* channels 31...0 */ u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ @@ -310,11 +374,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (channels_hi) c = manage_channel(card, irm_id, generation, channels_hi, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, - allocate, buffer); + allocate); if (channels_lo && c < 0) { c = manage_channel(card, irm_id, generation, channels_lo, CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, - allocate, buffer); + allocate); if (c >= 0) c += 32; } @@ -326,13 +390,14 @@ void fw_iso_resource_manage(struct fw_card *card, int generation, if (*bandwidth == 0) return; - ret = manage_bandwidth(card, irm_id, generation, *bandwidth, - allocate, buffer); + ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate); if (ret < 0) *bandwidth = 0; - if (allocate && ret < 0 && c >= 0) { - deallocate_channel(card, irm_id, generation, c, buffer); + if (allocate && ret < 0) { + if (c >= 0) + deallocate_channel(card, irm_id, generation, c); *channel = ret; } } +EXPORT_SYMBOL(fw_iso_resource_manage); diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 93ec64cdeef..0de83508f32 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -29,9 +29,8 @@ #include <linux/slab.h> #include <linux/spinlock.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <asm/byteorder.h> -#include <asm/system.h> #include "core.h" @@ -174,12 +173,7 @@ static inline struct fw_node *fw_node(struct list_head *l) return list_entry(l, struct fw_node, link); } -/** - * build_tree - Build the tree representation of the topology - * @self_ids: array of self IDs to create the tree from - * @self_id_count: the length of the self_ids array - * @local_id: the node ID of the local node - * +/* * This function builds the tree representation of the topology given * by the self IDs from the latest bus reset. During the construction * of the tree, the function checks that the self IDs are valid and @@ -210,19 +204,19 @@ static struct fw_node *build_tree(struct fw_card *card, next_sid = count_ports(sid, &port_count, &child_port_count); if (next_sid == NULL) { - fw_error("Inconsistent extended self IDs.\n"); + fw_err(card, "inconsistent extended self IDs\n"); return NULL; } q = *sid; if (phy_id != SELF_ID_PHY_ID(q)) { - fw_error("PHY ID mismatch in self ID: %d != %d.\n", - phy_id, SELF_ID_PHY_ID(q)); + fw_err(card, "PHY ID mismatch in self ID: %d != %d\n", + phy_id, SELF_ID_PHY_ID(q)); return NULL; } if (child_port_count > stack_depth) { - fw_error("Topology stack underflow\n"); + fw_err(card, "topology stack underflow\n"); return NULL; } @@ -240,7 +234,7 @@ static struct fw_node *build_tree(struct fw_card *card, node = fw_node_create(q, port_count, card->color); if (node == NULL) { - fw_error("Out of memory while building topology.\n"); + fw_err(card, "out of memory while building topology\n"); return NULL; } @@ -289,8 +283,8 @@ static struct fw_node *build_tree(struct fw_card *card, */ if ((next_sid == end && parent_count != 0) || (next_sid < end && parent_count != 1)) { - fw_error("Parent port inconsistency for node %d: " - "parent_count=%d\n", phy_id, parent_count); + fw_err(card, "parent port inconsistency for node %d: " + "parent_count=%d\n", phy_id, parent_count); return NULL; } @@ -420,11 +414,10 @@ static void move_tree(struct fw_node *node0, struct fw_node *node1, int port) } } -/** - * update_tree - compare the old topology tree for card with the new - * one specified by root. Queue the nodes and mark them as either - * found, lost or updated. Update the nodes in the card topology tree - * as we go. +/* + * Compare the old topology tree for card with the new one specified by root. + * Queue the nodes and mark them as either found, lost or updated. + * Update the nodes in the card topology tree as we go. */ static void update_tree(struct fw_card *card, struct fw_node *root) { @@ -524,7 +517,7 @@ static void update_topology_map(struct fw_card *card, } void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, - int self_id_count, u32 *self_ids) + int self_id_count, u32 *self_ids, bool bm_abdicate) { struct fw_node *local_node; unsigned long flags; @@ -536,14 +529,13 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, */ if (!is_next_generation(generation, card->generation) && card->local_node != NULL) { - fw_notify("skipped bus generations, destroying all nodes\n"); fw_destroy_nodes(card); card->bm_retries = 0; } spin_lock_irqsave(&card->lock, flags); - card->broadcast_channel_allocated = false; + card->broadcast_channel_allocated = card->broadcast_channel_auto_allocated; card->node_id = node_id; /* * Update node_id before generation to prevent anybody from using @@ -551,7 +543,9 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, */ smp_wmb(); card->generation = generation; - card->reset_jiffies = jiffies; + card->reset_jiffies = get_jiffies_64(); + card->bm_node_id = 0xffff; + card->bm_abdicate = bm_abdicate; fw_schedule_bm_work(card, 0); local_node = build_tree(card, self_ids, self_id_count); @@ -561,7 +555,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, card->color++; if (local_node == NULL) { - fw_error("topology build failed\n"); + fw_err(card, "topology build failed\n"); /* FIXME: We need to issue a bus reset in this case. */ } else if (card->local_node == NULL) { card->local_node = local_node; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 495849eb13c..eb6935c8ad9 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -31,11 +31,13 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> +#include <linux/rculist.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/types.h> +#include <linux/workqueue.h> #include <asm/byteorder.h> @@ -72,6 +74,15 @@ #define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) #define PHY_IDENTIFIER(id) ((id) << 30) +/* returns 0 if the split timeout handler is already running */ +static int try_cancel_split_timeout(struct fw_transaction *t) +{ + if (t->is_split_transaction) + return del_timer(&t->split_timeout_timer); + else + return 1; +} + static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode) { @@ -81,7 +92,11 @@ static int close_transaction(struct fw_transaction *transaction, spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { - list_del(&t->link); + if (!try_cancel_split_timeout(t)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } + list_del_init(&t->link); card->tlabel_mask &= ~(1ULL << t->tlabel); break; } @@ -93,6 +108,7 @@ static int close_transaction(struct fw_transaction *transaction, return 0; } + timed_out: return -ENOENT; } @@ -121,6 +137,43 @@ int fw_cancel_transaction(struct fw_card *card, } EXPORT_SYMBOL(fw_cancel_transaction); +static void split_transaction_timeout_callback(unsigned long data) +{ + struct fw_transaction *t = (struct fw_transaction *)data; + struct fw_card *card = t->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + if (list_empty(&t->link)) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + list_del(&t->link); + card->tlabel_mask &= ~(1ULL << t->tlabel); + spin_unlock_irqrestore(&card->lock, flags); + + t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); +} + +static void start_split_transaction_timeout(struct fw_transaction *t, + struct fw_card *card) +{ + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + + t->is_split_transaction = true; + mod_timer(&t->split_timeout_timer, + jiffies + card->split_timeout_jiffies); + + spin_unlock_irqrestore(&card->lock, flags); +} + static void transmit_complete_callback(struct fw_packet *packet, struct fw_card *card, int status) { @@ -132,7 +185,7 @@ static void transmit_complete_callback(struct fw_packet *packet, close_transaction(t, card, RCODE_COMPLETE); break; case ACK_PENDING: - t->timestamp = packet->timestamp; + start_split_transaction_timeout(t, card); break; case ACK_BUSY_X: case ACK_BUSY_A: @@ -220,7 +273,7 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, break; default: - WARN(1, KERN_ERR "wrong tcode %d", tcode); + WARN(1, "wrong tcode %d\n", tcode); } common: packet->speed = speed; @@ -229,44 +282,70 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, packet->payload_mapped = false; } +static int allocate_tlabel(struct fw_card *card) +{ + int tlabel; + + tlabel = card->current_tlabel; + while (card->tlabel_mask & (1ULL << tlabel)) { + tlabel = (tlabel + 1) & 0x3f; + if (tlabel == card->current_tlabel) + return -EBUSY; + } + + card->current_tlabel = (tlabel + 1) & 0x3f; + card->tlabel_mask |= 1ULL << tlabel; + + return tlabel; +} + /** - * This function provides low-level access to the IEEE1394 transaction - * logic. Most C programs would use either fw_read(), fw_write() or - * fw_lock() instead - those function are convenience wrappers for - * this function. The fw_send_request() function is primarily - * provided as a flexible, one-stop entry point for languages bindings - * and protocol bindings. - * - * FIXME: Document this function further, in particular the possible - * values for rcode in the callback. In short, we map ACK_COMPLETE to - * RCODE_COMPLETE, internal errors set errno and set rcode to - * RCODE_SEND_ERROR (which is out of range for standard ieee1394 - * rcodes). All other rcodes are forwarded unchanged. For all - * errors, payload is NULL, length is 0. + * fw_send_request() - submit a request packet for transmission + * @card: interface to send the request at + * @t: transaction instance to which the request belongs + * @tcode: transaction code + * @destination_id: destination node ID, consisting of bus_ID and phy_ID + * @generation: bus generation in which request and response are valid + * @speed: transmission speed + * @offset: 48bit wide offset into destination's address space + * @payload: data payload for the request subaction + * @length: length of the payload, in bytes + * @callback: function to be called when the transaction is completed + * @callback_data: data to be passed to the transaction completion callback * - * Can not expect the callback to be called before the function - * returns, though this does happen in some cases (ACK_COMPLETE and - * errors). + * Submit a request packet into the asynchronous request transmission queue. + * Can be called from atomic context. If you prefer a blocking API, use + * fw_run_transaction() in a context that can sleep. * - * The payload is only used for write requests and must not be freed - * until the callback has been called. + * In case of lock requests, specify one of the firewire-core specific %TCODE_ + * constants instead of %TCODE_LOCK_REQUEST in @tcode. * - * @param card the card from which to send the request - * @param tcode the tcode for this transaction. Do not use - * TCODE_LOCK_REQUEST directly, instead use TCODE_LOCK_MASK_SWAP - * etc. to specify tcode and ext_tcode. - * @param node_id the destination node ID (bus ID and PHY ID concatenated) - * @param generation the generation for which node_id is valid - * @param speed the speed to use for sending the request - * @param offset the 48 bit offset on the destination node - * @param payload the data payload for the request subaction - * @param length the length in bytes of the data to read - * @param callback function to be called when the transaction is completed - * @param callback_data pointer to arbitrary data, which will be - * passed to the callback + * Make sure that the value in @destination_id is not older than the one in + * @generation. Otherwise the request is in danger to be sent to a wrong node. * - * In case of asynchronous stream packets i.e. TCODE_STREAM_DATA, the caller + * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller * needs to synthesize @destination_id with fw_stream_packet_destination_id(). + * It will contain tag, channel, and sy data instead of a node ID then. + * + * The payload buffer at @data is going to be DMA-mapped except in case of + * @length <= 8 or of local (loopback) requests. Hence make sure that the + * buffer complies with the restrictions of the streaming DMA mapping API. + * @payload must not be freed before the @callback is called. + * + * In case of request types without payload, @data is NULL and @length is 0. + * + * After the transaction is completed successfully or unsuccessfully, the + * @callback will be called. Among its parameters is the response code which + * is either one of the rcodes per IEEE 1394 or, in case of internal errors, + * the firewire-core specific %RCODE_SEND_ERROR. The other firewire-core + * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION, + * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request + * generation, or missing ACK respectively. + * + * Note some timing corner cases: fw_send_request() may complete much earlier + * than when the request packet actually hits the wire. On the other hand, + * transaction completion and hence execution of @callback may happen even + * before fw_send_request() returns. */ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, int destination_id, int generation, int speed, @@ -277,31 +356,25 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, int tlabel; /* - * Bump the flush timer up 100ms first of all so we - * don't race with a flush timer callback. - */ - - mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10)); - - /* * Allocate tlabel from the bitmap and put the transaction on * the list while holding the card spinlock. */ spin_lock_irqsave(&card->lock, flags); - tlabel = card->current_tlabel; - if (card->tlabel_mask & (1ULL << tlabel)) { + tlabel = allocate_tlabel(card); + if (tlabel < 0) { spin_unlock_irqrestore(&card->lock, flags); callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); return; } - card->current_tlabel = (card->current_tlabel + 1) & 0x3f; - card->tlabel_mask |= (1ULL << tlabel); - t->node_id = destination_id; t->tlabel = tlabel; + t->card = card; + t->is_split_transaction = false; + setup_timer(&t->split_timeout_timer, + split_transaction_timeout_callback, (unsigned long)t); t->callback = callback; t->callback_data = callback_data; @@ -336,9 +409,12 @@ static void transaction_callback(struct fw_card *card, int rcode, } /** - * fw_run_transaction - send request and sleep until transaction is completed + * fw_run_transaction() - send request and sleep until transaction is completed * - * Returns the RCODE. + * Returns the RCODE. See fw_send_request() for parameter documentation. + * Unlike fw_send_request(), @data points to the payload of the request or/and + * to the payload of the response. DMA mapping restrictions apply to outbound + * request payloads of >= 8 bytes but not to inbound response payloads. */ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, int generation, int speed, unsigned long long offset, @@ -347,11 +423,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, struct transaction_callback_data d; struct fw_transaction t; + init_timer_on_stack(&t.split_timeout_timer); init_completion(&d.done); d.payload = payload; fw_send_request(card, &t, tcode, destination_id, generation, speed, offset, payload, length, transaction_callback, &d); wait_for_completion(&d.done); + destroy_timer_on_stack(&t.split_timeout_timer); return d.rcode; } @@ -367,7 +445,8 @@ static void transmit_phy_packet_callback(struct fw_packet *packet, } static struct fw_packet phy_config_packet = { - .header_length = 8, + .header_length = 12, + .header[0] = TCODE_LINK_INTERNAL << 4, .payload_length = 0, .speed = SCODE_100, .callback = transmit_phy_packet_callback, @@ -377,16 +456,28 @@ void fw_send_phy_config(struct fw_card *card, int node_id, int generation, int gap_count) { long timeout = DIV_ROUND_UP(HZ, 10); - u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | - PHY_CONFIG_ROOT_ID(node_id) | - PHY_CONFIG_GAP_COUNT(gap_count); + u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG); + + if (node_id != FW_PHY_CONFIG_NO_NODE_ID) + data |= PHY_CONFIG_ROOT_ID(node_id); + + if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) { + gap_count = card->driver->read_phy_reg(card, 1); + if (gap_count < 0) + return; + + gap_count &= 63; + if (gap_count == 63) + return; + } + data |= PHY_CONFIG_GAP_COUNT(gap_count); mutex_lock(&phy_config_mutex); - phy_config_packet.header[0] = data; - phy_config_packet.header[1] = ~data; + phy_config_packet.header[1] = data; + phy_config_packet.header[2] = ~data; phy_config_packet.generation = generation; - INIT_COMPLETION(phy_config_done); + reinit_completion(&phy_config_done); card->driver->send_request(card, &phy_config_packet); wait_for_completion_timeout(&phy_config_done, timeout); @@ -394,36 +485,12 @@ void fw_send_phy_config(struct fw_card *card, mutex_unlock(&phy_config_mutex); } -void fw_flush_transactions(struct fw_card *card) -{ - struct fw_transaction *t, *next; - struct list_head list; - unsigned long flags; - - INIT_LIST_HEAD(&list); - spin_lock_irqsave(&card->lock, flags); - list_splice_init(&card->transaction_list, &list); - card->tlabel_mask = 0; - spin_unlock_irqrestore(&card->lock, flags); - - list_for_each_entry_safe(t, next, &list, link) { - card->driver->cancel_packet(card, &t->packet); - - /* - * At this point cancel_packet will never call the - * transaction callback, since we just took all the - * transactions out of the list. So do it here. - */ - t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); - } -} - static struct fw_address_handler *lookup_overlapping_address_handler( struct list_head *list, unsigned long long offset, size_t length) { struct fw_address_handler *handler; - list_for_each_entry(handler, list, link) { + list_for_each_entry_rcu(handler, list, link) { if (handler->offset < offset + length && offset < handler->offset + handler->length) return handler; @@ -444,7 +511,7 @@ static struct fw_address_handler *lookup_enclosing_address_handler( { struct fw_address_handler *handler; - list_for_each_entry(handler, list, link) { + list_for_each_entry_rcu(handler, list, link) { if (is_enclosing_handler(handler, offset, length)) return handler; } @@ -452,16 +519,17 @@ static struct fw_address_handler *lookup_enclosing_address_handler( return NULL; } -static DEFINE_SPINLOCK(address_handler_lock); +static DEFINE_SPINLOCK(address_handler_list_lock); static LIST_HEAD(address_handler_list); const struct fw_address_region fw_high_memory_region = - { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; + { .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, }; EXPORT_SYMBOL(fw_high_memory_region); +static const struct fw_address_region low_memory_region = + { .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, }; + #if 0 -const struct fw_address_region fw_low_memory_region = - { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; const struct fw_address_region fw_private_region = { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; const struct fw_address_region fw_csr_region = @@ -478,9 +546,9 @@ static bool is_in_fcp_region(u64 offset, size_t length) } /** - * fw_core_add_address_handler - register for incoming requests - * @handler: callback - * @region: region in the IEEE 1212 node space address range + * fw_core_add_address_handler() - register for incoming requests + * @handler: callback + * @region: region in the IEEE 1212 node space address range * * region->start, ->end, and handler->length have to be quadlet-aligned. * @@ -488,6 +556,7 @@ static bool is_in_fcp_region(u64 offset, size_t length) * the specified callback is invoked. The parameters passed to the callback * give the details of the particular request. * + * To be called in process context. * Return value: 0 on success, non-zero otherwise. * * The start offset of the handler's address region is determined by @@ -499,17 +568,16 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, const struct fw_address_region *region) { struct fw_address_handler *other; - unsigned long flags; int ret = -EBUSY; if (region->start & 0xffff000000000003ULL || - region->end & 0xffff000000000003ULL || region->start >= region->end || + region->end > 0x0001000000000000ULL || handler->length & 3 || handler->length == 0) return -EINVAL; - spin_lock_irqsave(&address_handler_lock, flags); + spin_lock(&address_handler_list_lock); handler->offset = region->start; while (handler->offset + handler->length <= region->end) { @@ -522,28 +590,32 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, if (other != NULL) { handler->offset += other->length; } else { - list_add_tail(&handler->link, &address_handler_list); + list_add_tail_rcu(&handler->link, &address_handler_list); ret = 0; break; } } - spin_unlock_irqrestore(&address_handler_lock, flags); + spin_unlock(&address_handler_list_lock); return ret; } EXPORT_SYMBOL(fw_core_add_address_handler); /** - * fw_core_remove_address_handler - unregister an address handler + * fw_core_remove_address_handler() - unregister an address handler + * + * To be called in process context. + * + * When fw_core_remove_address_handler() returns, @handler->callback() is + * guaranteed to not run on any CPU anymore. */ void fw_core_remove_address_handler(struct fw_address_handler *handler) { - unsigned long flags; - - spin_lock_irqsave(&address_handler_lock, flags); - list_del(&handler->link); - spin_unlock_irqrestore(&address_handler_lock, flags); + spin_lock(&address_handler_list_lock); + list_del_rcu(&handler->link); + spin_unlock(&address_handler_list_lock); + synchronize_rcu(); } EXPORT_SYMBOL(fw_core_remove_address_handler); @@ -564,6 +636,41 @@ static void free_response_callback(struct fw_packet *packet, kfree(request); } +int fw_get_response_length(struct fw_request *r) +{ + int tcode, ext_tcode, data_length; + + tcode = HEADER_GET_TCODE(r->request_header[0]); + + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + return 0; + + case TCODE_READ_QUADLET_REQUEST: + return 4; + + case TCODE_READ_BLOCK_REQUEST: + data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + return data_length; + + case TCODE_LOCK_REQUEST: + ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]); + data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + switch (ext_tcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + return data_length; + default: + return data_length / 2; + } + + default: + WARN(1, "wrong tcode %d\n", tcode); + return 0; + } +} + void fw_fill_response(struct fw_packet *response, u32 *request_header, int rcode, void *payload, size_t length) { @@ -615,18 +722,35 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header, break; default: - WARN(1, KERN_ERR "wrong tcode %d", tcode); + WARN(1, "wrong tcode %d\n", tcode); } response->payload_mapped = false; } EXPORT_SYMBOL(fw_fill_response); -static struct fw_request *allocate_request(struct fw_packet *p) +static u32 compute_split_timeout_timestamp(struct fw_card *card, + u32 request_timestamp) +{ + unsigned int cycles; + u32 timestamp; + + cycles = card->split_timeout_cycles; + cycles += request_timestamp & 0x1fff; + + timestamp = request_timestamp & ~0x1fff; + timestamp += (cycles / 8000) << 13; + timestamp |= cycles % 8000; + + return timestamp; +} + +static struct fw_request *allocate_request(struct fw_card *card, + struct fw_packet *p) { struct fw_request *request; u32 *data, length; - int request_tcode, t; + int request_tcode; request_tcode = HEADER_GET_TCODE(p->header[0]); switch (request_tcode) { @@ -652,7 +776,7 @@ static struct fw_request *allocate_request(struct fw_packet *p) break; default: - fw_error("ERROR - corrupt request received - %08x %08x %08x\n", + fw_notice(card, "ERROR - corrupt request received - %08x %08x %08x\n", p->header[0], p->header[1], p->header[2]); return NULL; } @@ -661,14 +785,9 @@ static struct fw_request *allocate_request(struct fw_packet *p) if (request == NULL) return NULL; - t = (p->timestamp & 0x1fff) + 4000; - if (t >= 8000) - t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000; - else - t = (p->timestamp & ~0x1fff) + t; - request->response.speed = p->speed; - request->response.timestamp = t; + request->response.timestamp = + compute_split_timeout_timestamp(card, p->timestamp); request->response.generation = p->generation; request->response.ack = 0; request->response.callback = free_response_callback; @@ -697,7 +816,8 @@ void fw_send_response(struct fw_card *card, if (rcode == RCODE_COMPLETE) fw_fill_response(&request->response, request->request_header, - rcode, request->data, request->length); + rcode, request->data, + fw_get_response_length(request)); else fw_fill_response(&request->response, request->request_header, rcode, NULL, 0); @@ -706,40 +826,42 @@ void fw_send_response(struct fw_card *card, } EXPORT_SYMBOL(fw_send_response); +/** + * fw_get_request_speed() - returns speed at which the @request was received + */ +int fw_get_request_speed(struct fw_request *request) +{ + return request->response.speed; +} +EXPORT_SYMBOL(fw_get_request_speed); + static void handle_exclusive_region_request(struct fw_card *card, struct fw_packet *p, struct fw_request *request, unsigned long long offset) { struct fw_address_handler *handler; - unsigned long flags; int tcode, destination, source; - tcode = HEADER_GET_TCODE(p->header[0]); destination = HEADER_GET_DESTINATION(p->header[0]); source = HEADER_GET_SOURCE(p->header[1]); + tcode = HEADER_GET_TCODE(p->header[0]); + if (tcode == TCODE_LOCK_REQUEST) + tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); - spin_lock_irqsave(&address_handler_lock, flags); + rcu_read_lock(); handler = lookup_enclosing_address_handler(&address_handler_list, offset, request->length); - spin_unlock_irqrestore(&address_handler_lock, flags); - - /* - * FIXME: lookup the fw_node corresponding to the sender of - * this request and pass that to the address handler instead - * of the node ID. We may also want to move the address - * allocations to fw_node so we only do this callback if the - * upper layers registered it for this node. - */ - - if (handler == NULL) - fw_send_response(card, request, RCODE_ADDRESS_ERROR); - else + if (handler) handler->address_callback(card, request, tcode, destination, source, - p->generation, p->speed, offset, + p->generation, offset, request->data, request->length, handler->callback_data); + rcu_read_unlock(); + + if (!handler) + fw_send_response(card, request, RCODE_ADDRESS_ERROR); } static void handle_fcp_region_request(struct fw_card *card, @@ -748,7 +870,6 @@ static void handle_fcp_region_request(struct fw_card *card, unsigned long long offset) { struct fw_address_handler *handler; - unsigned long flags; int tcode, destination, source; if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) && @@ -770,17 +891,17 @@ static void handle_fcp_region_request(struct fw_card *card, return; } - spin_lock_irqsave(&address_handler_lock, flags); - list_for_each_entry(handler, &address_handler_list, link) { + rcu_read_lock(); + list_for_each_entry_rcu(handler, &address_handler_list, link) { if (is_enclosing_handler(handler, offset, request->length)) handler->address_callback(card, NULL, tcode, destination, source, - p->generation, p->speed, - offset, request->data, + p->generation, offset, + request->data, request->length, handler->callback_data); } - spin_unlock_irqrestore(&address_handler_lock, flags); + rcu_read_unlock(); fw_send_response(card, request, RCODE_COMPLETE); } @@ -793,7 +914,12 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - request = allocate_request(p); + if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { + fw_cdev_handle_phy_packet(card, p); + return; + } + + request = allocate_request(card, p); if (request == NULL) { /* FIXME: send statically allocated busy packet. */ return; @@ -816,26 +942,30 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) unsigned long flags; u32 *data; size_t data_length; - int tcode, tlabel, destination, source, rcode; + int tcode, tlabel, source, rcode; - tcode = HEADER_GET_TCODE(p->header[0]); - tlabel = HEADER_GET_TLABEL(p->header[0]); - destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); - rcode = HEADER_GET_RCODE(p->header[1]); + tcode = HEADER_GET_TCODE(p->header[0]); + tlabel = HEADER_GET_TLABEL(p->header[0]); + source = HEADER_GET_SOURCE(p->header[1]); + rcode = HEADER_GET_RCODE(p->header[1]); spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t->node_id == source && t->tlabel == tlabel) { - list_del(&t->link); - card->tlabel_mask &= ~(1 << t->tlabel); + if (!try_cancel_split_timeout(t)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } + list_del_init(&t->link); + card->tlabel_mask &= ~(1ULL << t->tlabel); break; } } spin_unlock_irqrestore(&card->lock, flags); if (&t->link == &card->transaction_list) { - fw_notify("Unsolicited response (source %x, tlabel %x)\n", + timed_out: + fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", source, tlabel); return; } @@ -879,14 +1009,40 @@ 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, }; static void handle_topology_map(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, - int speed, unsigned long long offset, - void *payload, size_t length, void *callback_data) + unsigned long long offset, void *payload, size_t length, + void *callback_data) { int start; @@ -915,29 +1071,99 @@ static const struct fw_address_region registers_region = { .start = CSR_REGISTER_BASE, .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; +static void update_split_timeout(struct fw_card *card) +{ + unsigned int cycles; + + cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); + + /* minimum per IEEE 1394, maximum which doesn't overflow OHCI */ + cycles = clamp(cycles, 800u, 3u * 8000u); + + card->split_timeout_cycles = cycles; + card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000); +} + static void handle_registers(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, - int speed, unsigned long long offset, - void *payload, size_t length, void *callback_data) + unsigned long long offset, void *payload, size_t length, + void *callback_data) { int reg = offset & ~CSR_REGISTER_BASE; - unsigned long long bus_time; __be32 *data = payload; int rcode = RCODE_COMPLETE; + unsigned long flags; switch (reg) { + case CSR_PRIORITY_BUDGET: + if (!card->priority_budget_implemented) { + rcode = RCODE_ADDRESS_ERROR; + break; + } + /* else fall through */ + + case CSR_NODE_IDS: + /* + * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8 + * and 9.6, but interoperable with IEEE 1394.1-2004 bridges + */ + /* fall through */ + + case CSR_STATE_CLEAR: + case CSR_STATE_SET: case CSR_CYCLE_TIME: case CSR_BUS_TIME: - if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) { + case CSR_BUSY_TIMEOUT: + if (tcode == TCODE_READ_QUADLET_REQUEST) + *data = cpu_to_be32(card->driver->read_csr(card, reg)); + else if (tcode == TCODE_WRITE_QUADLET_REQUEST) + card->driver->write_csr(card, reg, be32_to_cpu(*data)); + else + rcode = RCODE_TYPE_ERROR; + break; + + case CSR_RESET_START: + if (tcode == TCODE_WRITE_QUADLET_REQUEST) + card->driver->write_csr(card, CSR_STATE_CLEAR, + CSR_STATE_BIT_ABDICATE); + else + rcode = RCODE_TYPE_ERROR; + break; + + case CSR_SPLIT_TIMEOUT_HI: + if (tcode == TCODE_READ_QUADLET_REQUEST) { + *data = cpu_to_be32(card->split_timeout_hi); + } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { + spin_lock_irqsave(&card->lock, flags); + card->split_timeout_hi = be32_to_cpu(*data) & 7; + update_split_timeout(card); + spin_unlock_irqrestore(&card->lock, flags); + } else { rcode = RCODE_TYPE_ERROR; - break; } + break; + + case CSR_SPLIT_TIMEOUT_LO: + if (tcode == TCODE_READ_QUADLET_REQUEST) { + *data = cpu_to_be32(card->split_timeout_lo); + } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { + spin_lock_irqsave(&card->lock, flags); + card->split_timeout_lo = + be32_to_cpu(*data) & 0xfff80000; + update_split_timeout(card); + spin_unlock_irqrestore(&card->lock, flags); + } else { + rcode = RCODE_TYPE_ERROR; + } + break; - bus_time = card->driver->get_bus_time(card); - if (reg == CSR_CYCLE_TIME) - *data = cpu_to_be32(bus_time); + case CSR_MAINT_UTILITY: + if (tcode == TCODE_READ_QUADLET_REQUEST) + *data = card->maint_utility_register; + else if (tcode == TCODE_WRITE_QUADLET_REQUEST) + card->maint_utility_register = *data; else - *data = cpu_to_be32(bus_time >> 25); + rcode = RCODE_TYPE_ERROR; break; case CSR_BROADCAST_CHANNEL: @@ -965,9 +1191,6 @@ static void handle_registers(struct fw_card *card, struct fw_request *request, BUG(); break; - case CSR_BUSY_TIMEOUT: - /* FIXME: Implement this. */ - default: rcode = RCODE_ADDRESS_ERROR; break; @@ -981,6 +1204,23 @@ static struct fw_address_handler registers = { .address_callback = handle_registers, }; +static void handle_low_memory(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *payload, size_t length, + void *callback_data) +{ + /* + * This catches requests not handled by the physical DMA unit, + * i.e., wrong transaction types or unauthorized source nodes. + */ + fw_send_response(card, request, RCODE_TYPE_ERROR); +} + +static struct fw_address_handler low_memory = { + .length = FW_MAX_PHYSICAL_RANGE, + .address_callback = handle_low_memory, +}; + MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); MODULE_LICENSE("GPL"); @@ -1022,18 +1262,26 @@ static int __init fw_core_init(void) { int ret; + fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0); + if (!fw_workqueue) + return -ENOMEM; + ret = bus_register(&fw_bus_type); - if (ret < 0) + if (ret < 0) { + destroy_workqueue(fw_workqueue); return ret; + } fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); + destroy_workqueue(fw_workqueue); return fw_cdev_major; } fw_core_add_address_handler(&topology_map, &topology_map_region); fw_core_add_address_handler(®isters, ®isters_region); + fw_core_add_address_handler(&low_memory, &low_memory_region); fw_core_add_descriptor(&vendor_id_descriptor); fw_core_add_descriptor(&model_id_descriptor); @@ -1044,6 +1292,7 @@ static void __exit fw_core_cleanup(void) { unregister_chrdev(fw_cdev_major, "firewire"); bus_unregister(&fw_bus_type); + destroy_workqueue(fw_workqueue); idr_destroy(&fw_device_idr); } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index ed3b1a765c0..e1480ff683d 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -1,6 +1,9 @@ #ifndef _FIREWIRE_CORE_H #define _FIREWIRE_CORE_H +#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> @@ -9,7 +12,7 @@ #include <linux/slab.h> #include <linux/types.h> -#include <asm/atomic.h> +#include <linux/atomic.h> struct device; struct fw_card; @@ -23,16 +26,29 @@ struct fw_packet; /* -card */ +extern __printf(2, 3) +void fw_err(const struct fw_card *card, const char *fmt, ...); +extern __printf(2, 3) +void fw_notice(const struct fw_card *card, const char *fmt, ...); + /* bitfields within the PHY registers */ #define PHY_LINK_ACTIVE 0x80 #define PHY_CONTENDER 0x40 #define PHY_BUS_RESET 0x40 +#define PHY_EXTENDED_REGISTERS 0xe0 #define PHY_BUS_SHORT_RESET 0x40 +#define PHY_INT_STATUS_BITS 0x3c +#define PHY_ENABLE_ACCEL 0x02 +#define PHY_ENABLE_MULTI 0x01 +#define PHY_PAGE_SELECT 0xe0 #define BANDWIDTH_AVAILABLE_INITIAL 4915 #define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31) #define BROADCAST_CHANNEL_VALID (1 << 30) +#define CSR_STATE_BIT_CMSTR (1 << 8) +#define CSR_STATE_BIT_ABDICATE (1 << 10) + struct fw_card_driver { /* * Enable the given card with the given initial config rom. @@ -43,6 +59,7 @@ struct fw_card_driver { int (*enable)(struct fw_card *card, const __be32 *config_rom, size_t length); + int (*read_phy_reg)(struct fw_card *card, int address); int (*update_phy_reg)(struct fw_card *card, int address, int clear_bits, int set_bits); @@ -70,7 +87,8 @@ struct fw_card_driver { int (*enable_phys_dma)(struct fw_card *card, int node_id, int generation); - u64 (*get_bus_time)(struct fw_card *card); + u32 (*read_csr)(struct fw_card *card, int csr_offset); + void (*write_csr)(struct fw_card *card, int csr_offset, u32 value); struct fw_iso_context * (*allocate_iso_context)(struct fw_card *card, @@ -80,11 +98,17 @@ struct fw_card_driver { int (*start_iso)(struct fw_iso_context *ctx, s32 cycle, u32 sync, u32 tags); + int (*set_iso_channels)(struct fw_iso_context *ctx, u64 *channels); + int (*queue_iso)(struct fw_iso_context *ctx, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, unsigned long payload); + void (*flush_queue_iso)(struct fw_iso_context *ctx); + + int (*flush_iso_completions)(struct fw_iso_context *ctx); + int (*stop_iso)(struct fw_iso_context *ctx); }; @@ -93,31 +117,16 @@ void fw_card_initialize(struct fw_card *card, int fw_card_add(struct fw_card *card, u32 max_receive, u32 link_speed, u64 guid); void fw_core_remove_card(struct fw_card *card); -int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); int fw_compute_block_crc(__be32 *block); void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); -static inline struct fw_card *fw_card_get(struct fw_card *card) -{ - kref_get(&card->kref); - - return card; -} - -void fw_card_release(struct kref *kref); - -static inline void fw_card_put(struct fw_card *card) -{ - kref_put(&card->kref, fw_card_release); -} - - /* -cdev */ extern const struct file_operations fw_device_ops; void fw_device_cdev_update(struct fw_device *device); void fw_device_cdev_remove(struct fw_device *device); +void fw_cdev_handle_phy_packet(struct fw_card *card, struct fw_packet *p); /* -device */ @@ -126,6 +135,18 @@ extern struct rw_semaphore fw_device_rwsem; extern struct idr fw_device_idr; extern int fw_cdev_major; +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) +{ + put_device(&device->device); +} + struct fw_device *fw_device_get_by_devt(dev_t devt); int fw_device_set_broadcast_channel(struct device *dev, void *gen); void fw_node_event(struct fw_card *card, struct fw_node *node, int event); @@ -133,10 +154,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); -void fw_iso_resource_manage(struct fw_card *card, int generation, - u64 channels_mask, int *channel, int *bandwidth, - bool allocate, __be32 buffer[2]); +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 */ @@ -187,7 +209,7 @@ static inline void fw_node_put(struct fw_node *node) } void fw_core_handle_bus_reset(struct fw_card *card, int node_id, - int generation, int self_id_count, u32 *self_ids); + int generation, int self_id_count, u32 *self_ids, bool bm_abdicate); void fw_destroy_nodes(struct fw_card *card); /* @@ -202,8 +224,11 @@ static inline bool is_next_generation(int new_generation, int old_generation) /* -transaction */ +#define TCODE_LINK_INTERNAL 0xe + #define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) #define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) +#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == TCODE_LINK_INTERNAL) #define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) #define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) #define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) @@ -211,12 +236,23 @@ static inline bool is_next_generation(int new_generation, int old_generation) #define LOCAL_BUS 0xffc0 +/* OHCI-1394's default upper bound for physical DMA: 4 GB */ +#define FW_MAX_PHYSICAL_RANGE (1ULL << 32) + void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); +int fw_get_response_length(struct fw_request *request); void fw_fill_response(struct fw_packet *response, u32 *request_header, int rcode, void *payload, size_t length); -void fw_flush_transactions(struct fw_card *card); + +#define FW_PHY_CONFIG_NO_NODE_ID -1 +#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1 void fw_send_phy_config(struct fw_card *card, int node_id, int generation, int gap_count); +static inline bool is_ping_packet(u32 *data) +{ + return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1]; +} + #endif /* _FIREWIRE_CORE_H */ diff --git a/drivers/firewire/init_ohci1394_dma.c b/drivers/firewire/init_ohci1394_dma.c new file mode 100644 index 00000000000..2cc89ce745c --- /dev/null +++ b/drivers/firewire/init_ohci1394_dma.c @@ -0,0 +1,309 @@ +/* + * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers + * + * Copyright (C) 2006-2007 Bernhard Kaindl <bk@suse.de> + * + * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c + * this file has functions to: + * - scan the PCI very early on boot for all OHCI 1394-compliant controllers + * - reset and initialize them and make them join the IEEE1394 bus and + * - enable physical DMA on them to allow remote debugging + * + * All code and data is marked as __init and __initdata, respective as + * during boot, all OHCI1394 controllers may be claimed by the firewire + * stack and at this point, this code should not touch them anymore. + * + * To use physical DMA after the initialization of the firewire stack, + * be sure that the stack enables it and (re-)attach after the bus reset + * which may be caused by the firewire stack initialization. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/pci.h> /* for PCI defines */ +#include <linux/string.h> + +#include <asm/pci-direct.h> /* for direct PCI config space access */ +#include <asm/fixmap.h> + +#include <linux/init_ohci1394_dma.h> +#include "ohci.h" + +int __initdata init_ohci1394_dma_early; + +struct ohci { + void __iomem *registers; +}; + +static inline void reg_write(const struct ohci *ohci, int offset, u32 data) +{ + writel(data, ohci->registers + offset); +} + +static inline u32 reg_read(const struct ohci *ohci, int offset) +{ + return readl(ohci->registers + offset); +} + +#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */ + +/* Reads a PHY register of an OHCI-1394 controller */ +static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr) +{ + int i; + u32 r; + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) + break; + mdelay(1); + } + r = reg_read(ohci, OHCI1394_PhyControl); + + return (r & 0x00ff0000) >> 16; +} + +/* Writes to a PHY register of an OHCI-1394 controller */ +static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data) +{ + int i; + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000)) + break; + mdelay(1); + } +} + +/* Resets an OHCI-1394 controller (for sane state before initialization) */ +static inline void __init init_ohci1394_soft_reset(struct ohci *ohci) +{ + int i; + + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (!(reg_read(ohci, OHCI1394_HCControlSet) + & OHCI1394_HCControl_softReset)) + break; + mdelay(1); + } +} + +#define OHCI1394_MAX_AT_REQ_RETRIES 0xf +#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 + +/* Basic OHCI-1394 register and port inititalization */ +static inline void __init init_ohci1394_initialize(struct ohci *ohci) +{ + u32 bus_options; + int num_ports, i; + + /* Put some defaults to these undefined bus options */ + bus_options = reg_read(ohci, OHCI1394_BusOptions); + bus_options |= 0x60000000; /* Enable CMC and ISC */ + bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ + bus_options &= ~0x18000000; /* Disable PMC and BMC */ + reg_write(ohci, OHCI1394_BusOptions, bus_options); + + /* Set the bus number */ + reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + + /* Enable posted writes */ + reg_write(ohci, OHCI1394_HCControlSet, + OHCI1394_HCControl_postedWriteEnable); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* enable phys */ + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_rcvPhyPkt); + + /* Don't accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); + + /* Clear the Isochonouys interrupt masks */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); + + /* Accept asynchronous transfer requests from all nodes for now */ + reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); + + /* Specify asynchronous transfer retries */ + reg_write(ohci, OHCI1394_ATRetries, + OHCI1394_MAX_AT_REQ_RETRIES | + (OHCI1394_MAX_AT_RESP_RETRIES<<4) | + (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); + + /* We don't want hardware swapping */ + reg_write(ohci, OHCI1394_HCControlClear, + OHCI1394_HCControl_noByteSwapData); + + /* Enable link */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); + + /* If anything is connected to a port, make sure it is enabled */ + num_ports = get_phy_reg(ohci, 2) & 0xf; + for (i = 0; i < num_ports; i++) { + unsigned int status; + + set_phy_reg(ohci, 7, i); + status = get_phy_reg(ohci, 8); + + if (status & 0x20) + set_phy_reg(ohci, 8, status & ~1); + } +} + +/** + * init_ohci1394_wait_for_busresets - wait until bus resets are completed + * + * OHCI1394 initialization itself and any device going on- or offline + * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec + * specifies that physical DMA is disabled on each bus reset and it + * has to be enabled after each bus reset when needed. We resort + * to polling here because on early boot, we have no interrupts. + */ +static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci) +{ + int i, events; + + for (i = 0; i < 9; i++) { + mdelay(200); + events = reg_read(ohci, OHCI1394_IntEventSet); + if (events & OHCI1394_busReset) + reg_write(ohci, OHCI1394_IntEventClear, + OHCI1394_busReset); + } +} + +/** + * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging + * This enables remote DMA access over IEEE1394 from every host for the low + * 4GB of address space. DMA accesses above 4GB are not available currently. + */ +static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci) +{ + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff); + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff); + reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000); +} + +/** + * init_ohci1394_reset_and_init_dma - init controller and enable DMA + * This initializes the given controller and enables physical DMA engine in it. + */ +static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci) +{ + /* Start off with a soft reset, clears everything to a sane state. */ + init_ohci1394_soft_reset(ohci); + + /* Accessing some registers without LPS enabled may cause lock up */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); + + /* Disable and clear interrupts */ + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + + mdelay(50); /* Wait 50msec to make sure we have full link enabled */ + + init_ohci1394_initialize(ohci); + /* + * The initialization causes at least one IEEE1394 bus reset. Enabling + * physical DMA only works *after* *all* bus resets have calmed down: + */ + init_ohci1394_wait_for_busresets(ohci); + + /* We had to wait and do this now if we want to debug early problems */ + init_ohci1394_enable_physical_dma(ohci); +} + +/** + * init_ohci1394_controller - Map the registers of the controller and init DMA + * This maps the registers of the specified controller and initializes it + */ +static inline void __init init_ohci1394_controller(int num, int slot, int func) +{ + unsigned long ohci_base; + struct ohci ohci; + + printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394" + " at %02x:%02x.%x\n", num, slot, func); + + ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2)) + & PCI_BASE_ADDRESS_MEM_MASK; + + set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base); + + ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE); + + init_ohci1394_reset_and_init_dma(&ohci); +} + +/** + * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them + * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them + */ +void __init init_ohci1394_dma_on_all_controllers(void) +{ + int num, slot, func; + u32 class; + + if (!early_pci_allowed()) + return; + + /* Poor man's PCI discovery, the only thing we can do at early boot */ + for (num = 0; num < 32; num++) { + for (slot = 0; slot < 32; slot++) { + for (func = 0; func < 8; func++) { + class = read_pci_config(num, slot, func, + PCI_CLASS_REVISION); + if (class == 0xffffffff) + continue; /* No device at this func */ + + if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI) + continue; /* Not an OHCI-1394 device */ + + init_ohci1394_controller(num, slot, func); + break; /* Assume one controller per device */ + } + } + } + printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n"); +} + +/** + * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization + */ +static int __init setup_ohci1394_dma(char *opt) +{ + if (!strcmp(opt, "early")) + init_ohci1394_dma_early = 1; + return 0; +} + +/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */ +early_param("ohci1394_dma", setup_ohci1394_dma); diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index cbaf420c36c..c3986452194 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1,5 +1,6 @@ /* * IPv4 over IEEE 1394, per RFC 2734 + * IPv6 over IEEE 1394, per RFC 3146 * * Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com> * @@ -7,6 +8,8 @@ */ #include <linux/bug.h> +#include <linux/compiler.h> +#include <linux/delay.h> #include <linux/device.h> #include <linux/ethtool.h> #include <linux/firewire.h> @@ -21,13 +24,21 @@ #include <linux/mutex.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <asm/unaligned.h> #include <net/arp.h> +#include <net/firewire.h> -#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */ -#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2) +/* rx limits */ +#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ +#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16*1024 ? 4 : 2) + +/* tx limits */ +#define FWNET_MAX_QUEUED_DATAGRAMS 20 /* < 64 = number of tlabels */ +#define FWNET_MIN_QUEUED_DATAGRAMS 10 /* should keep AT DMA busy enough */ +#define FWNET_TX_QUEUE_LEN FWNET_MAX_QUEUED_DATAGRAMS /* ? */ #define IEEE1394_BROADCAST_CHANNEL 31 #define IEEE1394_ALL_NODES (0xffc0 | 0x003f) @@ -36,6 +47,7 @@ #define IANA_SPECIFIER_ID 0x00005eU #define RFC2734_SW_VERSION 0x000001U +#define RFC3146_SW_VERSION 0x000002U #define IEEE1394_GASP_HDR_SIZE 8 @@ -48,32 +60,10 @@ #define RFC2374_HDR_LASTFRAG 2 /* last fragment */ #define RFC2374_HDR_INTFRAG 3 /* interior fragment */ -#define RFC2734_HW_ADDR_LEN 16 - -struct rfc2734_arp { - __be16 hw_type; /* 0x0018 */ - __be16 proto_type; /* 0x0806 */ - u8 hw_addr_len; /* 16 */ - u8 ip_addr_len; /* 4 */ - __be16 opcode; /* ARP Opcode */ - /* Above is exactly the same format as struct arphdr */ - - __be64 s_uniq_id; /* Sender's 64bit EUI */ - u8 max_rec; /* Sender's max packet size */ - u8 sspd; /* Sender's max speed */ - __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */ - __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */ - __be32 sip; /* Sender's IP Address */ - __be32 tip; /* IP Address of requested hw addr */ -} __attribute__((packed)); - -/* This header format is specific to this driver implementation. */ -#define FWNET_ALEN 8 -#define FWNET_HLEN 10 -struct fwnet_header { - u8 h_dest[FWNET_ALEN]; /* destination address */ - __be16 h_proto; /* packet type ID field */ -} __attribute__((packed)); +static bool fwnet_hwaddr_is_multicast(u8 *ha) +{ + return !!(*ha & 1); +} /* IPv4 and IPv6 encapsulation header */ struct rfc2734_header { @@ -169,16 +159,10 @@ struct fwnet_device { struct fw_address_handler handler; u64 local_fifo; - /* List of packets to be sent */ - struct list_head packet_list; - /* - * List of packets that were broadcasted. When we get an ISO interrupt - * one of them has been sent - */ - struct list_head broadcasted_list; - /* List of packets that have been sent but not yet acked */ - struct list_head sent_list; + /* Number of tx datagrams that have been queued but not yet acked */ + int queued_datagrams; + int peer_count; struct list_head peer_list; struct fw_card *card; struct net_device *netdev; @@ -188,14 +172,13 @@ struct fwnet_peer { struct list_head peer_link; struct fwnet_device *dev; u64 guid; - u64 fifo; /* guarded by dev->lock */ struct list_head pd_list; /* received partial datagrams */ unsigned pdg_size; /* pd_list size */ u16 datagram_label; /* outgoing datagram label */ - unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ + u16 max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */ int node_id; int generation; unsigned speed; @@ -203,25 +186,30 @@ struct fwnet_peer { /* This is our task struct. It's used for the packet complete callback. */ struct fwnet_packet_task { - /* - * ptask can actually be on dev->packet_list, dev->broadcasted_list, - * or dev->sent_list depending on its current state. - */ - struct list_head pt_link; struct fw_transaction transaction; struct rfc2734_header hdr; struct sk_buff *skb; struct fwnet_device *dev; int outstanding_pkts; - unsigned max_payload; u64 fifo_addr; u16 dest_node; + u16 max_payload; u8 generation; u8 speed; + u8 enqueued; }; /* + * Get fifo address embedded in hwaddr + */ +static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha) +{ + return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32 + | get_unaligned_be32(&ha->uc.fifo_lo); +} + +/* * saddr == NULL means use device source address. * daddr == NULL means leave destination address (eg unresolved arp). */ @@ -256,22 +244,22 @@ static int fwnet_header_rebuild(struct sk_buff *skb) if (get_unaligned_be16(&h->h_proto) == ETH_P_IP) return arp_find((unsigned char *)&h->h_dest, skb); - fw_notify("%s: unable to resolve type %04x addresses\n", - skb->dev->name, be16_to_cpu(h->h_proto)); + dev_notice(&skb->dev->dev, "unable to resolve type %04x addresses\n", + be16_to_cpu(h->h_proto)); return 0; } static int fwnet_header_cache(const struct neighbour *neigh, - struct hh_cache *hh) + struct hh_cache *hh, __be16 type) { struct net_device *net; struct fwnet_header *h; - if (hh->hh_type == cpu_to_be16(ETH_P_802_3)) + if (type == cpu_to_be16(ETH_P_802_3)) return -1; net = neigh->dev; - h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h)); - h->h_proto = hh->hh_type; + h = (struct fwnet_header *)((u8 *)hh->hh_data + HH_DATA_OFF(sizeof(*h))); + h->h_proto = type; memcpy(h->h_dest, neigh->ha, net->addr_len); hh->hh_len = FWNET_HLEN; @@ -282,7 +270,7 @@ static int fwnet_header_cache(const struct neighbour *neigh, static void fwnet_header_cache_update(struct hh_cache *hh, const struct net_device *net, const unsigned char *haddr) { - memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len); + memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len); } static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr) @@ -368,10 +356,8 @@ static struct fwnet_fragment_info *fwnet_frag_new( } new = kmalloc(sizeof(*new), GFP_ATOMIC); - if (!new) { - fw_error("out of memory\n"); + if (!new) return NULL; - } new->offset = offset; new->len = len; @@ -398,11 +384,11 @@ static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net, new->datagram_label = datagram_label; new->datagram_size = dg_size; - new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15); + new->skb = dev_alloc_skb(dg_size + LL_RESERVED_SPACE(net)); if (new->skb == NULL) goto fail_w_fi; - skb_reserve(new->skb, (net->hard_header_len + 15) & ~15); + skb_reserve(new->skb, LL_RESERVED_SPACE(net)); new->pbuf = skb_put(new->skb, dg_size); memcpy(new->pbuf + frag_off, frag_buf, frag_len); list_add_tail(&new->pd_link, &peer->pd_list); @@ -414,8 +400,6 @@ fail_w_fi: fail_w_new: kfree(new); fail: - fw_error("out of memory\n"); - return NULL; } @@ -454,7 +438,7 @@ static bool fwnet_pd_update(struct fwnet_peer *peer, memcpy(pd->pbuf + frag_off, frag_buf, frag_len); /* - * Move list entry to beginnig of list so that oldest partial + * Move list entry to beginning of list so that oldest partial * datagrams percolate to the end of the list */ list_move_tail(&pd->pd_link, &peer->pd_list); @@ -502,11 +486,7 @@ static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev, static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed) { max_rec = min(max_rec, speed + 8); - max_rec = min(max_rec, 0xbU); /* <= 4096 */ - if (max_rec < 8) { - fw_notify("max_rec %x out of range\n", max_rec); - max_rec = 8; - } + max_rec = clamp(max_rec, 8U, 11U); /* 512...4096 */ return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE; } @@ -517,100 +497,32 @@ static int fwnet_finish_incoming_packet(struct net_device *net, bool is_broadcast, u16 ether_type) { struct fwnet_device *dev; - static const __be64 broadcast_hw = cpu_to_be64(~0ULL); int status; __be64 guid; + switch (ether_type) { + case ETH_P_ARP: + case ETH_P_IP: +#if IS_ENABLED(CONFIG_IPV6) + case ETH_P_IPV6: +#endif + break; + default: + goto err; + } + dev = netdev_priv(net); /* Write metadata, and then pass to the receive level */ skb->dev = net; - skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + skb->ip_summed = CHECKSUM_NONE; /* * Parse the encapsulation header. This actually does the job of - * converting to an ethernet frame header, as well as arp - * conversion if needed. ARP conversion is easier in this - * direction, since we are using ethernet as our backend. - */ - /* - * If this is an ARP packet, convert it. First, we want to make - * use of some of the fields, since they tell us a little bit - * about the sending machine. + * converting to an ethernet-like pseudo frame header. */ - if (ether_type == ETH_P_ARP) { - struct rfc2734_arp *arp1394; - struct arphdr *arp; - unsigned char *arp_ptr; - u64 fifo_addr; - u64 peer_guid; - unsigned sspd; - u16 max_payload; - struct fwnet_peer *peer; - unsigned long flags; - - arp1394 = (struct rfc2734_arp *)skb->data; - arp = (struct arphdr *)skb->data; - arp_ptr = (unsigned char *)(arp + 1); - peer_guid = get_unaligned_be64(&arp1394->s_uniq_id); - fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32 - | get_unaligned_be32(&arp1394->fifo_lo); - - sspd = arp1394->sspd; - /* Sanity check. OS X 10.3 PPC reportedly sends 131. */ - if (sspd > SCODE_3200) { - fw_notify("sspd %x out of range\n", sspd); - sspd = SCODE_3200; - } - max_payload = fwnet_max_payload(arp1394->max_rec, sspd); - - spin_lock_irqsave(&dev->lock, flags); - peer = fwnet_peer_find_by_guid(dev, peer_guid); - if (peer) { - peer->fifo = fifo_addr; - - if (peer->speed > sspd) - peer->speed = sspd; - if (peer->max_payload > max_payload) - peer->max_payload = max_payload; - } - spin_unlock_irqrestore(&dev->lock, flags); - - if (!peer) { - fw_notify("No peer for ARP packet from %016llx\n", - (unsigned long long)peer_guid); - goto failed_proto; - } - - /* - * Now that we're done with the 1394 specific stuff, we'll - * need to alter some of the data. Believe it or not, all - * that needs to be done is sender_IP_address needs to be - * moved, the destination hardware address get stuffed - * in and the hardware address length set to 8. - * - * IMPORTANT: The code below overwrites 1394 specific data - * needed above so keep the munging of the data for the - * higher level IP stack last. - */ - - arp->ar_hln = 8; - /* skip over sender unique id */ - arp_ptr += arp->ar_hln; - /* move sender IP addr */ - put_unaligned(arp1394->sip, (u32 *)arp_ptr); - /* skip over sender IP addr */ - arp_ptr += arp->ar_pln; - - if (arp->ar_op == htons(ARPOP_REQUEST)) - memset(arp_ptr, 0, sizeof(u64)); - else - memcpy(arp_ptr, net->dev_addr, sizeof(u64)); - } - - /* Now add the ethernet header. */ guid = cpu_to_be64(dev->card->guid); if (dev_hard_header(skb, net, ether_type, - is_broadcast ? &broadcast_hw : &guid, + is_broadcast ? net->broadcast : net->dev_addr, NULL, skb->len) >= 0) { struct fwnet_header *eth; u16 *rawp; @@ -619,7 +531,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, skb_reset_mac_header(skb); skb_pull(skb, sizeof(*eth)); eth = (struct fwnet_header *)skb_mac_header(skb); - if (*eth->h_dest & 1) { + if (fwnet_hwaddr_is_multicast(eth->h_dest)) { if (memcmp(eth->h_dest, net->broadcast, net->addr_len) == 0) skb->pkt_type = PACKET_BROADCAST; @@ -631,7 +543,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, if (memcmp(eth->h_dest, net->dev_addr, net->addr_len)) skb->pkt_type = PACKET_OTHERHOST; } - if (ntohs(eth->h_proto) >= 1536) { + if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) { protocol = eth->h_proto; } else { rawp = (u16 *)skb->data; @@ -650,20 +562,16 @@ static int fwnet_finish_incoming_packet(struct net_device *net, net->stats.rx_packets++; net->stats.rx_bytes += skb->len; } - if (netif_queue_stopped(net)) - netif_wake_queue(net); return 0; - failed_proto: + err: net->stats.rx_errors++; net->stats.rx_dropped++; dev_kfree_skb_any(skb); - if (netif_queue_stopped(net)) - netif_wake_queue(net); - return 0; + return -ENOENT; } static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, @@ -695,14 +603,13 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, buf++; len -= RFC2374_UNFRAG_HDR_SIZE; - skb = dev_alloc_skb(len + net->hard_header_len + 15); + skb = dev_alloc_skb(len + LL_RESERVED_SPACE(net)); if (unlikely(!skb)) { - fw_error("out of memory\n"); net->stats.rx_dropped++; - return -1; + return -ENOMEM; } - skb_reserve(skb, (net->hard_header_len + 15) & ~15); + skb_reserve(skb, LL_RESERVED_SPACE(net)); memcpy(skb_put(skb, len), buf, len); return fwnet_finish_incoming_packet(net, skb, source_node_id, @@ -725,8 +632,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, spin_lock_irqsave(&dev->lock, flags); peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation); - if (!peer) - goto bad_proto; + if (!peer) { + retval = -ENOENT; + goto fail; + } pd = fwnet_pd_find(peer, datagram_label); if (pd == NULL) { @@ -740,7 +649,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, dg_size, buf, fg_off, len); if (pd == NULL) { retval = -ENOMEM; - goto bad_proto; + goto fail; } peer->pdg_size++; } else { @@ -754,9 +663,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, pd = fwnet_pd_new(net, peer, datagram_label, dg_size, buf, fg_off, len); if (pd == NULL) { - retval = -ENOMEM; peer->pdg_size--; - goto bad_proto; + retval = -ENOMEM; + goto fail; } } else { if (!fwnet_pd_update(peer, pd, buf, fg_off, len)) { @@ -767,7 +676,8 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, */ fwnet_pd_delete(pd); peer->pdg_size--; - goto bad_proto; + retval = -ENOMEM; + goto fail; } } } /* new datagram or add to existing one */ @@ -790,23 +700,17 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, * Datagram is not complete, we're done for the * moment. */ + retval = 0; + fail: spin_unlock_irqrestore(&dev->lock, flags); - return 0; - - bad_proto: - spin_unlock_irqrestore(&dev->lock, flags); - - if (netif_queue_stopped(net)) - netif_wake_queue(net); - - return 0; + return retval; } static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, int tcode, int destination, int source, int generation, - int speed, unsigned long long offset, void *payload, - size_t length, void *callback_data) + unsigned long long offset, void *payload, size_t length, + void *callback_data) { struct fwnet_device *dev = callback_data; int rcode; @@ -823,7 +727,7 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, rcode = RCODE_TYPE_ERROR; else if (fwnet_incoming_packet(dev, payload, length, source, generation, false) != 0) { - fw_error("Incoming packet failure\n"); + dev_err(&dev->netdev->dev, "incoming packet failure\n"); rcode = RCODE_CONFLICT_ERROR; } else rcode = RCODE_COMPLETE; @@ -836,7 +740,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, { struct fwnet_device *dev; struct fw_iso_packet packet; - struct fw_card *card; __be16 *hdr_ptr; __be32 *buf_ptr; int retval; @@ -848,7 +751,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, unsigned long flags; dev = data; - card = dev->card; hdr_ptr = header; length = be16_to_cpup(hdr_ptr); @@ -866,11 +768,16 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; - if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) { + if (specifier_id == IANA_SPECIFIER_ID && + (ver == RFC2734_SW_VERSION +#if IS_ENABLED(CONFIG_IPV6) + || ver == RFC3146_SW_VERSION +#endif + )) { buf_ptr += 2; length -= IEEE1394_GASP_HDR_SIZE; - fwnet_incoming_packet(dev, buf_ptr, length, - source_node_id, -1, true); + fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, + context->card->generation, true); } packet.payload_length = dev->rcv_buffer_size; @@ -887,33 +794,57 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, spin_unlock_irqrestore(&dev->lock, flags); - if (retval < 0) - fw_error("requeue failed\n"); + if (retval >= 0) + fw_iso_context_queue_flush(dev->broadcast_rcv_context); + else + dev_err(&dev->netdev->dev, "requeue failed\n"); } static struct kmem_cache *fwnet_packet_task_cache; +static void fwnet_free_ptask(struct fwnet_packet_task *ptask) +{ + dev_kfree_skb_any(ptask->skb); + kmem_cache_free(fwnet_packet_task_cache, ptask); +} + +/* Caller must hold dev->lock. */ +static void dec_queued_datagrams(struct fwnet_device *dev) +{ + if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS) + netif_wake_queue(dev->netdev); +} + static int fwnet_send_packet(struct fwnet_packet_task *ptask); static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) { - struct fwnet_device *dev; + struct fwnet_device *dev = ptask->dev; + struct sk_buff *skb = ptask->skb; unsigned long flags; - - dev = ptask->dev; + bool free; spin_lock_irqsave(&dev->lock, flags); - list_del(&ptask->pt_link); - spin_unlock_irqrestore(&dev->lock, flags); - ptask->outstanding_pkts--; /* FIXME access inside lock */ + ptask->outstanding_pkts--; + + /* Check whether we or the networking TX soft-IRQ is last user. */ + free = (ptask->outstanding_pkts == 0 && ptask->enqueued); + if (free) + dec_queued_datagrams(dev); + + if (ptask->outstanding_pkts == 0) { + dev->netdev->stats.tx_packets++; + dev->netdev->stats.tx_bytes += skb->len; + } + + spin_unlock_irqrestore(&dev->lock, flags); if (ptask->outstanding_pkts > 0) { u16 dg_size; u16 fg_off; u16 datagram_label; u16 lf; - struct sk_buff *skb; /* Update the ptask to point to the next fragment and send it */ lf = fwnet_get_hdr_lf(&ptask->hdr); @@ -921,9 +852,10 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) case RFC2374_HDR_LASTFRAG: case RFC2374_HDR_UNFRAG: default: - fw_error("Outstanding packet %x lf %x, header %x,%x\n", - ptask->outstanding_pkts, lf, ptask->hdr.w0, - ptask->hdr.w1); + dev_err(&dev->netdev->dev, + "outstanding packet %x lf %x, header %x,%x\n", + ptask->outstanding_pkts, lf, ptask->hdr.w0, + ptask->hdr.w1); BUG(); case RFC2374_HDR_FIRSTFRAG: @@ -940,8 +872,13 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) datagram_label = fwnet_get_hdr_dgl(&ptask->hdr); break; } - skb = ptask->skb; - skb_pull(skb, ptask->max_payload); + + if (ptask->dest_node == IEEE1394_ALL_NODES) { + skb_pull(skb, + ptask->max_payload + IEEE1394_GASP_HDR_SIZE); + } else { + skb_pull(skb, ptask->max_payload); + } if (ptask->outstanding_pkts > 1) { fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG, dg_size, fg_off, datagram_label); @@ -951,24 +888,59 @@ static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask) ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE; } fwnet_send_packet(ptask); - } else { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); } + + if (free) + fwnet_free_ptask(ptask); +} + +static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask) +{ + struct fwnet_device *dev = ptask->dev; + unsigned long flags; + bool free; + + spin_lock_irqsave(&dev->lock, flags); + + /* One fragment failed; don't try to send remaining fragments. */ + ptask->outstanding_pkts = 0; + + /* Check whether we or the networking TX soft-IRQ is last user. */ + free = ptask->enqueued; + if (free) + dec_queued_datagrams(dev); + + dev->netdev->stats.tx_dropped++; + dev->netdev->stats.tx_errors++; + + spin_unlock_irqrestore(&dev->lock, flags); + + if (free) + fwnet_free_ptask(ptask); } static void fwnet_write_complete(struct fw_card *card, int rcode, void *payload, size_t length, void *data) { - struct fwnet_packet_task *ptask; - - ptask = data; + struct fwnet_packet_task *ptask = data; + static unsigned long j; + static int last_rcode, errors_skipped; - if (rcode == RCODE_COMPLETE) + if (rcode == RCODE_COMPLETE) { fwnet_transmit_packet_done(ptask); - else - fw_error("fwnet_write_complete: failed: %x\n", rcode); - /* ??? error recovery */ + } else { + if (printk_timed_ratelimit(&j, 1000) || rcode != last_rcode) { + dev_err(&ptask->dev->netdev->dev, + "fwnet_write_complete failed: %x (skipped %d)\n", + rcode, errors_skipped); + + errors_skipped = 0; + last_rcode = rcode; + } else { + errors_skipped++; + } + fwnet_transmit_packet_failed(ptask); + } } static int fwnet_send_packet(struct fwnet_packet_task *ptask) @@ -977,6 +949,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) unsigned tx_len; struct rfc2734_header *bufhdr; unsigned long flags; + bool free; dev = ptask->dev; tx_len = ptask->max_payload; @@ -1003,16 +976,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) u8 *p; int generation; int node_id; + unsigned int sw_version; /* ptask->generation may not have been set yet */ generation = dev->card->generation; smp_rmb(); node_id = dev->card->node_id; - p = skb_push(ptask->skb, 8); + switch (ptask->skb->protocol) { + default: + sw_version = RFC2734_SW_VERSION; + break; +#if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): + sw_version = RFC3146_SW_VERSION; +#endif + } + + p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE); put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p); put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 - | RFC2734_SW_VERSION, &p[4]); + | sw_version, &p[4]); /* We should not transmit if broadcast_channel.valid == 0. */ fw_send_request(dev->card, &ptask->transaction, @@ -1022,12 +1006,18 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) generation, SCODE_100, 0ULL, ptask->skb->data, tx_len + 8, fwnet_write_complete, ptask); - /* FIXME race? */ spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&ptask->pt_link, &dev->broadcasted_list); + + /* If the AT tasklet already ran, we may be last user. */ + free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); + if (!free) + ptask->enqueued = true; + else + dec_queued_datagrams(dev); + spin_unlock_irqrestore(&dev->lock, flags); - return 0; + goto out; } fw_send_request(dev->card, &ptask->transaction, @@ -1035,16 +1025,81 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) ptask->generation, ptask->speed, ptask->fifo_addr, ptask->skb->data, tx_len, fwnet_write_complete, ptask); - /* FIXME race? */ spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&ptask->pt_link, &dev->sent_list); + + /* If the AT tasklet already ran, we may be last user. */ + free = (ptask->outstanding_pkts == 0 && !ptask->enqueued); + if (!free) + ptask->enqueued = true; + else + dec_queued_datagrams(dev); + spin_unlock_irqrestore(&dev->lock, flags); dev->netdev->trans_start = jiffies; + out: + if (free) + fwnet_free_ptask(ptask); + + return 0; +} + +static void fwnet_fifo_stop(struct fwnet_device *dev) +{ + if (dev->local_fifo == FWNET_NO_FIFO_ADDR) + return; + + fw_core_remove_address_handler(&dev->handler); + dev->local_fifo = FWNET_NO_FIFO_ADDR; +} + +static int fwnet_fifo_start(struct fwnet_device *dev) +{ + int retval; + + if (dev->local_fifo != FWNET_NO_FIFO_ADDR) + return 0; + + dev->handler.length = 4096; + dev->handler.address_callback = fwnet_receive_packet; + dev->handler.callback_data = dev; + + retval = fw_core_add_address_handler(&dev->handler, + &fw_high_memory_region); + if (retval < 0) + return retval; + + dev->local_fifo = dev->handler.offset; return 0; } +static void __fwnet_broadcast_stop(struct fwnet_device *dev) +{ + unsigned u; + + if (dev->broadcast_state != FWNET_BROADCAST_ERROR) { + for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) + kunmap(dev->broadcast_rcv_buffer.pages[u]); + fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card); + } + if (dev->broadcast_rcv_context) { + fw_iso_context_destroy(dev->broadcast_rcv_context); + dev->broadcast_rcv_context = NULL; + } + kfree(dev->broadcast_rcv_buffer_ptrs); + dev->broadcast_rcv_buffer_ptrs = NULL; + dev->broadcast_state = FWNET_BROADCAST_ERROR; +} + +static void fwnet_broadcast_stop(struct fwnet_device *dev) +{ + if (dev->broadcast_state == FWNET_BROADCAST_ERROR) + return; + fw_iso_context_stop(dev->broadcast_rcv_context); + __fwnet_broadcast_stop(dev); +} + static int fwnet_broadcast_start(struct fwnet_device *dev) { struct fw_iso_context *context; @@ -1053,65 +1108,47 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) unsigned max_receive; struct fw_iso_packet packet; unsigned long offset; + void **ptrptr; unsigned u; - if (dev->local_fifo == FWNET_NO_FIFO_ADDR) { - /* outside OHCI posted write area? */ - static const struct fw_address_region region = { - .start = 0xffff00000000ULL, - .end = CSR_REGISTER_BASE, - }; - - dev->handler.length = 4096; - dev->handler.address_callback = fwnet_receive_packet; - dev->handler.callback_data = dev; - - retval = fw_core_add_address_handler(&dev->handler, ®ion); - if (retval < 0) - goto failed_initial; - - dev->local_fifo = dev->handler.offset; - } + if (dev->broadcast_state != FWNET_BROADCAST_ERROR) + return 0; max_receive = 1U << (dev->card->max_receive + 1); num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive; - if (!dev->broadcast_rcv_context) { - void **ptrptr; - - context = fw_iso_context_create(dev->card, - FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL, - dev->card->link_speed, 8, fwnet_receive_broadcast, dev); - if (IS_ERR(context)) { - retval = PTR_ERR(context); - goto failed_context_create; - } + ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); + if (!ptrptr) { + retval = -ENOMEM; + goto failed; + } + dev->broadcast_rcv_buffer_ptrs = ptrptr; + + context = fw_iso_context_create(dev->card, FW_ISO_CONTEXT_RECEIVE, + IEEE1394_BROADCAST_CHANNEL, + dev->card->link_speed, 8, + fwnet_receive_broadcast, dev); + if (IS_ERR(context)) { + retval = PTR_ERR(context); + goto failed; + } - retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, - dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE); - if (retval < 0) - goto failed_buffer_init; + retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, dev->card, + FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE); + if (retval < 0) + goto failed; - ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL); - if (!ptrptr) { - retval = -ENOMEM; - goto failed_ptrs_alloc; - } + dev->broadcast_state = FWNET_BROADCAST_STOPPED; - dev->broadcast_rcv_buffer_ptrs = ptrptr; - for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) { - void *ptr; - unsigned v; + for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) { + void *ptr; + unsigned v; - ptr = kmap(dev->broadcast_rcv_buffer.pages[u]); - for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++) - *ptrptr++ = (void *) - ((char *)ptr + v * max_receive); - } - dev->broadcast_rcv_context = context; - } else { - context = dev->broadcast_rcv_context; + ptr = kmap(dev->broadcast_rcv_buffer.pages[u]); + for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++) + *ptrptr++ = (void *) ((char *)ptr + v * max_receive); } + dev->broadcast_rcv_context = context; packet.payload_length = max_receive; packet.interrupt = 1; @@ -1125,7 +1162,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) retval = fw_iso_context_queue(context, &packet, &dev->broadcast_rcv_buffer, offset); if (retval < 0) - goto failed_rcv_queue; + goto failed; offset += max_receive; } @@ -1135,7 +1172,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) retval = fw_iso_context_start(context, -1, 0, FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */ if (retval < 0) - goto failed_rcv_queue; + goto failed; /* FIXME: adjust it according to the min. speed of all known peers? */ dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100 @@ -1144,44 +1181,45 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) return 0; - failed_rcv_queue: - kfree(dev->broadcast_rcv_buffer_ptrs); - dev->broadcast_rcv_buffer_ptrs = NULL; - failed_ptrs_alloc: - fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card); - failed_buffer_init: - fw_iso_context_destroy(context); - dev->broadcast_rcv_context = NULL; - failed_context_create: - fw_core_remove_address_handler(&dev->handler); - failed_initial: - dev->local_fifo = FWNET_NO_FIFO_ADDR; - + failed: + __fwnet_broadcast_stop(dev); return retval; } +static void set_carrier_state(struct fwnet_device *dev) +{ + if (dev->peer_count > 1) + netif_carrier_on(dev->netdev); + else + netif_carrier_off(dev->netdev); +} + /* ifup */ static int fwnet_open(struct net_device *net) { struct fwnet_device *dev = netdev_priv(net); int ret; - if (dev->broadcast_state == FWNET_BROADCAST_ERROR) { - ret = fwnet_broadcast_start(dev); - if (ret) - return ret; - } + ret = fwnet_broadcast_start(dev); + if (ret) + return ret; + netif_start_queue(net); + spin_lock_irq(&dev->lock); + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); + return 0; } /* ifdown */ static int fwnet_stop(struct net_device *net) { - netif_stop_queue(net); + struct fwnet_device *dev = netdev_priv(net); - /* Deallocate iso context for use by other applications? */ + netif_stop_queue(net); + fwnet_broadcast_stop(dev); return 0; } @@ -1199,6 +1237,15 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) struct fwnet_peer *peer; unsigned long flags; + spin_lock_irqsave(&dev->lock, flags); + + /* Can this happen? */ + if (netif_queue_stopped(dev->netdev)) { + spin_unlock_irqrestore(&dev->lock, flags); + + return NETDEV_TX_BUSY; + } + ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC); if (ptask == NULL) goto fail; @@ -1212,22 +1259,27 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) * We might need to rebuild the header on tx failure. */ memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); - skb_pull(skb, sizeof(hdr_buf)); - proto = hdr_buf.h_proto; - dg_size = skb->len; - /* serialize access to peer, including peer->datagram_label */ - spin_lock_irqsave(&dev->lock, flags); + switch (proto) { + case htons(ETH_P_ARP): + case htons(ETH_P_IP): +#if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +#endif + break; + default: + goto fail; + } + + skb_pull(skb, sizeof(hdr_buf)); + dg_size = skb->len; /* * Set the transmission type for the packet. ARP packets and IP * broadcast packets are sent via GASP. */ - if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0 - || proto == htons(ETH_P_ARP) - || (proto == htons(ETH_P_IP) - && IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { + if (fwnet_hwaddr_is_multicast(hdr_buf.h_dest)) { max_payload = dev->broadcast_xmt_max_payload; datagram_label_ptr = &dev->broadcast_xmt_datagramlabel; @@ -1236,44 +1288,25 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ptask->dest_node = IEEE1394_ALL_NODES; ptask->speed = SCODE_100; } else { - __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest); + union fwnet_hwaddr *ha = (union fwnet_hwaddr *)hdr_buf.h_dest; + __be64 guid = get_unaligned(&ha->uc.uniq_id); u8 generation; peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); - if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) - goto fail_unlock; + if (!peer) + goto fail; generation = peer->generation; dest_node = peer->node_id; max_payload = peer->max_payload; datagram_label_ptr = &peer->datagram_label; - ptask->fifo_addr = peer->fifo; + ptask->fifo_addr = fwnet_hwaddr_fifo(ha); ptask->generation = generation; ptask->dest_node = dest_node; ptask->speed = peer->speed; } - /* If this is an ARP packet, convert it */ - if (proto == htons(ETH_P_ARP)) { - struct arphdr *arp = (struct arphdr *)skb->data; - unsigned char *arp_ptr = (unsigned char *)(arp + 1); - struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data; - __be32 ipaddr; - - ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN)); - - arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN; - arp1394->max_rec = dev->card->max_receive; - arp1394->sspd = dev->card->link_speed; - - put_unaligned_be16(dev->local_fifo >> 32, - &arp1394->fifo_hi); - put_unaligned_be32(dev->local_fifo & 0xffffffff, - &arp1394->fifo_lo); - put_unaligned(ipaddr, &arp1394->sip); - } - ptask->hdr.w0 = 0; ptask->hdr.w1 = 0; ptask->skb = skb; @@ -1295,16 +1328,21 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) max_payload += RFC2374_FRAG_HDR_SIZE; } + if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS) + netif_stop_queue(dev->netdev); + spin_unlock_irqrestore(&dev->lock, flags); ptask->max_payload = max_payload; + ptask->enqueued = 0; + fwnet_send_packet(ptask); return NETDEV_TX_OK; - fail_unlock: - spin_unlock_irqrestore(&dev->lock, flags); fail: + spin_unlock_irqrestore(&dev->lock, flags); + if (ptask) kmem_cache_free(fwnet_packet_task_cache, ptask); @@ -1333,15 +1371,8 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu) return 0; } -static void fwnet_get_drvinfo(struct net_device *net, - struct ethtool_drvinfo *info) -{ - strcpy(info->driver, KBUILD_MODNAME); - strcpy(info->bus_info, "ieee1394"); -} - static const struct ethtool_ops fwnet_ethtool_ops = { - .get_drvinfo = fwnet_get_drvinfo, + .get_link = ethtool_op_get_link, }; static const struct net_device_ops fwnet_netdev_ops = { @@ -1361,8 +1392,8 @@ static void fwnet_init_dev(struct net_device *net) net->addr_len = FWNET_ALEN; net->hard_header_len = FWNET_HLEN; net->type = ARPHRD_IEEE1394; - net->tx_queue_len = 10; - SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops); + net->tx_queue_len = FWNET_TX_QUEUE_LEN; + net->ethtool_ops = &fwnet_ethtool_ops; } /* caller must hold fwnet_device_mutex */ @@ -1390,7 +1421,6 @@ static int fwnet_add_peer(struct fwnet_device *dev, peer->dev = dev; peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; - peer->fifo = FWNET_NO_FIFO_ADDR; INIT_LIST_HEAD(&peer->pd_list); peer->pdg_size = 0; peer->datagram_label = 0; @@ -1403,14 +1433,16 @@ static int fwnet_add_peer(struct fwnet_device *dev, spin_lock_irq(&dev->lock); list_add_tail(&peer->peer_link, &dev->peer_list); + dev->peer_count++; + set_carrier_state(dev); spin_unlock_irq(&dev->lock); return 0; } -static int fwnet_probe(struct device *_dev) +static int fwnet_probe(struct fw_unit *unit, + const struct ieee1394_device_id *id) { - struct fw_unit *unit = fw_unit(_dev); struct fw_device *device = fw_parent_device(unit); struct fw_card *card = device->card; struct net_device *net; @@ -1418,6 +1450,7 @@ static int fwnet_probe(struct device *_dev) struct fwnet_device *dev; unsigned max_mtu; int ret; + union fwnet_hwaddr *ha; mutex_lock(&fwnet_device_mutex); @@ -1429,8 +1462,8 @@ static int fwnet_probe(struct device *_dev) net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev); if (net == NULL) { - ret = -ENOMEM; - goto out; + mutex_unlock(&fwnet_device_mutex); + return -ENOMEM; } allocated_netdev = true; @@ -1442,17 +1475,17 @@ static int fwnet_probe(struct device *_dev) dev->broadcast_rcv_context = NULL; dev->broadcast_xmt_max_payload = 0; dev->broadcast_xmt_datagramlabel = 0; - dev->local_fifo = FWNET_NO_FIFO_ADDR; - - INIT_LIST_HEAD(&dev->packet_list); - INIT_LIST_HEAD(&dev->broadcasted_list); - INIT_LIST_HEAD(&dev->sent_list); + dev->queued_datagrams = 0; INIT_LIST_HEAD(&dev->peer_list); - dev->card = card; dev->netdev = net; + ret = fwnet_fifo_start(dev); + if (ret < 0) + goto out; + dev->local_fifo = dev->handler.offset; + /* * Use the RFC 2734 default 1500 octets or the maximum payload * as initial MTU @@ -1462,39 +1495,64 @@ static int fwnet_probe(struct device *_dev) net->mtu = min(1500U, max_mtu); /* Set our hardware address while we're at it */ - put_unaligned_be64(card->guid, net->dev_addr); - put_unaligned_be64(~0ULL, net->broadcast); + ha = (union fwnet_hwaddr *)net->dev_addr; + put_unaligned_be64(card->guid, &ha->uc.uniq_id); + ha->uc.max_rec = dev->card->max_receive; + ha->uc.sspd = dev->card->link_speed; + put_unaligned_be16(dev->local_fifo >> 32, &ha->uc.fifo_hi); + put_unaligned_be32(dev->local_fifo & 0xffffffff, &ha->uc.fifo_lo); + + memset(net->broadcast, -1, net->addr_len); + ret = register_netdev(net); - if (ret) { - fw_error("Cannot register the driver\n"); + if (ret) goto out; - } list_add_tail(&dev->dev_link, &fwnet_device_list); - fw_notify("%s: IPv4 over FireWire on device %016llx\n", - net->name, (unsigned long long)card->guid); + dev_notice(&net->dev, "IP over IEEE 1394 on card %s\n", + dev_name(card->device)); have_dev: ret = fwnet_add_peer(dev, unit, device); if (ret && allocated_netdev) { unregister_netdev(net); list_del(&dev->dev_link); - } out: - if (ret && allocated_netdev) + fwnet_fifo_stop(dev); free_netdev(net); + } mutex_unlock(&fwnet_device_mutex); return ret; } -static void fwnet_remove_peer(struct fwnet_peer *peer) +/* + * FIXME abort partially sent fragmented datagrams, + * discard partially received fragmented datagrams + */ +static void fwnet_update(struct fw_unit *unit) { - struct fwnet_partial_datagram *pd, *pd_next; + struct fw_device *device = fw_parent_device(unit); + struct fwnet_peer *peer = dev_get_drvdata(&unit->device); + int generation; + + generation = device->generation; spin_lock_irq(&peer->dev->lock); - list_del(&peer->peer_link); + peer->node_id = device->node_id; + peer->generation = generation; spin_unlock_irq(&peer->dev->lock); +} + +static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev) +{ + struct fwnet_partial_datagram *pd, *pd_next; + + spin_lock_irq(&dev->lock); + list_del(&peer->peer_link); + dev->peer_count--; + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) fwnet_pd_delete(pd); @@ -1502,70 +1560,33 @@ static void fwnet_remove_peer(struct fwnet_peer *peer) kfree(peer); } -static int fwnet_remove(struct device *_dev) +static void fwnet_remove(struct fw_unit *unit) { - struct fwnet_peer *peer = dev_get_drvdata(_dev); + struct fwnet_peer *peer = dev_get_drvdata(&unit->device); struct fwnet_device *dev = peer->dev; struct net_device *net; - struct fwnet_packet_task *ptask, *pt_next; + int i; mutex_lock(&fwnet_device_mutex); - fwnet_remove_peer(peer); + net = dev->netdev; + + fwnet_remove_peer(peer, dev); if (list_empty(&dev->peer_list)) { - net = dev->netdev; unregister_netdev(net); - if (dev->local_fifo != FWNET_NO_FIFO_ADDR) - fw_core_remove_address_handler(&dev->handler); - if (dev->broadcast_rcv_context) { - fw_iso_context_stop(dev->broadcast_rcv_context); - fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, - dev->card); - fw_iso_context_destroy(dev->broadcast_rcv_context); - } - list_for_each_entry_safe(ptask, pt_next, - &dev->packet_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } - list_for_each_entry_safe(ptask, pt_next, - &dev->broadcasted_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } - list_for_each_entry_safe(ptask, pt_next, - &dev->sent_list, pt_link) { - dev_kfree_skb_any(ptask->skb); - kmem_cache_free(fwnet_packet_task_cache, ptask); - } + fwnet_fifo_stop(dev); + + for (i = 0; dev->queued_datagrams && i < 5; i++) + ssleep(1); + WARN_ON(dev->queued_datagrams); list_del(&dev->dev_link); free_netdev(net); } mutex_unlock(&fwnet_device_mutex); - - return 0; -} - -/* - * FIXME abort partially sent fragmented datagrams, - * discard partially received fragmented datagrams - */ -static void fwnet_update(struct fw_unit *unit) -{ - struct fw_device *device = fw_parent_device(unit); - struct fwnet_peer *peer = dev_get_drvdata(&unit->device); - int generation; - - generation = device->generation; - - spin_lock_irq(&peer->dev->lock); - peer->node_id = device->node_id; - peer->generation = generation; - spin_unlock_irq(&peer->dev->lock); } static const struct ieee1394_device_id fwnet_id_table[] = { @@ -1575,18 +1596,26 @@ static const struct ieee1394_device_id fwnet_id_table[] = { .specifier_id = IANA_SPECIFIER_ID, .version = RFC2734_SW_VERSION, }, +#if IS_ENABLED(CONFIG_IPV6) + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .specifier_id = IANA_SPECIFIER_ID, + .version = RFC3146_SW_VERSION, + }, +#endif { } }; static struct fw_driver fwnet_driver = { .driver = { .owner = THIS_MODULE, - .name = "net", + .name = KBUILD_MODNAME, .bus = &fw_bus_type, - .probe = fwnet_probe, - .remove = fwnet_remove, }, + .probe = fwnet_probe, .update = fwnet_update, + .remove = fwnet_remove, .id_table = fwnet_id_table, }; @@ -1612,6 +1641,30 @@ static struct fw_descriptor rfc2374_unit_directory = { .data = rfc2374_unit_directory_data }; +#if IS_ENABLED(CONFIG_IPV6) +static const u32 rfc3146_unit_directory_data[] = { + 0x00040000, /* directory_length */ + 0x1200005e, /* unit_specifier_id: IANA */ + 0x81000003, /* textual descriptor offset */ + 0x13000002, /* unit_sw_version: RFC 3146 */ + 0x81000005, /* textual descriptor offset */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49414e41, /* I A N A */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49507636, /* I P v 6 */ +}; + +static struct fw_descriptor rfc3146_unit_directory = { + .length = ARRAY_SIZE(rfc3146_unit_directory_data), + .key = (CSR_DIRECTORY | CSR_UNIT) << 24, + .data = rfc3146_unit_directory_data +}; +#endif + static int __init fwnet_init(void) { int err; @@ -1620,11 +1673,17 @@ static int __init fwnet_init(void) if (err) return err; +#if IS_ENABLED(CONFIG_IPV6) + err = fw_core_add_descriptor(&rfc3146_unit_directory); + if (err) + goto out; +#endif + fwnet_packet_task_cache = kmem_cache_create("packet_task", sizeof(struct fwnet_packet_task), 0, 0, NULL); if (!fwnet_packet_task_cache) { err = -ENOMEM; - goto out; + goto out2; } err = driver_register(&fwnet_driver.driver); @@ -1632,7 +1691,11 @@ static int __init fwnet_init(void) return 0; kmem_cache_destroy(fwnet_packet_task_cache); +out2: +#if IS_ENABLED(CONFIG_IPV6) + fw_core_remove_descriptor(&rfc3146_unit_directory); out: +#endif fw_core_remove_descriptor(&rfc2374_unit_directory); return err; @@ -1643,11 +1706,14 @@ static void __exit fwnet_cleanup(void) { driver_unregister(&fwnet_driver.driver); kmem_cache_destroy(fwnet_packet_task_cache); +#if IS_ENABLED(CONFIG_IPV6) + fw_core_remove_descriptor(&rfc3146_unit_directory); +#endif fw_core_remove_descriptor(&rfc2374_unit_directory); } module_exit(fwnet_cleanup); MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>"); -MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734"); +MODULE_DESCRIPTION("IP over IEEE1394 as per RFC 2734/3146"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table); diff --git a/drivers/firewire/nosy-user.h b/drivers/firewire/nosy-user.h new file mode 100644 index 00000000000..e48aa6200c7 --- /dev/null +++ b/drivers/firewire/nosy-user.h @@ -0,0 +1,25 @@ +#ifndef __nosy_user_h +#define __nosy_user_h + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define NOSY_IOC_GET_STATS _IOR('&', 0, struct nosy_stats) +#define NOSY_IOC_START _IO('&', 1) +#define NOSY_IOC_STOP _IO('&', 2) +#define NOSY_IOC_FILTER _IOW('&', 2, __u32) + +struct nosy_stats { + __u32 total_packet_count; + __u32 lost_packet_count; +}; + +/* + * Format of packets returned from the kernel driver: + * + * quadlet with timestamp (microseconds, CPU endian) + * quadlet-padded packet data... (little endian) + * quadlet with ack (little endian) + */ + +#endif /* __nosy_user_h */ diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c new file mode 100644 index 00000000000..76b2d390f6e --- /dev/null +++ b/drivers/firewire/nosy.c @@ -0,0 +1,709 @@ +/* + * nosy - Snoop mode driver for TI PCILynx 1394 controllers + * Copyright (C) 2002-2007 Kristian Høgsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/kref.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/poll.h> +#include <linux/sched.h> /* required for linux/wait.h */ +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/timex.h> +#include <linux/uaccess.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> +#include <linux/atomic.h> +#include <asm/byteorder.h> + +#include "nosy.h" +#include "nosy-user.h" + +#define TCODE_PHY_PACKET 0x10 +#define PCI_DEVICE_ID_TI_PCILYNX 0x8000 + +static char driver_name[] = KBUILD_MODNAME; + +/* this is the physical layout of a PCL, its size is 128 bytes */ +struct pcl { + __le32 next; + __le32 async_error_next; + u32 user_data; + __le32 pcl_status; + __le32 remaining_transfer_count; + __le32 next_data_buffer; + struct { + __le32 control; + __le32 pointer; + } buffer[13]; +}; + +struct packet { + unsigned int length; + char data[0]; +}; + +struct packet_buffer { + char *data; + size_t capacity; + long total_packet_count, lost_packet_count; + atomic_t size; + struct packet *head, *tail; + wait_queue_head_t wait; +}; + +struct pcilynx { + struct pci_dev *pci_device; + __iomem char *registers; + + struct pcl *rcv_start_pcl, *rcv_pcl; + __le32 *rcv_buffer; + + dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; + + spinlock_t client_list_lock; + struct list_head client_list; + + struct miscdevice misc; + struct list_head link; + struct kref kref; +}; + +static inline struct pcilynx * +lynx_get(struct pcilynx *lynx) +{ + kref_get(&lynx->kref); + + return lynx; +} + +static void +lynx_release(struct kref *kref) +{ + kfree(container_of(kref, struct pcilynx, kref)); +} + +static inline void +lynx_put(struct pcilynx *lynx) +{ + kref_put(&lynx->kref, lynx_release); +} + +struct client { + struct pcilynx *lynx; + u32 tcode_mask; + struct packet_buffer buffer; + struct list_head link; +}; + +static DEFINE_MUTEX(card_mutex); +static LIST_HEAD(card_list); + +static int +packet_buffer_init(struct packet_buffer *buffer, size_t capacity) +{ + buffer->data = kmalloc(capacity, GFP_KERNEL); + if (buffer->data == NULL) + return -ENOMEM; + buffer->head = (struct packet *) buffer->data; + buffer->tail = (struct packet *) buffer->data; + buffer->capacity = capacity; + buffer->lost_packet_count = 0; + atomic_set(&buffer->size, 0); + init_waitqueue_head(&buffer->wait); + + return 0; +} + +static void +packet_buffer_destroy(struct packet_buffer *buffer) +{ + kfree(buffer->data); +} + +static int +packet_buffer_get(struct client *client, char __user *data, size_t user_length) +{ + struct packet_buffer *buffer = &client->buffer; + size_t length; + char *end; + + if (wait_event_interruptible(buffer->wait, + atomic_read(&buffer->size) > 0) || + list_empty(&client->lynx->link)) + return -ERESTARTSYS; + + if (atomic_read(&buffer->size) == 0) + return -ENODEV; + + /* FIXME: Check length <= user_length. */ + + end = buffer->data + buffer->capacity; + length = buffer->head->length; + + if (&buffer->head->data[length] < end) { + if (copy_to_user(data, buffer->head->data, length)) + return -EFAULT; + buffer->head = (struct packet *) &buffer->head->data[length]; + } else { + size_t split = end - buffer->head->data; + + if (copy_to_user(data, buffer->head->data, split)) + return -EFAULT; + if (copy_to_user(data + split, buffer->data, length - split)) + return -EFAULT; + buffer->head = (struct packet *) &buffer->data[length - split]; + } + + /* + * Decrease buffer->size as the last thing, since this is what + * keeps the interrupt from overwriting the packet we are + * retrieving from the buffer. + */ + atomic_sub(sizeof(struct packet) + length, &buffer->size); + + return length; +} + +static void +packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) +{ + char *end; + + buffer->total_packet_count++; + + if (buffer->capacity < + atomic_read(&buffer->size) + sizeof(struct packet) + length) { + buffer->lost_packet_count++; + return; + } + + end = buffer->data + buffer->capacity; + buffer->tail->length = length; + + if (&buffer->tail->data[length] < end) { + memcpy(buffer->tail->data, data, length); + buffer->tail = (struct packet *) &buffer->tail->data[length]; + } else { + size_t split = end - buffer->tail->data; + + memcpy(buffer->tail->data, data, split); + memcpy(buffer->data, data + split, length - split); + buffer->tail = (struct packet *) &buffer->data[length - split]; + } + + /* Finally, adjust buffer size and wake up userspace reader. */ + + atomic_add(sizeof(struct packet) + length, &buffer->size); + wake_up_interruptible(&buffer->wait); +} + +static inline void +reg_write(struct pcilynx *lynx, int offset, u32 data) +{ + writel(data, lynx->registers + offset); +} + +static inline u32 +reg_read(struct pcilynx *lynx, int offset) +{ + return readl(lynx->registers + offset); +} + +static inline void +reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) +{ + reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); +} + +/* + * Maybe the pcl programs could be set up to just append data instead + * of using a whole packet. + */ +static inline void +run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, + int dmachan) +{ + reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); + reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, + DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); +} + +static int +set_phy_reg(struct pcilynx *lynx, int addr, int val) +{ + if (addr > 15) { + dev_err(&lynx->pci_device->dev, + "PHY register address %d out of range\n", addr); + return -1; + } + if (val > 0xff) { + dev_err(&lynx->pci_device->dev, + "PHY register value %d out of range\n", val); + return -1; + } + reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | + LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); + + return 0; +} + +static int +nosy_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct client *client; + struct pcilynx *tmp, *lynx = NULL; + + mutex_lock(&card_mutex); + list_for_each_entry(tmp, &card_list, link) + if (tmp->misc.minor == minor) { + lynx = lynx_get(tmp); + break; + } + mutex_unlock(&card_mutex); + if (lynx == NULL) + return -ENODEV; + + client = kmalloc(sizeof *client, GFP_KERNEL); + if (client == NULL) + goto fail; + + client->tcode_mask = ~0; + client->lynx = lynx; + INIT_LIST_HEAD(&client->link); + + if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) + goto fail; + + file->private_data = client; + + return nonseekable_open(inode, file); +fail: + kfree(client); + lynx_put(lynx); + + return -ENOMEM; +} + +static int +nosy_release(struct inode *inode, struct file *file) +{ + struct client *client = file->private_data; + struct pcilynx *lynx = client->lynx; + + spin_lock_irq(&lynx->client_list_lock); + list_del_init(&client->link); + spin_unlock_irq(&lynx->client_list_lock); + + packet_buffer_destroy(&client->buffer); + kfree(client); + lynx_put(lynx); + + return 0; +} + +static unsigned int +nosy_poll(struct file *file, poll_table *pt) +{ + struct client *client = file->private_data; + unsigned int ret = 0; + + poll_wait(file, &client->buffer.wait, pt); + + if (atomic_read(&client->buffer.size) > 0) + ret = POLLIN | POLLRDNORM; + + if (list_empty(&client->lynx->link)) + ret |= POLLHUP; + + return ret; +} + +static ssize_t +nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) +{ + struct client *client = file->private_data; + + return packet_buffer_get(client, buffer, count); +} + +static long +nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct client *client = file->private_data; + spinlock_t *client_list_lock = &client->lynx->client_list_lock; + struct nosy_stats stats; + + switch (cmd) { + case NOSY_IOC_GET_STATS: + spin_lock_irq(client_list_lock); + stats.total_packet_count = client->buffer.total_packet_count; + stats.lost_packet_count = client->buffer.lost_packet_count; + spin_unlock_irq(client_list_lock); + + if (copy_to_user((void __user *) arg, &stats, sizeof stats)) + return -EFAULT; + else + return 0; + + case NOSY_IOC_START: + spin_lock_irq(client_list_lock); + list_add_tail(&client->link, &client->lynx->client_list); + spin_unlock_irq(client_list_lock); + + return 0; + + case NOSY_IOC_STOP: + spin_lock_irq(client_list_lock); + list_del_init(&client->link); + spin_unlock_irq(client_list_lock); + + return 0; + + case NOSY_IOC_FILTER: + spin_lock_irq(client_list_lock); + client->tcode_mask = arg; + spin_unlock_irq(client_list_lock); + + return 0; + + default: + return -EINVAL; + /* Flush buffer, configure filter. */ + } +} + +static const struct file_operations nosy_ops = { + .owner = THIS_MODULE, + .read = nosy_read, + .unlocked_ioctl = nosy_ioctl, + .poll = nosy_poll, + .open = nosy_open, + .release = nosy_release, +}; + +#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ + +static void +packet_irq_handler(struct pcilynx *lynx) +{ + struct client *client; + u32 tcode_mask, tcode; + size_t length; + struct timeval tv; + + /* FIXME: Also report rcv_speed. */ + + length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff; + tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf; + + do_gettimeofday(&tv); + lynx->rcv_buffer[0] = (__force __le32)tv.tv_usec; + + if (length == PHY_PACKET_SIZE) + tcode_mask = 1 << TCODE_PHY_PACKET; + else + tcode_mask = 1 << tcode; + + spin_lock(&lynx->client_list_lock); + + list_for_each_entry(client, &lynx->client_list, link) + if (client->tcode_mask & tcode_mask) + packet_buffer_put(&client->buffer, + lynx->rcv_buffer, length + 4); + + spin_unlock(&lynx->client_list_lock); +} + +static void +bus_reset_irq_handler(struct pcilynx *lynx) +{ + struct client *client; + struct timeval tv; + + do_gettimeofday(&tv); + + spin_lock(&lynx->client_list_lock); + + list_for_each_entry(client, &lynx->client_list, link) + packet_buffer_put(&client->buffer, &tv.tv_usec, 4); + + spin_unlock(&lynx->client_list_lock); +} + +static irqreturn_t +irq_handler(int irq, void *device) +{ + struct pcilynx *lynx = device; + u32 pci_int_status; + + pci_int_status = reg_read(lynx, PCI_INT_STATUS); + + if (pci_int_status == ~0) + /* Card was ejected. */ + return IRQ_NONE; + + if ((pci_int_status & PCI_INT_INT_PEND) == 0) + /* Not our interrupt, bail out quickly. */ + return IRQ_NONE; + + if ((pci_int_status & PCI_INT_P1394_INT) != 0) { + u32 link_int_status; + + link_int_status = reg_read(lynx, LINK_INT_STATUS); + reg_write(lynx, LINK_INT_STATUS, link_int_status); + + if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) + bus_reset_irq_handler(lynx); + } + + /* Clear the PCI_INT_STATUS register only after clearing the + * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will + * be set again immediately. */ + + reg_write(lynx, PCI_INT_STATUS, pci_int_status); + + if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { + packet_irq_handler(lynx); + run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); + } + + return IRQ_HANDLED; +} + +static void +remove_card(struct pci_dev *dev) +{ + struct pcilynx *lynx = pci_get_drvdata(dev); + struct client *client; + + mutex_lock(&card_mutex); + list_del_init(&lynx->link); + misc_deregister(&lynx->misc); + mutex_unlock(&card_mutex); + + reg_write(lynx, PCI_INT_ENABLE, 0); + free_irq(lynx->pci_device->irq, lynx); + + spin_lock_irq(&lynx->client_list_lock); + list_for_each_entry(client, &lynx->client_list, link) + wake_up_interruptible(&client->buffer.wait); + spin_unlock_irq(&lynx->client_list_lock); + + pci_free_consistent(lynx->pci_device, sizeof(struct pcl), + lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); + pci_free_consistent(lynx->pci_device, sizeof(struct pcl), + lynx->rcv_pcl, lynx->rcv_pcl_bus); + pci_free_consistent(lynx->pci_device, PAGE_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); + + iounmap(lynx->registers); + pci_disable_device(dev); + lynx_put(lynx); +} + +#define RCV_BUFFER_SIZE (16 * 1024) + +static int +add_card(struct pci_dev *dev, const struct pci_device_id *unused) +{ + struct pcilynx *lynx; + u32 p, end; + int ret, i; + + if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + dev_err(&dev->dev, + "DMA address limits not supported for PCILynx hardware\n"); + return -ENXIO; + } + if (pci_enable_device(dev)) { + dev_err(&dev->dev, "Failed to enable PCILynx hardware\n"); + return -ENXIO; + } + pci_set_master(dev); + + lynx = kzalloc(sizeof *lynx, GFP_KERNEL); + if (lynx == NULL) { + dev_err(&dev->dev, "Failed to allocate control structure\n"); + ret = -ENOMEM; + goto fail_disable; + } + lynx->pci_device = dev; + pci_set_drvdata(dev, lynx); + + spin_lock_init(&lynx->client_list_lock); + INIT_LIST_HEAD(&lynx->client_list); + kref_init(&lynx->kref); + + lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), + PCILYNX_MAX_REGISTER); + + lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, + sizeof(struct pcl), &lynx->rcv_start_pcl_bus); + lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, + sizeof(struct pcl), &lynx->rcv_pcl_bus); + lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, + RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); + if (lynx->rcv_start_pcl == NULL || + lynx->rcv_pcl == NULL || + lynx->rcv_buffer == NULL) { + dev_err(&dev->dev, "Failed to allocate receive buffer\n"); + ret = -ENOMEM; + goto fail_deallocate; + } + lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); + lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); + lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID); + + lynx->rcv_pcl->buffer[0].control = + cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044); + lynx->rcv_pcl->buffer[0].pointer = + cpu_to_le32(lynx->rcv_buffer_bus + 4); + p = lynx->rcv_buffer_bus + 2048; + end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; + for (i = 1; p < end; i++, p += 2048) { + lynx->rcv_pcl->buffer[i].control = + cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048); + lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p); + } + lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF); + + reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + /* Fix buggy cards with autoboot pin not tied low: */ + reg_write(lynx, DMA0_CHAN_CTRL, 0); + reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); + +#if 0 + /* now, looking for PHY register set */ + if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { + lynx->phyic.reg_1394a = 1; + PRINT(KERN_INFO, lynx->id, + "found 1394a conform PHY (using extended register set)"); + lynx->phyic.vendor = get_phy_vendorid(lynx); + lynx->phyic.product = get_phy_productid(lynx); + } else { + lynx->phyic.reg_1394a = 0; + PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); + } +#endif + + /* Setup the general receive FIFO max size. */ + reg_write(lynx, FIFO_SIZES, 255); + + reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); + + reg_write(lynx, LINK_INT_ENABLE, + LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | + LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | + LINK_INT_AT_STUCK | LINK_INT_SNTRJ | + LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | + LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); + + /* Disable the L flag in self ID packets. */ + set_phy_reg(lynx, 4, 0); + + /* Put this baby into snoop mode */ + reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); + + run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); + + if (request_irq(dev->irq, irq_handler, IRQF_SHARED, + driver_name, lynx)) { + dev_err(&dev->dev, + "Failed to allocate shared interrupt %d\n", dev->irq); + ret = -EIO; + goto fail_deallocate; + } + + lynx->misc.parent = &dev->dev; + lynx->misc.minor = MISC_DYNAMIC_MINOR; + lynx->misc.name = "nosy"; + lynx->misc.fops = &nosy_ops; + + mutex_lock(&card_mutex); + ret = misc_register(&lynx->misc); + if (ret) { + dev_err(&dev->dev, "Failed to register misc char device\n"); + mutex_unlock(&card_mutex); + goto fail_free_irq; + } + list_add_tail(&lynx->link, &card_list); + mutex_unlock(&card_mutex); + + dev_info(&dev->dev, + "Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq); + + return 0; + +fail_free_irq: + reg_write(lynx, PCI_INT_ENABLE, 0); + free_irq(lynx->pci_device->irq, lynx); + +fail_deallocate: + if (lynx->rcv_start_pcl) + pci_free_consistent(lynx->pci_device, sizeof(struct pcl), + lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); + if (lynx->rcv_pcl) + pci_free_consistent(lynx->pci_device, sizeof(struct pcl), + lynx->rcv_pcl, lynx->rcv_pcl_bus); + if (lynx->rcv_buffer) + pci_free_consistent(lynx->pci_device, PAGE_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); + iounmap(lynx->registers); + kfree(lynx); + +fail_disable: + pci_disable_device(dev); + + return ret; +} + +static struct pci_device_id pci_table[] = { + { + .vendor = PCI_VENDOR_ID_TI, + .device = PCI_DEVICE_ID_TI_PCILYNX, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(pci, pci_table); + +static struct pci_driver lynx_pci_driver = { + .name = driver_name, + .id_table = pci_table, + .probe = add_card, + .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"); diff --git a/drivers/firewire/nosy.h b/drivers/firewire/nosy.h new file mode 100644 index 00000000000..078ff27f475 --- /dev/null +++ b/drivers/firewire/nosy.h @@ -0,0 +1,237 @@ +/* + * Chip register definitions for PCILynx chipset. Based on pcilynx.h + * from the Linux 1394 drivers, but modified a bit so the names here + * match the specification exactly (even though they have weird names, + * like xxx_OVER_FLOW, or arbitrary abbreviations like SNTRJ for "sent + * reject" etc.) + */ + +#define PCILYNX_MAX_REGISTER 0xfff +#define PCILYNX_MAX_MEMORY 0xffff + +#define PCI_LATENCY_CACHELINE 0x0c + +#define MISC_CONTROL 0x40 +#define MISC_CONTROL_SWRESET (1<<0) + +#define SERIAL_EEPROM_CONTROL 0x44 + +#define PCI_INT_STATUS 0x48 +#define PCI_INT_ENABLE 0x4c +/* status and enable have identical bit numbers */ +#define PCI_INT_INT_PEND (1<<31) +#define PCI_INT_FRC_INT (1<<30) +#define PCI_INT_SLV_ADR_PERR (1<<28) +#define PCI_INT_SLV_DAT_PERR (1<<27) +#define PCI_INT_MST_DAT_PERR (1<<26) +#define PCI_INT_MST_DEV_TO (1<<25) +#define PCI_INT_INT_SLV_TO (1<<23) +#define PCI_INT_AUX_TO (1<<18) +#define PCI_INT_AUX_INT (1<<17) +#define PCI_INT_P1394_INT (1<<16) +#define PCI_INT_DMA4_PCL (1<<9) +#define PCI_INT_DMA4_HLT (1<<8) +#define PCI_INT_DMA3_PCL (1<<7) +#define PCI_INT_DMA3_HLT (1<<6) +#define PCI_INT_DMA2_PCL (1<<5) +#define PCI_INT_DMA2_HLT (1<<4) +#define PCI_INT_DMA1_PCL (1<<3) +#define PCI_INT_DMA1_HLT (1<<2) +#define PCI_INT_DMA0_PCL (1<<1) +#define PCI_INT_DMA0_HLT (1<<0) +/* all DMA interrupts combined: */ +#define PCI_INT_DMA_ALL 0x3ff + +#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2)) +#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1)) + +#define LBUS_ADDR 0xb4 +#define LBUS_ADDR_SEL_RAM (0x0<<16) +#define LBUS_ADDR_SEL_ROM (0x1<<16) +#define LBUS_ADDR_SEL_AUX (0x2<<16) +#define LBUS_ADDR_SEL_ZV (0x3<<16) + +#define GPIO_CTRL_A 0xb8 +#define GPIO_CTRL_B 0xbc +#define GPIO_DATA_BASE 0xc0 + +#define DMA_BREG(base, chan) (base + chan * 0x20) +#define DMA_SREG(base, chan) (base + chan * 0x10) + +#define PCL_NEXT_INVALID (1<<0) + +/* transfer commands */ +#define PCL_CMD_RCV (0x1<<24) +#define PCL_CMD_RCV_AND_UPDATE (0xa<<24) +#define PCL_CMD_XMT (0x2<<24) +#define PCL_CMD_UNFXMT (0xc<<24) +#define PCL_CMD_PCI_TO_LBUS (0x8<<24) +#define PCL_CMD_LBUS_TO_PCI (0x9<<24) + +/* aux commands */ +#define PCL_CMD_NOP (0x0<<24) +#define PCL_CMD_LOAD (0x3<<24) +#define PCL_CMD_STOREQ (0x4<<24) +#define PCL_CMD_STORED (0xb<<24) +#define PCL_CMD_STORE0 (0x5<<24) +#define PCL_CMD_STORE1 (0x6<<24) +#define PCL_CMD_COMPARE (0xe<<24) +#define PCL_CMD_SWAP_COMPARE (0xf<<24) +#define PCL_CMD_ADD (0xd<<24) +#define PCL_CMD_BRANCH (0x7<<24) + +/* BRANCH condition codes */ +#define PCL_COND_DMARDY_SET (0x1<<20) +#define PCL_COND_DMARDY_CLEAR (0x2<<20) + +#define PCL_GEN_INTR (1<<19) +#define PCL_LAST_BUFF (1<<18) +#define PCL_LAST_CMD (PCL_LAST_BUFF) +#define PCL_WAITSTAT (1<<17) +#define PCL_BIGENDIAN (1<<16) +#define PCL_ISOMODE (1<<12) + +#define DMA0_PREV_PCL 0x100 +#define DMA1_PREV_PCL 0x120 +#define DMA2_PREV_PCL 0x140 +#define DMA3_PREV_PCL 0x160 +#define DMA4_PREV_PCL 0x180 +#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan)) + +#define DMA0_CURRENT_PCL 0x104 +#define DMA1_CURRENT_PCL 0x124 +#define DMA2_CURRENT_PCL 0x144 +#define DMA3_CURRENT_PCL 0x164 +#define DMA4_CURRENT_PCL 0x184 +#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan)) + +#define DMA0_CHAN_STAT 0x10c +#define DMA1_CHAN_STAT 0x12c +#define DMA2_CHAN_STAT 0x14c +#define DMA3_CHAN_STAT 0x16c +#define DMA4_CHAN_STAT 0x18c +#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan)) +/* CHAN_STATUS registers share bits */ +#define DMA_CHAN_STAT_SELFID (1<<31) +#define DMA_CHAN_STAT_ISOPKT (1<<30) +#define DMA_CHAN_STAT_PCIERR (1<<29) +#define DMA_CHAN_STAT_PKTERR (1<<28) +#define DMA_CHAN_STAT_PKTCMPL (1<<27) +#define DMA_CHAN_STAT_SPECIALACK (1<<14) + +#define DMA0_CHAN_CTRL 0x110 +#define DMA1_CHAN_CTRL 0x130 +#define DMA2_CHAN_CTRL 0x150 +#define DMA3_CHAN_CTRL 0x170 +#define DMA4_CHAN_CTRL 0x190 +#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan)) +/* CHAN_CTRL registers share bits */ +#define DMA_CHAN_CTRL_ENABLE (1<<31) +#define DMA_CHAN_CTRL_BUSY (1<<30) +#define DMA_CHAN_CTRL_LINK (1<<29) + +#define DMA0_READY 0x114 +#define DMA1_READY 0x134 +#define DMA2_READY 0x154 +#define DMA3_READY 0x174 +#define DMA4_READY 0x194 +#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan)) + +#define DMA_GLOBAL_REGISTER 0x908 + +#define FIFO_SIZES 0xa00 + +#define FIFO_CONTROL 0xa10 +#define FIFO_CONTROL_GRF_FLUSH (1<<4) +#define FIFO_CONTROL_ITF_FLUSH (1<<3) +#define FIFO_CONTROL_ATF_FLUSH (1<<2) + +#define FIFO_XMIT_THRESHOLD 0xa14 + +#define DMA0_WORD0_CMP_VALUE 0xb00 +#define DMA1_WORD0_CMP_VALUE 0xb10 +#define DMA2_WORD0_CMP_VALUE 0xb20 +#define DMA3_WORD0_CMP_VALUE 0xb30 +#define DMA4_WORD0_CMP_VALUE 0xb40 +#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan)) + +#define DMA0_WORD0_CMP_ENABLE 0xb04 +#define DMA1_WORD0_CMP_ENABLE 0xb14 +#define DMA2_WORD0_CMP_ENABLE 0xb24 +#define DMA3_WORD0_CMP_ENABLE 0xb34 +#define DMA4_WORD0_CMP_ENABLE 0xb44 +#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE, chan)) + +#define DMA0_WORD1_CMP_VALUE 0xb08 +#define DMA1_WORD1_CMP_VALUE 0xb18 +#define DMA2_WORD1_CMP_VALUE 0xb28 +#define DMA3_WORD1_CMP_VALUE 0xb38 +#define DMA4_WORD1_CMP_VALUE 0xb48 +#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan)) + +#define DMA0_WORD1_CMP_ENABLE 0xb0c +#define DMA1_WORD1_CMP_ENABLE 0xb1c +#define DMA2_WORD1_CMP_ENABLE 0xb2c +#define DMA3_WORD1_CMP_ENABLE 0xb3c +#define DMA4_WORD1_CMP_ENABLE 0xb4c +#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE, chan)) +/* word 1 compare enable flags */ +#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15) +#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14) +#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13) +#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12) +#define DMA_WORD1_CMP_MATCH_EXACT (1<<11) +#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10) +#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8) + +#define LINK_ID 0xf00 +#define LINK_ID_BUS(id) (id<<22) +#define LINK_ID_NODE(id) (id<<16) + +#define LINK_CONTROL 0xf04 +#define LINK_CONTROL_BUSY (1<<29) +#define LINK_CONTROL_TX_ISO_EN (1<<26) +#define LINK_CONTROL_RX_ISO_EN (1<<25) +#define LINK_CONTROL_TX_ASYNC_EN (1<<24) +#define LINK_CONTROL_RX_ASYNC_EN (1<<23) +#define LINK_CONTROL_RESET_TX (1<<21) +#define LINK_CONTROL_RESET_RX (1<<20) +#define LINK_CONTROL_CYCMASTER (1<<11) +#define LINK_CONTROL_CYCSOURCE (1<<10) +#define LINK_CONTROL_CYCTIMEREN (1<<9) +#define LINK_CONTROL_RCV_CMP_VALID (1<<7) +#define LINK_CONTROL_SNOOP_ENABLE (1<<6) + +#define CYCLE_TIMER 0xf08 + +#define LINK_PHY 0xf0c +#define LINK_PHY_READ (1<<31) +#define LINK_PHY_WRITE (1<<30) +#define LINK_PHY_ADDR(addr) (addr<<24) +#define LINK_PHY_WDATA(data) (data<<16) +#define LINK_PHY_RADDR(addr) (addr<<8) + +#define LINK_INT_STATUS 0xf14 +#define LINK_INT_ENABLE 0xf18 +/* status and enable have identical bit numbers */ +#define LINK_INT_LINK_INT (1<<31) +#define LINK_INT_PHY_TIME_OUT (1<<30) +#define LINK_INT_PHY_REG_RCVD (1<<29) +#define LINK_INT_PHY_BUSRESET (1<<28) +#define LINK_INT_TX_RDY (1<<26) +#define LINK_INT_RX_DATA_RDY (1<<25) +#define LINK_INT_IT_STUCK (1<<20) +#define LINK_INT_AT_STUCK (1<<19) +#define LINK_INT_SNTRJ (1<<17) +#define LINK_INT_HDR_ERR (1<<16) +#define LINK_INT_TC_ERR (1<<15) +#define LINK_INT_CYC_SEC (1<<11) +#define LINK_INT_CYC_STRT (1<<10) +#define LINK_INT_CYC_DONE (1<<9) +#define LINK_INT_CYC_PEND (1<<8) +#define LINK_INT_CYC_LOST (1<<7) +#define LINK_INT_CYC_ARB_FAILED (1<<6) +#define LINK_INT_GRF_OVER_FLOW (1<<5) +#define LINK_INT_ITF_UNDER_FLOW (1<<4) +#define LINK_INT_ATF_UNDER_FLOW (1<<3) +#define LINK_INT_IARB_FAILED (1<<0) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index a61571c63c5..a66a3217f1d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -18,13 +18,14 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/bitops.h> +#include <linux/bug.h> #include <linux/compiler.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/firewire.h> #include <linux/firewire-constants.h> -#include <linux/gfp.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -33,15 +34,18 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/mutex.h> #include <linux/pci.h> #include <linux/pci_ids.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> +#include <linux/time.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> -#include <asm/atomic.h> #include <asm/byteorder.h> #include <asm/page.h> -#include <asm/system.h> #ifdef CONFIG_PPC_PMAC #include <asm/pmac_feature.h> @@ -50,6 +54,10 @@ #include "core.h" #include "ohci.h" +#define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) +#define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) +#define ohci_err(ohci, f, args...) dev_err(ohci->card.device, f, ##args) + #define DESCRIPTOR_OUTPUT_MORE 0 #define DESCRIPTOR_OUTPUT_LAST (1 << 12) #define DESCRIPTOR_INPUT_MORE (2 << 12) @@ -64,6 +72,8 @@ #define DESCRIPTOR_BRANCH_ALWAYS (3 << 2) #define DESCRIPTOR_WAIT (3 << 0) +#define DESCRIPTOR_CMD (0xf << 12) + struct descriptor { __le16 req_count; __le16 control; @@ -73,36 +83,28 @@ struct descriptor { __le16 transfer_status; } __attribute__((aligned(16))); -struct db_descriptor { - __le16 first_size; - __le16 control; - __le16 second_req_count; - __le16 first_req_count; - __le32 branch_address; - __le16 second_res_count; - __le16 first_res_count; - __le32 reserved0; - __le32 first_buffer; - __le32 second_buffer; - __le32 reserved1; -} __attribute__((aligned(16))); - #define CONTROL_SET(regs) (regs) #define CONTROL_CLEAR(regs) ((regs) + 4) #define COMMAND_PTR(regs) ((regs) + 12) #define CONTEXT_MATCH(regs) ((regs) + 16) -struct ar_buffer { - struct descriptor descriptor; - struct ar_buffer *next; - __le32 data[0]; -}; +#define AR_BUFFER_SIZE (32*1024) +#define AR_BUFFERS_MIN DIV_ROUND_UP(AR_BUFFER_SIZE, PAGE_SIZE) +/* we need at least two pages for proper list management */ +#define AR_BUFFERS (AR_BUFFERS_MIN >= 2 ? AR_BUFFERS_MIN : 2) + +#define MAX_ASYNC_PAYLOAD 4096 +#define MAX_AR_PACKET_SIZE (16 + MAX_ASYNC_PAYLOAD + 4) +#define AR_WRAPAROUND_PAGES DIV_ROUND_UP(MAX_AR_PACKET_SIZE, PAGE_SIZE) struct ar_context { struct fw_ohci *ohci; - struct ar_buffer *current_buffer; - struct ar_buffer *last_buffer; + struct page *pages[AR_BUFFERS]; + void *buffer; + struct descriptor *descriptors; + dma_addr_t descriptors_bus; void *pointer; + unsigned int last_buffer_index; u32 regs; struct tasklet_struct tasklet; }; @@ -129,6 +131,9 @@ struct context { struct fw_ohci *ohci; u32 regs; int total_allocation; + u32 current_bus; + bool running; + bool flushing; /* * List of page-sized buffers for storing DMA descriptors. @@ -150,10 +155,11 @@ struct context { struct descriptor *last; /* - * The last descriptor in the DMA program. It contains the branch + * The last descriptor block in the DMA program. It contains the branch * address that must be updated upon appending a new descriptor. */ struct descriptor *prev; + int prev_z; descriptor_callback_t callback; @@ -170,9 +176,14 @@ struct context { struct iso_context { struct fw_iso_context base; struct context context; - int excess_bytes; void *header; size_t header_length; + unsigned long flushing_completions; + u32 mc_buffer_bus; + u16 mc_completed; + u16 last_timestamp; + u8 sync; + u8 tags; }; #define CONFIG_ROM_SIZE 1024 @@ -181,44 +192,58 @@ struct fw_ohci { struct fw_card card; __iomem char *registers; - dma_addr_t self_id_bus; - __le32 *self_id_cpu; - struct tasklet_struct bus_reset_tasklet; int node_id; int generation; int request_generation; /* for timestamping incoming requests */ - atomic_t bus_seconds; - - bool use_dualbuffer; - bool old_uninorth; - bool bus_reset_packet_quirk; - + unsigned quirks; + unsigned int pri_req_max; + u32 bus_time; + bool bus_time_running; + bool is_root; + bool csr_state_setclear_abdicate; + int n_ir; + int n_it; /* * Spinlock for accessing fw_ohci data. Never call out of * this driver with this lock held. */ spinlock_t lock; - u32 self_id_buffer[512]; - /* Config rom buffers */ - __be32 *config_rom; - dma_addr_t config_rom_bus; - __be32 *next_config_rom; - dma_addr_t next_config_rom_bus; - __be32 next_header; + struct mutex phy_reg_mutex; + + void *misc_buffer; + dma_addr_t misc_buffer_bus; struct ar_context ar_request_ctx; struct ar_context ar_response_ctx; struct context at_request_ctx; struct context at_response_ctx; - u32 it_context_mask; + u32 it_context_support; + u32 it_context_mask; /* unoccupied IT contexts */ struct iso_context *it_context_list; - u64 ir_context_channels; - u32 ir_context_mask; + u64 ir_context_channels; /* unoccupied channels */ + u32 ir_context_support; + u32 ir_context_mask; /* unoccupied IR contexts */ struct iso_context *ir_context_list; + u64 mc_channels; /* channels in use by the multichannel IR context */ + bool mc_allocated; + + __be32 *config_rom; + dma_addr_t config_rom_bus; + __be32 *next_config_rom; + dma_addr_t next_config_rom_bus; + __be32 next_header; + + __le32 *self_id; + dma_addr_t self_id_bus; + struct work_struct bus_reset_work; + + u32 self_id_buffer[512]; }; +static struct workqueue_struct *selfid_workqueue; + static inline struct fw_ohci *fw_ohci(struct fw_card *card) { return container_of(card, struct fw_ohci, card); @@ -241,7 +266,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 #define OHCI1394_REGISTER_SIZE 0x800 -#define OHCI_LOOP_COUNT 500 #define OHCI1394_PCI_HCI_Control 0x40 #define SELF_ID_BUF_SIZE 0x800 #define OHCI_TCODE_PHY_PACKET 0x0e @@ -249,7 +273,90 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; -#ifdef CONFIG_FIREWIRE_OHCI_DEBUG +#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd +#define PCI_DEVICE_ID_AGERE_FW643 0x5901 +#define PCI_DEVICE_ID_CREATIVE_SB1394 0x4001 +#define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 +#define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 +#define PCI_DEVICE_ID_TI_TSB12LV26 0x8020 +#define PCI_DEVICE_ID_TI_TSB82AA2 0x8025 +#define PCI_DEVICE_ID_VIA_VT630X 0x3044 +#define PCI_REV_ID_VIA_VT6306 0x46 +#define PCI_DEVICE_ID_VIA_VT6315 0x3403 + +#define QUIRK_CYCLE_TIMER 0x1 +#define QUIRK_RESET_PACKET 0x2 +#define QUIRK_BE_HEADERS 0x4 +#define QUIRK_NO_1394A 0x8 +#define QUIRK_NO_MSI 0x10 +#define QUIRK_TI_SLLZ059 0x20 +#define QUIRK_IR_WAKE 0x40 + +/* In case of multiple matches in ohci_quirks[], only the first one is used. */ +static const struct { + unsigned short vendor, device, revision, flags; +} ohci_quirks[] = { + {PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER}, + + {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID, + QUIRK_BE_HEADERS}, + + {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, + QUIRK_RESET_PACKET}, + + {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER}, + + {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, + QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, + + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV26, PCI_ANY_ID, + QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, + + {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB82AA2, PCI_ANY_ID, + QUIRK_RESET_PACKET | QUIRK_TI_SLLZ059}, + + {PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_RESET_PACKET}, + + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT630X, PCI_REV_ID_VIA_VT6306, + QUIRK_CYCLE_TIMER | QUIRK_IR_WAKE}, + + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, 0, + QUIRK_CYCLE_TIMER /* FIXME: necessary? */ | QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, PCI_ANY_ID, + QUIRK_NO_MSI}, + + {PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, +}; + +/* This overrides anything that was found in ohci_quirks[]. */ +static int param_quirks; +module_param_named(quirks, param_quirks, int, 0644); +MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" + ", nonatomic cycle timer = " __stringify(QUIRK_CYCLE_TIMER) + ", reset packet generation = " __stringify(QUIRK_RESET_PACKET) + ", AR/selfID endianness = " __stringify(QUIRK_BE_HEADERS) + ", no 1394a enhancements = " __stringify(QUIRK_NO_1394A) + ", disable MSI = " __stringify(QUIRK_NO_MSI) + ", TI SLLZ059 erratum = " __stringify(QUIRK_TI_SLLZ059) + ", IR wake unreliable = " __stringify(QUIRK_IR_WAKE) + ")"); #define OHCI_PARAM_DEBUG_AT_AR 1 #define OHCI_PARAM_DEBUG_SELFIDS 2 @@ -265,7 +372,11 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); -static void log_irqs(u32 evt) +static bool param_remote_dma; +module_param_named(remote_dma, param_remote_dma, bool, 0444); +MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)"); + +static void log_irqs(struct fw_ohci *ohci, u32 evt) { if (likely(!(param_debug & (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS)))) @@ -275,7 +386,7 @@ static void log_irqs(u32 evt) !(evt & OHCI1394_busReset)) return; - fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, + ohci_notice(ohci, "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", evt & OHCI1394_RSPkt ? " AR_resp" : "", @@ -288,6 +399,7 @@ static void log_irqs(u32 evt) evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", evt & OHCI1394_regAccessFail ? " regAccessFail" : "", + evt & OHCI1394_unrecoverableError ? " unrecoverableError" : "", evt & OHCI1394_busReset ? " busReset" : "", evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | @@ -313,24 +425,27 @@ static char _p(u32 *s, int shift) return port[*s >> shift & 3]; } -static void log_selfids(int node_id, int generation, int self_id_count, u32 *s) +static void log_selfids(struct fw_ohci *ohci, int generation, int self_id_count) { + u32 *s; + if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS))) return; - fw_notify("%d selfIDs, generation %d, local node ID %04x\n", - self_id_count, generation, node_id); + ohci_notice(ohci, "%d selfIDs, generation %d, local node ID %04x\n", + self_id_count, generation, ohci->node_id); - for (; self_id_count--; ++s) + for (s = ohci->self_id_buffer; self_id_count--; ++s) if ((*s & 1 << 23) == 0) - fw_notify("selfID 0: %08x, phy %d [%c%c%c] " - "%s gc=%d %s %s%s%s\n", + ohci_notice(ohci, + "selfID 0: %08x, phy %d [%c%c%c] %s gc=%d %s %s%s%s\n", *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2), speed[*s >> 14 & 3], *s >> 16 & 63, power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "", *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : ""); else - fw_notify("selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", + ohci_notice(ohci, + "selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n", *s, *s >> 24 & 63, _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10), _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2)); @@ -365,12 +480,9 @@ static const char *tcodes[] = { [0xc] = "-reserved-", [0xd] = "-reserved-", [0xe] = "link internal", [0xf] = "-reserved-", }; -static const char *phys[] = { - [0x0] = "phy config packet", [0x1] = "link-on packet", - [0x2] = "self-id packet", [0x3] = "-reserved-", -}; -static void log_ar_at_event(char dir, int speed, u32 *header, int evt) +static void log_ar_at_event(struct fw_ohci *ohci, + char dir, int speed, u32 *header, int evt) { int tcode = header[0] >> 4 & 0xf; char specific[12]; @@ -382,14 +494,8 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { - fw_notify("A%c evt_bus_reset, generation %d\n", - dir, (header[2] >> 16) & 0xff); - return; - } - - if (header[0] == ~header[1]) { - fw_notify("A%c %s, %s, %08x\n", - dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]); + ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n", + dir, (header[2] >> 16) & 0xff); return; } @@ -407,35 +513,30 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt) } switch (tcode) { - case 0xe: case 0xa: - fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); + case 0xa: + ohci_notice(ohci, "A%c %s, %s\n", + dir, evts[evt], tcodes[tcode]); + break; + case 0xe: + ohci_notice(ohci, "A%c %s, PHY %08x %08x\n", + dir, evts[evt], header[1], header[2]); break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: - fw_notify("A%c spd %x tl %02x, " - "%04x -> %04x, %s, " - "%s, %04x%08x%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], header[1] & 0xffff, header[2], specific); + ohci_notice(ohci, + "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %04x%08x%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], header[1] & 0xffff, header[2], specific); break; default: - fw_notify("A%c spd %x tl %02x, " - "%04x -> %04x, %s, " - "%s%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], specific); + ohci_notice(ohci, + "A%c spd %x tl %02x, %04x -> %04x, %s, %s%s\n", + dir, speed, header[0] >> 10 & 0x3f, + header[1] >> 16, header[0] >> 16, evts[evt], + tcodes[tcode], specific); } } -#else - -#define log_irqs(evt) -#define log_selfids(node_id, generation, self_id_count, sid) -#define log_ar_at_event(dir, speed, header, evt) - -#endif /* CONFIG_FIREWIRE_OHCI_DEBUG */ - static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data) { writel(data, ohci->registers + offset); @@ -452,79 +553,265 @@ static inline void flush_writes(const struct fw_ohci *ohci) reg_read(ohci, OHCI1394_Version); } -static int ohci_update_phy_reg(struct fw_card *card, int addr, - int clear_bits, int set_bits) +/* + * Beware! read_phy_reg(), write_phy_reg(), update_phy_reg(), and + * read_paged_phy_reg() require the caller to hold ohci->phy_reg_mutex. + * In other words, only use ohci_read_phy_reg() and ohci_update_phy_reg() + * directly. Exceptions are intrinsically serialized contexts like pci_probe. + */ +static int read_phy_reg(struct fw_ohci *ohci, int addr) { - struct fw_ohci *ohci = fw_ohci(card); - u32 val, old; + u32 val; + int i; reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr)); - flush_writes(ohci); - msleep(2); - val = reg_read(ohci, OHCI1394_PhyControl); - if ((val & OHCI1394_PhyControl_ReadDone) == 0) { - fw_error("failed to set phy reg bits.\n"); - return -EBUSY; + for (i = 0; i < 3 + 100; i++) { + val = reg_read(ohci, OHCI1394_PhyControl); + if (!~val) + return -ENODEV; /* Card was ejected. */ + + if (val & OHCI1394_PhyControl_ReadDone) + return OHCI1394_PhyControl_ReadData(val); + + /* + * Try a few times without waiting. Sleeping is necessary + * only when the link/PHY interface is busy. + */ + if (i >= 3) + msleep(1); } + ohci_err(ohci, "failed to read phy reg %d\n", addr); + dump_stack(); + + return -EBUSY; +} + +static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val) +{ + int i; - old = OHCI1394_PhyControl_ReadData(val); - old = (old & ~clear_bits) | set_bits; reg_write(ohci, OHCI1394_PhyControl, - OHCI1394_PhyControl_Write(addr, old)); + OHCI1394_PhyControl_Write(addr, val)); + for (i = 0; i < 3 + 100; i++) { + val = reg_read(ohci, OHCI1394_PhyControl); + if (!~val) + return -ENODEV; /* Card was ejected. */ - return 0; + if (!(val & OHCI1394_PhyControl_WritePending)) + return 0; + + if (i >= 3) + msleep(1); + } + ohci_err(ohci, "failed to write phy reg %d, val %u\n", addr, val); + dump_stack(); + + return -EBUSY; } -static int ar_context_add_page(struct ar_context *ctx) +static int update_phy_reg(struct fw_ohci *ohci, int addr, + int clear_bits, int set_bits) { - struct device *dev = ctx->ohci->card.device; - struct ar_buffer *ab; - dma_addr_t uninitialized_var(ab_bus); - size_t offset; + int ret = read_phy_reg(ohci, addr); + if (ret < 0) + return ret; - ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC); - if (ab == NULL) - return -ENOMEM; + /* + * The interrupt status bits are cleared by writing a one bit. + * Avoid clearing them unless explicitly requested in set_bits. + */ + if (addr == 5) + clear_bits |= PHY_INT_STATUS_BITS; - ab->next = NULL; - memset(&ab->descriptor, 0, sizeof(ab->descriptor)); - ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | - DESCRIPTOR_STATUS | - DESCRIPTOR_BRANCH_ALWAYS); - offset = offsetof(struct ar_buffer, data); - ab->descriptor.req_count = cpu_to_le16(PAGE_SIZE - offset); - ab->descriptor.data_address = cpu_to_le32(ab_bus + offset); - ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset); - ab->descriptor.branch_address = 0; - - ctx->last_buffer->descriptor.branch_address = cpu_to_le32(ab_bus | 1); - ctx->last_buffer->next = ab; - ctx->last_buffer = ab; + return write_phy_reg(ohci, addr, (ret & ~clear_bits) | set_bits); +} - reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); - flush_writes(ctx->ohci); +static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr) +{ + int ret; - return 0; + ret = update_phy_reg(ohci, 7, PHY_PAGE_SELECT, page << 5); + if (ret < 0) + return ret; + + return read_phy_reg(ohci, addr); +} + +static int ohci_read_phy_reg(struct fw_card *card, int addr) +{ + struct fw_ohci *ohci = fw_ohci(card); + int ret; + + mutex_lock(&ohci->phy_reg_mutex); + ret = read_phy_reg(ohci, addr); + mutex_unlock(&ohci->phy_reg_mutex); + + return ret; +} + +static int ohci_update_phy_reg(struct fw_card *card, int addr, + int clear_bits, int set_bits) +{ + struct fw_ohci *ohci = fw_ohci(card); + int ret; + + mutex_lock(&ohci->phy_reg_mutex); + ret = update_phy_reg(ohci, addr, clear_bits, set_bits); + mutex_unlock(&ohci->phy_reg_mutex); + + return ret; +} + +static inline dma_addr_t ar_buffer_bus(struct ar_context *ctx, unsigned int i) +{ + return page_private(ctx->pages[i]); +} + +static void ar_context_link_page(struct ar_context *ctx, unsigned int index) +{ + struct descriptor *d; + + d = &ctx->descriptors[index]; + d->branch_address &= cpu_to_le32(~0xf); + d->res_count = cpu_to_le16(PAGE_SIZE); + d->transfer_status = 0; + + wmb(); /* finish init of new descriptors before branch_address update */ + d = &ctx->descriptors[ctx->last_buffer_index]; + d->branch_address |= cpu_to_le32(1); + + ctx->last_buffer_index = index; + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); } static void ar_context_release(struct ar_context *ctx) { - struct ar_buffer *ab, *ab_next; - size_t offset; - dma_addr_t ab_bus; + unsigned int i; + + if (ctx->buffer) + vm_unmap_ram(ctx->buffer, AR_BUFFERS + AR_WRAPAROUND_PAGES); + + for (i = 0; i < AR_BUFFERS; i++) + if (ctx->pages[i]) { + dma_unmap_page(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(ctx->pages[i]); + } +} + +static void ar_context_abort(struct ar_context *ctx, const char *error_msg) +{ + struct fw_ohci *ohci = ctx->ohci; + + if (reg_read(ohci, CONTROL_CLEAR(ctx->regs)) & CONTEXT_RUN) { + reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + flush_writes(ohci); + + ohci_err(ohci, "AR error: %s; DMA stopped\n", error_msg); + } + /* FIXME: restart? */ +} + +static inline unsigned int ar_next_buffer_index(unsigned int index) +{ + return (index + 1) % AR_BUFFERS; +} + +static inline unsigned int ar_prev_buffer_index(unsigned int index) +{ + return (index - 1 + AR_BUFFERS) % AR_BUFFERS; +} + +static inline unsigned int ar_first_buffer_index(struct ar_context *ctx) +{ + return ar_next_buffer_index(ctx->last_buffer_index); +} + +/* + * We search for the buffer that contains the last AR packet DMA data written + * by the controller. + */ +static unsigned int ar_search_last_active_buffer(struct ar_context *ctx, + unsigned int *buffer_offset) +{ + unsigned int i, next_i, last = ctx->last_buffer_index; + __le16 res_count, next_res_count; + + i = ar_first_buffer_index(ctx); + res_count = ACCESS_ONCE(ctx->descriptors[i].res_count); - for (ab = ctx->current_buffer; ab; ab = ab_next) { - ab_next = ab->next; - offset = offsetof(struct ar_buffer, data); - ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; - dma_free_coherent(ctx->ohci->card.device, PAGE_SIZE, - ab, ab_bus); + /* A buffer that is not yet completely filled must be the last one. */ + while (i != last && res_count == 0) { + + /* Peek at the next descriptor. */ + next_i = ar_next_buffer_index(i); + rmb(); /* read descriptors in order */ + next_res_count = ACCESS_ONCE( + ctx->descriptors[next_i].res_count); + /* + * If the next descriptor is still empty, we must stop at this + * descriptor. + */ + if (next_res_count == cpu_to_le16(PAGE_SIZE)) { + /* + * The exception is when the DMA data for one packet is + * split over three buffers; in this case, the middle + * buffer's descriptor might be never updated by the + * controller and look still empty, and we have to peek + * at the third one. + */ + if (MAX_AR_PACKET_SIZE > PAGE_SIZE && i != last) { + next_i = ar_next_buffer_index(next_i); + rmb(); + next_res_count = ACCESS_ONCE( + ctx->descriptors[next_i].res_count); + if (next_res_count != cpu_to_le16(PAGE_SIZE)) + goto next_buffer_is_active; + } + + break; + } + +next_buffer_is_active: + i = next_i; + res_count = next_res_count; + } + + rmb(); /* read res_count before the DMA data */ + + *buffer_offset = PAGE_SIZE - le16_to_cpu(res_count); + if (*buffer_offset > PAGE_SIZE) { + *buffer_offset = 0; + ar_context_abort(ctx, "corrupted descriptor"); } + + return i; +} + +static void ar_sync_buffers_for_cpu(struct ar_context *ctx, + unsigned int end_buffer_index, + unsigned int end_buffer_offset) +{ + unsigned int i; + + i = ar_first_buffer_index(ctx); + while (i != end_buffer_index) { + dma_sync_single_for_cpu(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + i = ar_next_buffer_index(i); + } + if (end_buffer_offset > 0) + dma_sync_single_for_cpu(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + end_buffer_offset, DMA_FROM_DEVICE); } #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) #define cond_le32_to_cpu(v) \ - (ohci->old_uninorth ? (__force __u32)(v) : le32_to_cpu(v)) + (ohci->quirks & QUIRK_BE_HEADERS ? (__force __u32)(v) : le32_to_cpu(v)) #else #define cond_le32_to_cpu(v) le32_to_cpu(v) #endif @@ -562,6 +849,10 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; p.payload_length = p.header[3] >> 16; + if (p.payload_length > MAX_ASYNC_PAYLOAD) { + ar_context_abort(ctx, "invalid packet length"); + return NULL; + } break; case TCODE_WRITE_RESPONSE: @@ -572,9 +863,8 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) break; default: - /* FIXME: Stop context, discard everything, and restart? */ - p.header_length = 0; - p.payload_length = 0; + ar_context_abort(ctx, "invalid tcode"); + return NULL; } p.payload = (void *) buffer + p.header_length; @@ -589,10 +879,18 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.timestamp = status & 0xffff; p.generation = ohci->request_generation; - log_ar_at_event('R', p.speed, p.header, evt); + log_ar_at_event(ohci, 'R', p.speed, p.header, evt); + + /* + * Several controllers, notably from NEC and VIA, forget to + * write ack_complete status at PHY packet reception. + */ + if (evt == OHCI1394_evt_no_status && + (p.header[0] & 0xff) == (OHCI1394_phy_tcode << 4)) + p.ack = ACK_COMPLETE; /* - * The OHCI bus reset handler synthesizes a phy packet with + * The OHCI bus reset handler synthesizes a PHY packet with * the new generation number when a bus reset happens (see * section 8.4.2.3). This helps us determine when a request * was received and make sure we send the response in the same @@ -602,10 +900,10 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) * * Alas some chips sometimes emit bus reset packets with a * wrong generation. We set the correct generation for these - * at a slightly incorrect time (in bus_reset_tasklet). + * at a slightly incorrect time (in bus_reset_work). */ if (evt == OHCI1394_evt_bus_reset) { - if (!ohci->bus_reset_packet_quirk) + if (!(ohci->quirks & QUIRK_RESET_PACKET)) ohci->request_generation = (p.header[2] >> 16) & 0xff; } else if (ctx == &ohci->ar_request_ctx) { fw_core_handle_request(&ohci->card, &p); @@ -616,99 +914,158 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) return buffer + length + 1; } +static void *handle_ar_packets(struct ar_context *ctx, void *p, void *end) +{ + void *next; + + while (p < end) { + next = handle_ar_packet(ctx, p); + if (!next) + return p; + p = next; + } + + return p; +} + +static void ar_recycle_buffers(struct ar_context *ctx, unsigned int end_buffer) +{ + unsigned int i; + + i = ar_first_buffer_index(ctx); + while (i != end_buffer) { + dma_sync_single_for_device(ctx->ohci->card.device, + ar_buffer_bus(ctx, i), + PAGE_SIZE, DMA_FROM_DEVICE); + ar_context_link_page(ctx, i); + i = ar_next_buffer_index(i); + } +} + static void ar_context_tasklet(unsigned long data) { struct ar_context *ctx = (struct ar_context *)data; - struct fw_ohci *ohci = ctx->ohci; - struct ar_buffer *ab; - struct descriptor *d; - void *buffer, *end; + unsigned int end_buffer_index, end_buffer_offset; + void *p, *end; - ab = ctx->current_buffer; - d = &ab->descriptor; + p = ctx->pointer; + if (!p) + return; - if (d->res_count == 0) { - size_t size, rest, offset; - dma_addr_t start_bus; - void *start; + end_buffer_index = ar_search_last_active_buffer(ctx, + &end_buffer_offset); + ar_sync_buffers_for_cpu(ctx, end_buffer_index, end_buffer_offset); + end = ctx->buffer + end_buffer_index * PAGE_SIZE + end_buffer_offset; + if (end_buffer_index < ar_first_buffer_index(ctx)) { /* - * This descriptor is finished and we may have a - * packet split across this and the next buffer. We - * reuse the page for reassembling the split packet. + * The filled part of the overall buffer wraps around; handle + * all packets up to the buffer end here. If the last packet + * wraps around, its tail will be visible after the buffer end + * because the buffer start pages are mapped there again. */ + void *buffer_end = ctx->buffer + AR_BUFFERS * PAGE_SIZE; + p = handle_ar_packets(ctx, p, buffer_end); + if (p < buffer_end) + goto error; + /* adjust p to point back into the actual buffer */ + p -= AR_BUFFERS * PAGE_SIZE; + } - offset = offsetof(struct ar_buffer, data); - start = buffer = ab; - start_bus = le32_to_cpu(ab->descriptor.data_address) - offset; - - ab = ab->next; - d = &ab->descriptor; - size = buffer + PAGE_SIZE - ctx->pointer; - rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); - memmove(buffer, ctx->pointer, size); - memcpy(buffer + size, ab->data, rest); - ctx->current_buffer = ab; - ctx->pointer = (void *) ab->data + rest; - end = buffer + size + rest; - - while (buffer < end) - buffer = handle_ar_packet(ctx, buffer); - - dma_free_coherent(ohci->card.device, PAGE_SIZE, - start, start_bus); - ar_context_add_page(ctx); - } else { - buffer = ctx->pointer; - ctx->pointer = end = - (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count); - - while (buffer < end) - buffer = handle_ar_packet(ctx, buffer); + p = handle_ar_packets(ctx, p, end); + if (p != end) { + if (p > end) + ar_context_abort(ctx, "inconsistent descriptor"); + goto error; } + + ctx->pointer = p; + ar_recycle_buffers(ctx, end_buffer_index); + + return; + +error: + ctx->pointer = NULL; } -static int ar_context_init(struct ar_context *ctx, - struct fw_ohci *ohci, u32 regs) +static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, + unsigned int descriptors_offset, u32 regs) { - struct ar_buffer ab; + unsigned int i; + dma_addr_t dma_addr; + struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES]; + struct descriptor *d; ctx->regs = regs; ctx->ohci = ohci; - ctx->last_buffer = &ab; tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx); - ar_context_add_page(ctx); - ar_context_add_page(ctx); - ctx->current_buffer = ab.next; - ctx->pointer = ctx->current_buffer->data; + for (i = 0; i < AR_BUFFERS; i++) { + ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32); + if (!ctx->pages[i]) + goto out_of_memory; + dma_addr = dma_map_page(ohci->card.device, ctx->pages[i], + 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(ohci->card.device, dma_addr)) { + __free_page(ctx->pages[i]); + ctx->pages[i] = NULL; + goto out_of_memory; + } + set_page_private(ctx->pages[i], dma_addr); + } + + for (i = 0; i < AR_BUFFERS; i++) + pages[i] = ctx->pages[i]; + for (i = 0; i < AR_WRAPAROUND_PAGES; i++) + pages[AR_BUFFERS + i] = ctx->pages[i]; + ctx->buffer = vm_map_ram(pages, AR_BUFFERS + AR_WRAPAROUND_PAGES, + -1, PAGE_KERNEL); + if (!ctx->buffer) + goto out_of_memory; + + ctx->descriptors = ohci->misc_buffer + descriptors_offset; + ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset; + + for (i = 0; i < AR_BUFFERS; i++) { + d = &ctx->descriptors[i]; + d->req_count = cpu_to_le16(PAGE_SIZE); + d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | + DESCRIPTOR_STATUS | + DESCRIPTOR_BRANCH_ALWAYS); + d->data_address = cpu_to_le32(ar_buffer_bus(ctx, i)); + d->branch_address = cpu_to_le32(ctx->descriptors_bus + + ar_next_buffer_index(i) * sizeof(struct descriptor)); + } return 0; + +out_of_memory: + ar_context_release(ctx); + + return -ENOMEM; } static void ar_context_run(struct ar_context *ctx) { - struct ar_buffer *ab = ctx->current_buffer; - dma_addr_t ab_bus; - size_t offset; + unsigned int i; + + for (i = 0; i < AR_BUFFERS; i++) + ar_context_link_page(ctx, i); - offset = offsetof(struct ar_buffer, data); - ab_bus = le32_to_cpu(ab->descriptor.data_address) - offset; + ctx->pointer = ctx->buffer; - reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab_bus | 1); + reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ctx->descriptors_bus | 1); reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN); - flush_writes(ctx->ohci); } static struct descriptor *find_branch_descriptor(struct descriptor *d, int z) { - int b, key; + __le16 branch; - b = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2; - key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8; + branch = d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS); /* figure out which descriptor the branch address goes in */ - if (z == 2 && (b == 3 || key == 2)) + if (z == 2 && branch == cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) return d; else return d + z - 1; @@ -730,6 +1087,7 @@ static void context_tasklet(unsigned long data) address = le32_to_cpu(last->branch_address); z = address & 0xf; address &= ~0xf; + ctx->current_bus = address; /* If the branch address points to a buffer outside of the * current buffer, advance to the next buffer. */ @@ -817,6 +1175,7 @@ static int context_init(struct context *ctx, struct fw_ohci *ohci, ctx->buffer_tail->used += sizeof(*ctx->buffer_tail->buffer); ctx->last = ctx->buffer_tail->buffer; ctx->prev = ctx->buffer_tail->buffer; + ctx->prev_z = 1; return 0; } @@ -872,6 +1231,7 @@ static void context_run(struct context *ctx, u32 extra) le32_to_cpu(ctx->last->branch_address)); reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0); reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra); + ctx->running = true; flush_writes(ohci); } @@ -880,36 +1240,59 @@ static void context_append(struct context *ctx, { dma_addr_t d_bus; struct descriptor_buffer *desc = ctx->buffer_tail; + struct descriptor *d_branch; d_bus = desc->buffer_bus + (d - desc->buffer) * sizeof(*d); desc->used += (z + extra) * sizeof(*d); - ctx->prev->branch_address = cpu_to_le32(d_bus | z); - ctx->prev = find_branch_descriptor(d, z); - reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); - flush_writes(ctx->ohci); + wmb(); /* finish init of new descriptors before branch_address update */ + + d_branch = find_branch_descriptor(ctx->prev, ctx->prev_z); + d_branch->branch_address = cpu_to_le32(d_bus | z); + + /* + * VT6306 incorrectly checks only the single descriptor at the + * CommandPtr when the wake bit is written, so if it's a + * multi-descriptor block starting with an INPUT_MORE, put a copy of + * the branch address in the first descriptor. + * + * Not doing this for transmit contexts since not sure how it interacts + * with skip addresses. + */ + if (unlikely(ctx->ohci->quirks & QUIRK_IR_WAKE) && + d_branch != ctx->prev && + (ctx->prev->control & cpu_to_le16(DESCRIPTOR_CMD)) == + cpu_to_le16(DESCRIPTOR_INPUT_MORE)) { + ctx->prev->branch_address = cpu_to_le32(d_bus | z); + } + + ctx->prev = d; + ctx->prev_z = z; } static void context_stop(struct context *ctx) { + struct fw_ohci *ohci = ctx->ohci; u32 reg; int i; - reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); - flush_writes(ctx->ohci); + reg_write(ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN); + ctx->running = false; - for (i = 0; i < 10; i++) { - reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); + for (i = 0; i < 1000; i++) { + reg = reg_read(ohci, CONTROL_SET(ctx->regs)); if ((reg & CONTEXT_ACTIVE) == 0) return; - mdelay(1); + if (i) + udelay(10); } - fw_error("Error: DMA context still active (0x%08x)\n", reg); + ohci_err(ohci, "DMA context still active (0x%08x)\n", reg); } struct driver_data { + u8 inline_data[8]; struct fw_packet *packet; }; @@ -927,7 +1310,6 @@ static int at_context_queue_packet(struct context *ctx, struct descriptor *d, *last; __le32 *header; int z, tcode; - u32 reg; d = context_get_descriptors(ctx, 4, &d_bus); if (d == NULL) { @@ -939,23 +1321,29 @@ static int at_context_queue_packet(struct context *ctx, d[0].res_count = cpu_to_le16(packet->timestamp); /* - * The DMA format for asyncronous link packets is different + * The DMA format for asynchronous link packets is different * from the IEEE1394 layout, so shift the fields around - * accordingly. If header_length is 8, it's a PHY packet, to - * which we need to prepend an extra quadlet. + * accordingly. */ + tcode = (packet->header[0] >> 4) & 0x0f; header = (__le32 *) &d[1]; - switch (packet->header_length) { - case 16: - case 12: + switch (tcode) { + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_WRITE_RESPONSE: + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_READ_QUADLET_RESPONSE: + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_LOCK_RESPONSE: header[0] = cpu_to_le32((packet->header[0] & 0xffff) | (packet->speed << 16)); header[1] = cpu_to_le32((packet->header[1] & 0xffff) | (packet->header[0] & 0xffff0000)); header[2] = cpu_to_le32(packet->header[2]); - tcode = (packet->header[0] >> 4) & 0x0f; if (TCODE_IS_BLOCK_PACKET(tcode)) header[3] = cpu_to_le32(packet->header[3]); else @@ -964,15 +1352,18 @@ static int at_context_queue_packet(struct context *ctx, d[0].req_count = cpu_to_le16(packet->header_length); break; - case 8: + case TCODE_LINK_INTERNAL: header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) | (packet->speed << 16)); - header[1] = cpu_to_le32(packet->header[0]); - header[2] = cpu_to_le32(packet->header[1]); + header[1] = cpu_to_le32(packet->header[1]); + header[2] = cpu_to_le32(packet->header[2]); d[0].req_count = cpu_to_le16(12); + + if (is_ping_packet(&packet->header[1])) + d[0].control |= cpu_to_le16(DESCRIPTOR_PING); break; - case 4: + case TCODE_STREAM_DATA: header[0] = cpu_to_le32((packet->header[0] & 0xffff) | (packet->speed << 16)); header[1] = cpu_to_le32(packet->header[0] & 0xffff0000); @@ -985,20 +1376,28 @@ static int at_context_queue_packet(struct context *ctx, return -1; } + BUILD_BUG_ON(sizeof(struct driver_data) > sizeof(struct descriptor)); driver_data = (struct driver_data *) &d[3]; driver_data->packet = packet; packet->driver_data = driver_data; if (packet->payload_length > 0) { - payload_bus = - dma_map_single(ohci->card.device, packet->payload, - packet->payload_length, DMA_TO_DEVICE); - if (dma_mapping_error(ohci->card.device, payload_bus)) { - packet->ack = RCODE_SEND_ERROR; - return -1; + if (packet->payload_length > sizeof(driver_data->inline_data)) { + payload_bus = dma_map_single(ohci->card.device, + packet->payload, + packet->payload_length, + DMA_TO_DEVICE); + if (dma_mapping_error(ohci->card.device, payload_bus)) { + packet->ack = RCODE_SEND_ERROR; + return -1; + } + packet->payload_bus = payload_bus; + packet->payload_mapped = true; + } else { + memcpy(driver_data->inline_data, packet->payload, + packet->payload_length); + payload_bus = d_bus + 3 * sizeof(*d); } - packet->payload_bus = payload_bus; - packet->payload_mapped = true; d[2].req_count = cpu_to_le16(packet->payload_length); d[2].data_address = cpu_to_le32(payload_bus); @@ -1013,19 +1412,8 @@ static int at_context_queue_packet(struct context *ctx, DESCRIPTOR_IRQ_ALWAYS | DESCRIPTOR_BRANCH_ALWAYS); - /* - * If the controller and packet generations don't match, we need to - * bail out and try again. If IntEvent.busReset is set, the AT context - * is halted, so appending to the context and trying to run it is - * futile. Most controllers do the right thing and just flush the AT - * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but - * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind - * up stalling out. So we just bail out in software and try again - * later, and everyone is happy. - * FIXME: Document how the locking works. - */ - if (ohci->generation != packet->generation || - reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { + /* FIXME: Document how the locking works. */ + if (ohci->generation != packet->generation) { if (packet->payload_mapped) dma_unmap_single(ohci->card.device, payload_bus, packet->payload_length, DMA_TO_DEVICE); @@ -1035,14 +1423,25 @@ static int at_context_queue_packet(struct context *ctx, context_append(ctx, d, z, 4 - z); - /* If the context isn't already running, start it up. */ - reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs)); - if ((reg & CONTEXT_RUN) == 0) + if (ctx->running) + reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); + else context_run(ctx, 0); return 0; } +static void at_context_flush(struct context *ctx) +{ + tasklet_disable(&ctx->tasklet); + + ctx->flushing = true; + context_tasklet((unsigned long)ctx); + ctx->flushing = false; + + tasklet_enable(&ctx->tasklet); +} + static int handle_at_packet(struct context *context, struct descriptor *d, struct descriptor *last) @@ -1052,7 +1451,7 @@ static int handle_at_packet(struct context *context, struct fw_ohci *ohci = context->ohci; int evt; - if (last->transfer_status == 0) + if (last->transfer_status == 0 && !context->flushing) /* This descriptor isn't done yet, stop iteration. */ return 0; @@ -1069,7 +1468,7 @@ static int handle_at_packet(struct context *context, evt = le16_to_cpu(last->transfer_status) & 0x1f; packet->timestamp = le16_to_cpu(last->res_count); - log_ar_at_event('T', packet->speed, packet->header, evt); + log_ar_at_event(ohci, 'T', packet->speed, packet->header, evt); switch (evt) { case OHCI1394_evt_timeout: @@ -1086,11 +1485,15 @@ static int handle_at_packet(struct context *context, break; case OHCI1394_evt_missing_ack: - /* - * Using a valid (current) generation count, but the - * node is not on the bus or not sending acks. - */ - packet->ack = RCODE_NO_ACK; + if (context->flushing) + packet->ack = RCODE_GENERATION; + else { + /* + * Using a valid (current) generation count, but the + * node is not on the bus or not sending acks. + */ + packet->ack = RCODE_NO_ACK; + } break; case ACK_COMPLETE + 0x10: @@ -1103,6 +1506,13 @@ static int handle_at_packet(struct context *context, packet->ack = evt - 0x10; break; + case OHCI1394_evt_no_status: + if (context->flushing) { + packet->ack = RCODE_GENERATION; + break; + } + /* fall through */ + default: packet->ack = RCODE_SEND_ERROR; break; @@ -1150,7 +1560,7 @@ static void handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) { struct fw_packet response; - int tcode, length, ext_tcode, sel; + int tcode, length, ext_tcode, sel, try; __be32 *payload, lock_old; u32 lock_arg, lock_data; @@ -1177,21 +1587,26 @@ static void handle_local_lock(struct fw_ohci *ohci, reg_write(ohci, OHCI1394_CSRCompareData, lock_arg); reg_write(ohci, OHCI1394_CSRControl, sel); - if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) - lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData)); - else - fw_notify("swap not done yet\n"); + for (try = 0; try < 20; try++) + if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) { + lock_old = cpu_to_be32(reg_read(ohci, + OHCI1394_CSRData)); + fw_fill_response(&response, packet->header, + RCODE_COMPLETE, + &lock_old, sizeof(lock_old)); + goto out; + } + + ohci_err(ohci, "swap not done (CSR lock timeout)\n"); + fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0); - fw_fill_response(&response, packet->header, - RCODE_COMPLETE, &lock_old, sizeof(lock_old)); out: fw_core_handle_response(&ohci->card, &response); } static void handle_local_request(struct context *ctx, struct fw_packet *packet) { - u64 offset; - u32 csr; + u64 offset, csr; if (ctx == &ctx->ohci->at_request_ctx) { packet->ack = ACK_PENDING; @@ -1250,30 +1665,263 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) } -static void bus_reset_tasklet(unsigned long data) +static void detect_dead_context(struct fw_ohci *ohci, + const char *name, unsigned int regs) { - struct fw_ohci *ohci = (struct fw_ohci *)data; - int self_id_count, i, j, reg; - int generation, new_generation; - unsigned long flags; + u32 ctl; + + ctl = reg_read(ohci, CONTROL_SET(regs)); + if (ctl & CONTEXT_DEAD) + ohci_err(ohci, "DMA context %s has stopped, error code: %s\n", + name, evts[ctl & 0x1f]); +} + +static void handle_dead_contexts(struct fw_ohci *ohci) +{ + unsigned int i; + char name[8]; + + detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase); + detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase); + detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase); + detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase); + for (i = 0; i < 32; ++i) { + if (!(ohci->it_context_support & (1 << i))) + continue; + sprintf(name, "IT%u", i); + detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i)); + } + for (i = 0; i < 32; ++i) { + if (!(ohci->ir_context_support & (1 << i))) + continue; + sprintf(name, "IR%u", i); + detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i)); + } + /* TODO: maybe try to flush and restart the dead contexts */ +} + +static u32 cycle_timer_ticks(u32 cycle_timer) +{ + u32 ticks; + + ticks = cycle_timer & 0xfff; + ticks += 3072 * ((cycle_timer >> 12) & 0x1fff); + ticks += (3072 * 8000) * (cycle_timer >> 25); + + return ticks; +} + +/* + * Some controllers exhibit one or more of the following bugs when updating the + * iso cycle timer register: + * - When the lowest six bits are wrapping around to zero, a read that happens + * at the same time will return garbage in the lowest ten bits. + * - When the cycleOffset field wraps around to zero, the cycleCount field is + * not incremented for about 60 ns. + * - Occasionally, the entire register reads zero. + * + * To catch these, we read the register three times and ensure that the + * difference between each two consecutive reads is approximately the same, i.e. + * less than twice the other. Furthermore, any negative difference indicates an + * error. (A PCI read should take at least 20 ticks of the 24.576 MHz timer to + * execute, so we have enough precision to compute the ratio of the differences.) + */ +static u32 get_cycle_time(struct fw_ohci *ohci) +{ + u32 c0, c1, c2; + u32 t0, t1, t2; + s32 diff01, diff12; + int i; + + c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + + if (ohci->quirks & QUIRK_CYCLE_TIMER) { + i = 0; + c1 = c2; + c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + do { + c0 = c1; + c1 = c2; + c2 = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + t0 = cycle_timer_ticks(c0); + t1 = cycle_timer_ticks(c1); + t2 = cycle_timer_ticks(c2); + diff01 = t1 - t0; + diff12 = t2 - t1; + } while ((diff01 <= 0 || diff12 <= 0 || + diff01 / diff12 >= 2 || diff12 / diff01 >= 2) + && i++ < 20); + } + + return c2; +} + +/* + * This function has to be called at least every 64 seconds. The bus_time + * field stores not only the upper 25 bits of the BUS_TIME register but also + * the most significant bit of the cycle timer in bit 6 so that we can detect + * changes in this bit. + */ +static u32 update_bus_time(struct fw_ohci *ohci) +{ + u32 cycle_time_seconds = get_cycle_time(ohci) >> 25; + + if (unlikely(!ohci->bus_time_running)) { + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_cycle64Seconds); + ohci->bus_time = (lower_32_bits(get_seconds()) & ~0x7f) | + (cycle_time_seconds & 0x40); + ohci->bus_time_running = true; + } + + if ((ohci->bus_time & 0x40) != (cycle_time_seconds & 0x40)) + ohci->bus_time += 0x40; + + return ohci->bus_time | cycle_time_seconds; +} + +static int get_status_for_port(struct fw_ohci *ohci, int port_index) +{ + int reg; + + mutex_lock(&ohci->phy_reg_mutex); + reg = write_phy_reg(ohci, 7, port_index); + if (reg >= 0) + reg = read_phy_reg(ohci, 8); + mutex_unlock(&ohci->phy_reg_mutex); + if (reg < 0) + return reg; + + switch (reg & 0x0f) { + case 0x06: + return 2; /* is child node (connected to parent node) */ + case 0x0e: + return 3; /* is parent node (connected to child node) */ + } + return 1; /* not connected */ +} + +static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id, + int self_id_count) +{ + int i; + u32 entry; + + for (i = 0; i < self_id_count; i++) { + entry = ohci->self_id_buffer[i]; + if ((self_id & 0xff000000) == (entry & 0xff000000)) + return -1; + if ((self_id & 0xff000000) < (entry & 0xff000000)) + return i; + } + return i; +} + +static int initiated_reset(struct fw_ohci *ohci) +{ + int reg; + int ret = 0; + + mutex_lock(&ohci->phy_reg_mutex); + reg = write_phy_reg(ohci, 7, 0xe0); /* Select page 7 */ + if (reg >= 0) { + reg = read_phy_reg(ohci, 8); + reg |= 0x40; + reg = write_phy_reg(ohci, 8, reg); /* set PMODE bit */ + if (reg >= 0) { + reg = read_phy_reg(ohci, 12); /* read register 12 */ + if (reg >= 0) { + if ((reg & 0x08) == 0x08) { + /* bit 3 indicates "initiated reset" */ + ret = 0x2; + } + } + } + } + mutex_unlock(&ohci->phy_reg_mutex); + return ret; +} + +/* + * TI TSB82AA2B and TSB12LV26 do not receive the selfID of a locally + * attached TSB41BA3D phy; see http://www.ti.com/litv/pdf/sllz059. + * Construct the selfID from phy register contents. + */ +static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) +{ + int reg, i, pos, status; + /* link active 1, speed 3, bridge 0, contender 1, more packets 0 */ + u32 self_id = 0x8040c800; + + reg = reg_read(ohci, OHCI1394_NodeID); + if (!(reg & OHCI1394_NodeID_idValid)) { + ohci_notice(ohci, + "node ID not valid, new bus reset in progress\n"); + return -EBUSY; + } + self_id |= ((reg & 0x3f) << 24); /* phy ID */ + + reg = ohci_read_phy_reg(&ohci->card, 4); + if (reg < 0) + return reg; + self_id |= ((reg & 0x07) << 8); /* power class */ + + reg = ohci_read_phy_reg(&ohci->card, 1); + if (reg < 0) + return reg; + self_id |= ((reg & 0x3f) << 16); /* gap count */ + + for (i = 0; i < 3; i++) { + status = get_status_for_port(ohci, i); + if (status < 0) + return status; + self_id |= ((status & 0x3) << (6 - (i * 2))); + } + + self_id |= initiated_reset(ohci); + + pos = get_self_id_pos(ohci, self_id, self_id_count); + if (pos >= 0) { + memmove(&(ohci->self_id_buffer[pos+1]), + &(ohci->self_id_buffer[pos]), + (self_id_count - pos) * sizeof(*ohci->self_id_buffer)); + ohci->self_id_buffer[pos] = self_id; + self_id_count++; + } + return self_id_count; +} + +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, generation, new_generation, i, j; + u32 reg; void *free_rom = NULL; dma_addr_t free_rom_bus = 0; + bool is_new_root; reg = reg_read(ohci, OHCI1394_NodeID); if (!(reg & OHCI1394_NodeID_idValid)) { - fw_notify("node ID not valid, new bus reset in progress\n"); + ohci_notice(ohci, + "node ID not valid, new bus reset in progress\n"); return; } if ((reg & OHCI1394_NodeID_nodeNumber) == 63) { - fw_notify("malconfigured bus\n"); + ohci_notice(ohci, "malconfigured bus\n"); return; } ohci->node_id = reg & (OHCI1394_NodeID_busNumber | OHCI1394_NodeID_nodeNumber); + is_new_root = (reg & OHCI1394_NodeID_root) != 0; + if (!(ohci->is_root && is_new_root)) + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_cycleMaster); + ohci->is_root = is_new_root; + reg = reg_read(ohci, OHCI1394_SelfIDCount); if (reg & OHCI1394_SelfIDCount_selfIDError) { - fw_notify("inconsistent self IDs\n"); + ohci_notice(ohci, "self ID receive error\n"); return; } /* @@ -1283,20 +1931,52 @@ static void bus_reset_tasklet(unsigned long data) * bit extra to get the actual number of self IDs. */ self_id_count = (reg >> 3) & 0xff; - if (self_id_count == 0 || self_id_count > 252) { - fw_notify("inconsistent self IDs\n"); + + if (self_id_count > 252) { + ohci_notice(ohci, "bad selfIDSize (%08x)\n", reg); return; } - generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff; + + generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff; rmb(); for (i = 1, j = 0; j < self_id_count; i += 2, j++) { - if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1]) { - fw_notify("inconsistent self IDs\n"); + u32 id = cond_le32_to_cpu(ohci->self_id[i]); + u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]); + + if (id != ~id2) { + /* + * If the invalid data looks like a cycle start packet, + * it's likely to be the result of the cycle master + * having a wrong gap count. In this case, the self IDs + * so far are valid and should be processed so that the + * bus manager can then correct the gap count. + */ + if (id == 0xffff008f) { + ohci_notice(ohci, "ignoring spurious self IDs\n"); + self_id_count = j; + break; + } + + ohci_notice(ohci, "bad self ID %d/%d (%08x != ~%08x)\n", + j, self_id_count, id, id2); + return; + } + ohci->self_id_buffer[j] = id; + } + + if (ohci->quirks & QUIRK_TI_SLLZ059) { + self_id_count = find_and_insert_self_id(ohci, self_id_count); + if (self_id_count < 0) { + ohci_notice(ohci, + "could not construct local self ID\n"); return; } - ohci->self_id_buffer[j] = - cond_le32_to_cpu(ohci->self_id_cpu[i]); + } + + if (self_id_count == 0) { + ohci_notice(ohci, "no self IDs\n"); + return; } rmb(); @@ -1316,20 +1996,33 @@ static void bus_reset_tasklet(unsigned long data) new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff; if (new_generation != generation) { - fw_notify("recursive bus reset detected, " - "discarding self ids\n"); + ohci_notice(ohci, "new bus reset, discarding self ids\n"); return; } /* FIXME: Document how the locking works. */ - spin_lock_irqsave(&ohci->lock, flags); + spin_lock_irq(&ohci->lock); - ohci->generation = generation; + ohci->generation = -1; /* prevent AT packet queueing */ context_stop(&ohci->at_request_ctx); context_stop(&ohci->at_response_ctx); + + spin_unlock_irq(&ohci->lock); + + /* + * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent + * packets in the AT queues and software needs to drain them. + * Some OHCI 1.1 controllers (JMicron) apparently require this too. + */ + at_context_flush(&ohci->at_request_ctx); + at_context_flush(&ohci->at_response_ctx); + + spin_lock_irq(&ohci->lock); + + ohci->generation = generation; reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); - if (ohci->bus_reset_packet_quirk) + if (ohci->quirks & QUIRK_RESET_PACKET) ohci->request_generation = generation; /* @@ -1338,7 +2031,7 @@ static void bus_reset_tasklet(unsigned long data) * was set up before this reset, the old one is now no longer * in use and we can free it. Update the config rom pointers * to point to the current config rom and clear the - * next_config_rom pointer so a new udpate can take place. + * next_config_rom pointer so a new update can take place. */ if (ohci->next_config_rom != NULL) { @@ -1363,28 +2056,29 @@ static void bus_reset_tasklet(unsigned long data) be32_to_cpu(ohci->next_header)); } -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); - reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); -#endif + if (param_remote_dma) { + reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0); + reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0); + } - spin_unlock_irqrestore(&ohci->lock, flags); + spin_unlock_irq(&ohci->lock); if (free_rom) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, free_rom, free_rom_bus); - log_selfids(ohci->node_id, generation, - self_id_count, ohci->self_id_buffer); + log_selfids(ohci, generation, self_id_count); fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation, - self_id_count, ohci->self_id_buffer); + self_id_count, ohci->self_id_buffer, + ohci->csr_state_setclear_abdicate); + ohci->csr_state_setclear_abdicate = false; } static irqreturn_t irq_handler(int irq, void *data) { struct fw_ohci *ohci = data; - u32 event, iso_event, cycle_time; + u32 event, iso_event; int i; event = reg_read(ohci, OHCI1394_IntEventClear); @@ -1392,12 +2086,16 @@ static irqreturn_t irq_handler(int irq, void *data) if (!event || !~event) return IRQ_NONE; - /* busReset must not be cleared yet, see OHCI 1.1 clause 7.2.3.2 */ - reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); - log_irqs(event); + /* + * busReset and postedWriteErr must not be cleared yet + * (OHCI 1.1 clauses 7.2.3.2 and 13.2.8.1) + */ + reg_write(ohci, OHCI1394_IntEventClear, + event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); + log_irqs(ohci, event); if (event & OHCI1394_selfIDComplete) - tasklet_schedule(&ohci->bus_reset_tasklet); + queue_work(selfid_workqueue, &ohci->bus_reset_work); if (event & OHCI1394_RQPkt) tasklet_schedule(&ohci->ar_request_ctx.tasklet); @@ -1411,34 +2109,45 @@ static irqreturn_t irq_handler(int irq, void *data) if (event & OHCI1394_respTxComplete) tasklet_schedule(&ohci->at_response_ctx.tasklet); - iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear); - reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event); + if (event & OHCI1394_isochRx) { + iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event); - while (iso_event) { - i = ffs(iso_event) - 1; - tasklet_schedule(&ohci->ir_context_list[i].context.tasklet); - iso_event &= ~(1 << i); + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule( + &ohci->ir_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } } - iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear); - reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event); + if (event & OHCI1394_isochTx) { + iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event); - while (iso_event) { - i = ffs(iso_event) - 1; - tasklet_schedule(&ohci->it_context_list[i].context.tasklet); - iso_event &= ~(1 << i); + while (iso_event) { + i = ffs(iso_event) - 1; + tasklet_schedule( + &ohci->it_context_list[i].context.tasklet); + iso_event &= ~(1 << i); + } } if (unlikely(event & OHCI1394_regAccessFail)) - fw_error("Register access failure - " - "please notify linux1394-devel@lists.sf.net\n"); + ohci_err(ohci, "register access failure\n"); - if (unlikely(event & OHCI1394_postedWriteErr)) - fw_error("PCI posted write error\n"); + if (unlikely(event & OHCI1394_postedWriteErr)) { + reg_read(ohci, OHCI1394_PostedWriteAddressHi); + reg_read(ohci, OHCI1394_PostedWriteAddressLo); + reg_write(ohci, OHCI1394_IntEventClear, + OHCI1394_postedWriteErr); + if (printk_ratelimit()) + ohci_err(ohci, "PCI posted write error\n"); + } if (unlikely(event & OHCI1394_cycleTooLong)) { if (printk_ratelimit()) - fw_notify("isochronous cycle too long\n"); + ohci_notice(ohci, "isochronous cycle too long\n"); reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_cycleMaster); } @@ -1451,28 +2160,36 @@ static irqreturn_t irq_handler(int irq, void *data) * them at least two cycles later. (FIXME?) */ if (printk_ratelimit()) - fw_notify("isochronous cycle inconsistent\n"); + ohci_notice(ohci, "isochronous cycle inconsistent\n"); } + if (unlikely(event & OHCI1394_unrecoverableError)) + handle_dead_contexts(ohci); + if (event & OHCI1394_cycle64Seconds) { - cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - if ((cycle_time & 0x80000000) == 0) - atomic_inc(&ohci->bus_seconds); - } + spin_lock(&ohci->lock); + update_bus_time(ohci); + spin_unlock(&ohci->lock); + } else + flush_writes(ohci); return IRQ_HANDLED; } static int software_reset(struct fw_ohci *ohci) { + u32 val; int i; reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); + for (i = 0; i < 500; i++) { + val = reg_read(ohci, OHCI1394_HCControlSet); + if (!~val) + return -ENODEV; /* Card was ejected. */ - for (i = 0; i < OHCI_LOOP_COUNT; i++) { - if ((reg_read(ohci, OHCI1394_HCControlSet) & - OHCI1394_HCControl_softReset) == 0) + if (!(val & OHCI1394_HCControl_softReset)) return 0; + msleep(1); } @@ -1488,16 +2205,88 @@ static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length) memset(&dest[length], 0, CONFIG_ROM_SIZE - size); } +static int configure_1394a_enhancements(struct fw_ohci *ohci) +{ + bool enable_1394a; + int ret, clear, set, offset; + + /* Check if the driver should configure link and PHY. */ + if (!(reg_read(ohci, OHCI1394_HCControlSet) & + OHCI1394_HCControl_programPhyEnable)) + return 0; + + /* Paranoia: check whether the PHY supports 1394a, too. */ + enable_1394a = false; + ret = read_phy_reg(ohci, 2); + if (ret < 0) + return ret; + if ((ret & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) { + ret = read_paged_phy_reg(ohci, 1, 8); + if (ret < 0) + return ret; + if (ret >= 1) + enable_1394a = true; + } + + if (ohci->quirks & QUIRK_NO_1394A) + enable_1394a = false; + + /* Configure PHY and link consistently. */ + if (enable_1394a) { + clear = 0; + set = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI; + } else { + clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI; + set = 0; + } + ret = update_phy_reg(ohci, 5, clear, set); + if (ret < 0) + return ret; + + if (enable_1394a) + offset = OHCI1394_HCControlSet; + else + offset = OHCI1394_HCControlClear; + reg_write(ohci, offset, OHCI1394_HCControl_aPhyEnhanceEnable); + + /* Clean up: configuration has been taken care of. */ + reg_write(ohci, OHCI1394_HCControlClear, + OHCI1394_HCControl_programPhyEnable); + + return 0; +} + +static int probe_tsb41ba3d(struct fw_ohci *ohci) +{ + /* TI vendor ID = 0x080028, TSB41BA3D product ID = 0x833005 (sic) */ + static const u8 id[] = { 0x08, 0x00, 0x28, 0x83, 0x30, 0x05, }; + int reg, i; + + reg = read_phy_reg(ohci, 2); + if (reg < 0) + return reg; + if ((reg & PHY_EXTENDED_REGISTERS) != PHY_EXTENDED_REGISTERS) + return 0; + + for (i = ARRAY_SIZE(id) - 1; i >= 0; i--) { + reg = read_paged_phy_reg(ohci, 1, i + 10); + if (reg < 0) + return reg; + if (reg != id[i]) + return 0; + } + return 1; +} + static int ohci_enable(struct fw_card *card, const __be32 *config_rom, size_t length) { struct fw_ohci *ohci = fw_ohci(card); - struct pci_dev *dev = to_pci_dev(card->device); - u32 lps; - int i; + u32 lps, version, irqs; + int i, ret; if (software_reset(ohci)) { - fw_error("Failed to reset ohci card.\n"); + ohci_err(ohci, "failed to reset ohci card\n"); return -EBUSY; } @@ -1508,7 +2297,12 @@ static int ohci_enable(struct fw_card *card, * will lock up the machine. Wait 50msec to make sure we have * full link enabled. However, with some cards (well, at least * a JMicron PCIe card), we have to try again sometimes. + * + * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but + * cannot actually use the phy at that time. These need tens of + * millisecods pause between LPS write and first phy access too. */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS | OHCI1394_HCControl_postedWriteEnable); @@ -1521,48 +2315,66 @@ static int ohci_enable(struct fw_card *card, } if (!lps) { - fw_error("Failed to set Link Power Status\n"); + ohci_err(ohci, "failed to set Link Power Status\n"); return -EIO; } + if (ohci->quirks & QUIRK_TI_SLLZ059) { + ret = probe_tsb41ba3d(ohci); + if (ret < 0) + return ret; + if (ret) + ohci_notice(ohci, "local TSB41BA3D phy\n"); + else + ohci->quirks &= ~QUIRK_TI_SLLZ059; + } + reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwapData); reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus); - reg_write(ohci, OHCI1394_LinkControlClear, - OHCI1394_LinkControl_rcvPhyPkt); reg_write(ohci, OHCI1394_LinkControlSet, - OHCI1394_LinkControl_rcvSelfID | OHCI1394_LinkControl_cycleTimerEnable | OHCI1394_LinkControl_cycleMaster); reg_write(ohci, OHCI1394_ATRetries, OHCI1394_MAX_AT_REQ_RETRIES | (OHCI1394_MAX_AT_RESP_RETRIES << 4) | - (OHCI1394_MAX_PHYS_RESP_RETRIES << 8)); + (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) | + (200 << 16)); - ar_context_run(&ohci->ar_request_ctx); - ar_context_run(&ohci->ar_response_ctx); + ohci->bus_time_running = false; + + for (i = 0; i < 32; i++) + if (ohci->ir_context_support & (1 << i)) + reg_write(ohci, OHCI1394_IsoRcvContextControlClear(i), + IR_CONTEXT_MULTI_CHANNEL_MODE); + + version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; + if (version >= OHCI_VERSION_1_1) { + reg_write(ohci, OHCI1394_InitialChannelsAvailableHi, + 0xfffffffe); + card->broadcast_channel_auto_allocated = true; + } + + /* Get implemented bits of the priority arbitration request counter. */ + reg_write(ohci, OHCI1394_FairnessControl, 0x3f); + ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f; + reg_write(ohci, OHCI1394_FairnessControl, 0); + card->priority_budget_implemented = ohci->pri_req_max != 0; - reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000); + reg_write(ohci, OHCI1394_PhyUpperBound, FW_MAX_PHYSICAL_RANGE >> 16); reg_write(ohci, OHCI1394_IntEventClear, ~0); reg_write(ohci, OHCI1394_IntMaskClear, ~0); - reg_write(ohci, OHCI1394_IntMaskSet, - OHCI1394_selfIDComplete | - OHCI1394_RQPkt | OHCI1394_RSPkt | - OHCI1394_reqTxComplete | OHCI1394_respTxComplete | - OHCI1394_isochRx | OHCI1394_isochTx | - OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | - OHCI1394_cycleInconsistent | - OHCI1394_cycle64Seconds | OHCI1394_regAccessFail | - OHCI1394_masterIntEnable); - if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) - reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + + ret = configure_1394a_enhancements(ohci); + if (ret < 0) + return ret; /* Activate link_on bit and contender bit in our self ID packets.*/ - if (ohci_update_phy_reg(card, 4, 0, - PHY_LINK_ACTIVE | PHY_CONTENDER) < 0) - return -EIO; + ret = ohci_update_phy_reg(card, 4, 0, PHY_LINK_ACTIVE | PHY_CONTENDER); + if (ret < 0) + return ret; /* * When the link is not yet enabled, the atomic config rom @@ -1610,26 +2422,35 @@ static int ohci_enable(struct fw_card *card, reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); - if (request_irq(dev->irq, irq_handler, - IRQF_SHARED, ohci_driver_name, ohci)) { - fw_error("Failed to allocate shared interrupt %d.\n", - dev->irq); - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - ohci->config_rom, ohci->config_rom_bus); - return -EIO; - } + irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete | + OHCI1394_RQPkt | OHCI1394_RSPkt | + OHCI1394_isochTx | OHCI1394_isochRx | + OHCI1394_postedWriteErr | + OHCI1394_selfIDComplete | + OHCI1394_regAccessFail | + OHCI1394_cycleInconsistent | + OHCI1394_unrecoverableError | + OHCI1394_cycleTooLong | + OHCI1394_masterIntEnable; + if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) + irqs |= OHCI1394_busReset; + reg_write(ohci, OHCI1394_IntMaskSet, irqs); reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable | OHCI1394_HCControl_BIBimageValid); - flush_writes(ohci); - /* - * We are ready to go, initiate bus reset to finish the - * initialization. - */ + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_rcvSelfID | + OHCI1394_LinkControl_rcvPhyPkt); - fw_core_initiate_bus_reset(&ohci->card, 1); + ar_context_run(&ohci->ar_request_ctx); + ar_context_run(&ohci->ar_response_ctx); + + flush_writes(ohci); + + /* We are ready to go, reset bus to finish initialization. */ + fw_schedule_bus_reset(&ohci->card, false, true); return 0; } @@ -1638,8 +2459,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; - int ret = -EBUSY; __be32 *next_config_rom; dma_addr_t uninitialized_var(next_config_rom_bus); @@ -1669,7 +2488,7 @@ static int ohci_set_config_rom(struct fw_card *card, * then set up the real values for the two registers. * * We use ohci->lock to avoid racing with the code that sets - * ohci->next_config_rom to NULL (see bus_reset_tasklet). + * ohci->next_config_rom to NULL (see bus_reset_work). */ next_config_rom = @@ -1678,23 +2497,38 @@ 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, + * push our new allocation into the ohci->next_config_rom + * and then mark the local variable as null so that we + * won't deallocate the new buffer. + * + * OTOH, if there is a pending config_rom update, just + * use that buffer with the new config_rom data, and + * let this routine free the unused DMA allocation. + */ if (ohci->next_config_rom == NULL) { ohci->next_config_rom = next_config_rom; ohci->next_config_rom_bus = next_config_rom_bus; + next_config_rom = NULL; + } - copy_config_rom(ohci->next_config_rom, config_rom, length); + copy_config_rom(ohci->next_config_rom, config_rom, length); - ohci->next_header = config_rom[0]; - ohci->next_config_rom[0] = 0; + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; - reg_write(ohci, OHCI1394_ConfigROMmap, - ohci->next_config_rom_bus); - ret = 0; - } + 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) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + next_config_rom, next_config_rom_bus); /* * Now initiate a bus reset to have the changes take @@ -1703,13 +2537,10 @@ static int ohci_set_config_rom(struct fw_card *card, * controller could need to access it before the bus reset * takes effect. */ - if (ret == 0) - fw_core_initiate_bus_reset(&ohci->card, 1); - else - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - next_config_rom, next_config_rom_bus); - return ret; + fw_schedule_bus_reset(&ohci->card, true, true); + + return 0; } static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) @@ -1742,7 +2573,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) 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); + log_ar_at_event(ohci, 'T', packet->speed, packet->header, 0x20); driver_data->packet = NULL; packet->ack = RCODE_CANCELLED; packet->callback(packet, &ohci->card, packet->ack); @@ -1756,13 +2587,13 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) static int ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) { -#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA - return 0; -#else struct fw_ohci *ohci = fw_ohci(card); unsigned long flags; int n, ret = 0; + if (param_remote_dma) + return 0; + /* * FIXME: Make sure this bitmask is cleared when we clear the busReset * interrupt bit. Clear physReqResourceAllBuses on bus reset. @@ -1791,130 +2622,288 @@ static int ohci_enable_phys_dma(struct fw_card *card, spin_unlock_irqrestore(&ohci->lock, flags); return ret; -#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */ } -static u64 ohci_get_bus_time(struct fw_card *card) +static u32 ohci_read_csr(struct fw_card *card, int csr_offset) { struct fw_ohci *ohci = fw_ohci(card); - u32 cycle_time; - u64 bus_time; + unsigned long flags; + u32 value; + + switch (csr_offset) { + case CSR_STATE_CLEAR: + case CSR_STATE_SET: + if (ohci->is_root && + (reg_read(ohci, OHCI1394_LinkControlSet) & + OHCI1394_LinkControl_cycleMaster)) + value = CSR_STATE_BIT_CMSTR; + else + value = 0; + if (ohci->csr_state_setclear_abdicate) + value |= CSR_STATE_BIT_ABDICATE; + + return value; + + case CSR_NODE_IDS: + return reg_read(ohci, OHCI1394_NodeID) << 16; + + case CSR_CYCLE_TIME: + return get_cycle_time(ohci); + + case CSR_BUS_TIME: + /* + * We might be called just after the cycle timer has wrapped + * around but just before the cycle64Seconds handler, so we + * better check here, too, if the bus time needs to be updated. + */ + spin_lock_irqsave(&ohci->lock, flags); + value = update_bus_time(ohci); + spin_unlock_irqrestore(&ohci->lock, flags); + return value; + + case CSR_BUSY_TIMEOUT: + value = reg_read(ohci, OHCI1394_ATRetries); + return (value >> 4) & 0x0ffff00f; - cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer); - bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time; + case CSR_PRIORITY_BUDGET: + return (reg_read(ohci, OHCI1394_FairnessControl) & 0x3f) | + (ohci->pri_req_max << 8); - return bus_time; + default: + WARN_ON(1); + return 0; + } } -static void copy_iso_headers(struct iso_context *ctx, void *p) +static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value) { - int i = ctx->header_length; + struct fw_ohci *ohci = fw_ohci(card); + unsigned long flags; - if (i + ctx->base.header_size > PAGE_SIZE) - return; + switch (csr_offset) { + case CSR_STATE_CLEAR: + if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) { + reg_write(ohci, OHCI1394_LinkControlClear, + OHCI1394_LinkControl_cycleMaster); + flush_writes(ohci); + } + if (value & CSR_STATE_BIT_ABDICATE) + ohci->csr_state_setclear_abdicate = false; + break; + + case CSR_STATE_SET: + if ((value & CSR_STATE_BIT_CMSTR) && ohci->is_root) { + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_cycleMaster); + flush_writes(ohci); + } + if (value & CSR_STATE_BIT_ABDICATE) + ohci->csr_state_setclear_abdicate = true; + break; + + case CSR_NODE_IDS: + reg_write(ohci, OHCI1394_NodeID, value >> 16); + flush_writes(ohci); + break; + + case CSR_CYCLE_TIME: + reg_write(ohci, OHCI1394_IsochronousCycleTimer, value); + reg_write(ohci, OHCI1394_IntEventSet, + OHCI1394_cycleInconsistent); + flush_writes(ohci); + break; + + case CSR_BUS_TIME: + spin_lock_irqsave(&ohci->lock, flags); + ohci->bus_time = (update_bus_time(ohci) & 0x40) | + (value & ~0x7f); + spin_unlock_irqrestore(&ohci->lock, flags); + break; + + case CSR_BUSY_TIMEOUT: + value = (value & 0xf) | ((value & 0xf) << 4) | + ((value & 0xf) << 8) | ((value & 0x0ffff000) << 4); + reg_write(ohci, OHCI1394_ATRetries, value); + flush_writes(ohci); + break; + + case CSR_PRIORITY_BUDGET: + reg_write(ohci, OHCI1394_FairnessControl, value & 0x3f); + flush_writes(ohci); + break; + + default: + WARN_ON(1); + break; + } +} + +static void flush_iso_completions(struct iso_context *ctx) +{ + ctx->base.callback.sc(&ctx->base, ctx->last_timestamp, + ctx->header_length, ctx->header, + ctx->base.callback_data); + ctx->header_length = 0; +} + +static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) +{ + u32 *ctx_hdr; + + if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) { + if (ctx->base.drop_overflow_headers) + return; + flush_iso_completions(ctx); + } + + ctx_hdr = ctx->header + ctx->header_length; + ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]); /* - * The iso header is byteswapped to little endian by - * the controller, but the remaining header quadlets - * are big endian. We want to present all the headers - * as big endian, so we have to swap the first quadlet. + * The two iso header quadlets are byteswapped to little + * endian by the controller, but we want to present them + * as big endian for consistency with the bus endianness. */ if (ctx->base.header_size > 0) - *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); + ctx_hdr[0] = swab32(dma_hdr[1]); /* iso packet header */ if (ctx->base.header_size > 4) - *(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p); + ctx_hdr[1] = swab32(dma_hdr[0]); /* timestamp */ if (ctx->base.header_size > 8) - memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8); + memcpy(&ctx_hdr[2], &dma_hdr[2], ctx->base.header_size - 8); ctx->header_length += ctx->base.header_size; } -static int handle_ir_dualbuffer_packet(struct context *context, +static int handle_ir_packet_per_buffer(struct context *context, struct descriptor *d, struct descriptor *last) { struct iso_context *ctx = container_of(context, struct iso_context, context); - struct db_descriptor *db = (struct db_descriptor *) d; - __le32 *ir_header; - size_t header_length; - void *p, *end; - - if (db->first_res_count != 0 && db->second_res_count != 0) { - if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) { - /* This descriptor isn't done yet, stop iteration. */ - return 0; - } - ctx->excess_bytes -= le16_to_cpu(db->second_req_count); - } + struct descriptor *pd; + u32 buffer_dma; - header_length = le16_to_cpu(db->first_req_count) - - le16_to_cpu(db->first_res_count); + for (pd = d; pd <= last; pd++) + if (pd->transfer_status) + break; + if (pd > last) + /* Descriptor(s) not done yet, stop iteration */ + return 0; - p = db + 1; - end = p + header_length; - while (p < end) { - copy_iso_headers(ctx, p); - ctx->excess_bytes += - (le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff; - p += max(ctx->base.header_size, (size_t)8); + while (!(d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))) { + d++; + buffer_dma = le32_to_cpu(d->data_address); + dma_sync_single_range_for_cpu(context->ohci->card.device, + buffer_dma & PAGE_MASK, + buffer_dma & ~PAGE_MASK, + le16_to_cpu(d->req_count), + DMA_FROM_DEVICE); } - ctx->excess_bytes -= le16_to_cpu(db->second_req_count) - - le16_to_cpu(db->second_res_count); + copy_iso_headers(ctx, (u32 *) (last + 1)); - if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) { - ir_header = (__le32 *) (db + 1); - ctx->base.callback(&ctx->base, - le32_to_cpu(ir_header[0]) & 0xffff, - ctx->header_length, ctx->header, - ctx->base.callback_data); - ctx->header_length = 0; - } + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) + flush_iso_completions(ctx); return 1; } -static int handle_ir_packet_per_buffer(struct context *context, - struct descriptor *d, - struct descriptor *last) +/* d == last because each descriptor block is only a single descriptor. */ +static int handle_ir_buffer_fill(struct context *context, + struct descriptor *d, + struct descriptor *last) { struct iso_context *ctx = container_of(context, struct iso_context, context); - struct descriptor *pd; - __le32 *ir_header; - void *p; + unsigned int req_count, res_count, completed; + u32 buffer_dma; - for (pd = d; pd <= last; pd++) { - if (pd->transfer_status) - break; + req_count = le16_to_cpu(last->req_count); + res_count = le16_to_cpu(ACCESS_ONCE(last->res_count)); + completed = req_count - res_count; + buffer_dma = le32_to_cpu(last->data_address); + + if (completed > 0) { + ctx->mc_buffer_bus = buffer_dma; + ctx->mc_completed = completed; } - if (pd > last) + + if (res_count != 0) /* Descriptor(s) not done yet, stop iteration */ return 0; - p = last + 1; - copy_iso_headers(ctx, p); + dma_sync_single_range_for_cpu(context->ohci->card.device, + buffer_dma & PAGE_MASK, + buffer_dma & ~PAGE_MASK, + completed, DMA_FROM_DEVICE); - if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { - ir_header = (__le32 *) p; - ctx->base.callback(&ctx->base, - le32_to_cpu(ir_header[0]) & 0xffff, - ctx->header_length, ctx->header, - ctx->base.callback_data); - ctx->header_length = 0; + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) { + ctx->base.callback.mc(&ctx->base, + buffer_dma + completed, + ctx->base.callback_data); + ctx->mc_completed = 0; } return 1; } +static void flush_ir_buffer_fill(struct iso_context *ctx) +{ + dma_sync_single_range_for_cpu(ctx->context.ohci->card.device, + ctx->mc_buffer_bus & PAGE_MASK, + ctx->mc_buffer_bus & ~PAGE_MASK, + ctx->mc_completed, DMA_FROM_DEVICE); + + ctx->base.callback.mc(&ctx->base, + ctx->mc_buffer_bus + ctx->mc_completed, + ctx->base.callback_data); + ctx->mc_completed = 0; +} + +static inline void sync_it_packet_for_cpu(struct context *context, + struct descriptor *pd) +{ + __le16 control; + u32 buffer_dma; + + /* only packets beginning with OUTPUT_MORE* have data buffers */ + if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) + return; + + /* skip over the OUTPUT_MORE_IMMEDIATE descriptor */ + pd += 2; + + /* + * If the packet has a header, the first OUTPUT_MORE/LAST descriptor's + * data buffer is in the context program's coherent page and must not + * be synced. + */ + if ((le32_to_cpu(pd->data_address) & PAGE_MASK) == + (context->current_bus & PAGE_MASK)) { + if (pd->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS)) + return; + pd++; + } + + do { + buffer_dma = le32_to_cpu(pd->data_address); + dma_sync_single_range_for_cpu(context->ohci->card.device, + buffer_dma & PAGE_MASK, + buffer_dma & ~PAGE_MASK, + le16_to_cpu(pd->req_count), + DMA_TO_DEVICE); + control = pd->control; + pd++; + } while (!(control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))); +} + static int handle_it_packet(struct context *context, struct descriptor *d, struct descriptor *last) { struct iso_context *ctx = container_of(context, struct iso_context, context); - int i; struct descriptor *pd; + __be32 *ctx_hdr; for (pd = d; pd <= last; pd++) if (pd->transfer_status) @@ -1923,84 +2912,133 @@ static int handle_it_packet(struct context *context, /* Descriptor(s) not done yet, stop iteration */ return 0; - i = ctx->header_length; - if (i + 4 < PAGE_SIZE) { - /* Present this value as big-endian to match the receive code */ - *(__be32 *)(ctx->header + i) = cpu_to_be32( - ((u32)le16_to_cpu(pd->transfer_status) << 16) | - le16_to_cpu(pd->res_count)); - ctx->header_length += 4; - } - if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) { - ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count), - ctx->header_length, ctx->header, - ctx->base.callback_data); - ctx->header_length = 0; + sync_it_packet_for_cpu(context, d); + + if (ctx->header_length + 4 > PAGE_SIZE) { + if (ctx->base.drop_overflow_headers) + return 1; + flush_iso_completions(ctx); } + + ctx_hdr = ctx->header + ctx->header_length; + ctx->last_timestamp = le16_to_cpu(last->res_count); + /* Present this value as big-endian to match the receive code */ + *ctx_hdr = cpu_to_be32((le16_to_cpu(pd->transfer_status) << 16) | + le16_to_cpu(pd->res_count)); + ctx->header_length += 4; + + if (last->control & cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS)) + flush_iso_completions(ctx); + return 1; } +static void set_multichannel_mask(struct fw_ohci *ohci, u64 channels) +{ + u32 hi = channels >> 32, lo = channels; + + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, ~hi); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, ~lo); + reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, hi); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, lo); + mmiowb(); + ohci->mc_channels = channels; +} + static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, int type, int channel, size_t header_size) { struct fw_ohci *ohci = fw_ohci(card); - struct iso_context *ctx, *list; - descriptor_callback_t callback; - u64 *channels, dont_care = ~0ULL; - u32 *mask, regs; - unsigned long flags; - int index, ret = -ENOMEM; + struct iso_context *uninitialized_var(ctx); + descriptor_callback_t uninitialized_var(callback); + u64 *uninitialized_var(channels); + u32 *uninitialized_var(mask), uninitialized_var(regs); + int index, ret = -EBUSY; + + spin_lock_irq(&ohci->lock); - if (type == FW_ISO_CONTEXT_TRANSMIT) { - channels = &dont_care; - mask = &ohci->it_context_mask; - list = ohci->it_context_list; + switch (type) { + case FW_ISO_CONTEXT_TRANSMIT: + mask = &ohci->it_context_mask; callback = handle_it_packet; - } else { + index = ffs(*mask) - 1; + if (index >= 0) { + *mask &= ~(1 << index); + regs = OHCI1394_IsoXmitContextBase(index); + ctx = &ohci->it_context_list[index]; + } + break; + + case FW_ISO_CONTEXT_RECEIVE: channels = &ohci->ir_context_channels; - mask = &ohci->ir_context_mask; - list = ohci->ir_context_list; - if (ohci->use_dualbuffer) - callback = handle_ir_dualbuffer_packet; - else - callback = handle_ir_packet_per_buffer; - } + mask = &ohci->ir_context_mask; + callback = handle_ir_packet_per_buffer; + index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; + if (index >= 0) { + *channels &= ~(1ULL << channel); + *mask &= ~(1 << index); + regs = OHCI1394_IsoRcvContextBase(index); + ctx = &ohci->ir_context_list[index]; + } + break; - spin_lock_irqsave(&ohci->lock, flags); - index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; - if (index >= 0) { - *channels &= ~(1ULL << channel); - *mask &= ~(1 << index); + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + mask = &ohci->ir_context_mask; + callback = handle_ir_buffer_fill; + index = !ohci->mc_allocated ? ffs(*mask) - 1 : -1; + if (index >= 0) { + ohci->mc_allocated = true; + *mask &= ~(1 << index); + regs = OHCI1394_IsoRcvContextBase(index); + ctx = &ohci->ir_context_list[index]; + } + break; + + default: + index = -1; + ret = -ENOSYS; } - spin_unlock_irqrestore(&ohci->lock, flags); - if (index < 0) - return ERR_PTR(-EBUSY); + spin_unlock_irq(&ohci->lock); - if (type == FW_ISO_CONTEXT_TRANSMIT) - regs = OHCI1394_IsoXmitContextBase(index); - else - regs = OHCI1394_IsoRcvContextBase(index); + if (index < 0) + return ERR_PTR(ret); - ctx = &list[index]; memset(ctx, 0, sizeof(*ctx)); ctx->header_length = 0; ctx->header = (void *) __get_free_page(GFP_KERNEL); - if (ctx->header == NULL) + if (ctx->header == NULL) { + ret = -ENOMEM; goto out; - + } ret = context_init(&ctx->context, ohci, regs, callback); if (ret < 0) goto out_with_header; + if (type == FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL) { + set_multichannel_mask(ohci, 0); + ctx->mc_completed = 0; + } + return &ctx->base; 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: + *channels |= 1ULL << channel; + break; + + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + ohci->mc_allocated = false; + break; + } *mask |= 1 << index; - spin_unlock_irqrestore(&ohci->lock, flags); + + spin_unlock_irq(&ohci->lock); return ERR_PTR(ret); } @@ -2010,10 +3048,15 @@ static int ohci_start_iso(struct fw_iso_context *base, { struct iso_context *ctx = container_of(base, struct iso_context, base); struct fw_ohci *ohci = ctx->context.ohci; - u32 control, match; + u32 control = IR_CONTEXT_ISOCH_HEADER, match; int index; - if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + /* the controller cannot start without any queued packets */ + if (ctx->context.last->branch_address == 0) + return -ENODATA; + + switch (ctx->base.type) { + case FW_ISO_CONTEXT_TRANSMIT: index = ctx - ohci->it_context_list; match = 0; if (cycle >= 0) @@ -2023,11 +3066,13 @@ static int ohci_start_iso(struct fw_iso_context *base, reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index); context_run(&ctx->context, match); - } else { + break; + + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + control |= IR_CONTEXT_BUFFER_FILL|IR_CONTEXT_MULTI_CHANNEL_MODE; + /* fall through */ + case FW_ISO_CONTEXT_RECEIVE: index = ctx - ohci->ir_context_list; - control = IR_CONTEXT_ISOCH_HEADER; - if (ohci->use_dualbuffer) - control |= IR_CONTEXT_DUAL_BUFFER_MODE; match = (tags << 28) | (sync << 8) | ctx->base.channel; if (cycle >= 0) { match |= (cycle & 0x07fff) << 12; @@ -2038,6 +3083,11 @@ static int ohci_start_iso(struct fw_iso_context *base, reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index); reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match); context_run(&ctx->context, control); + + ctx->sync = sync; + ctx->tags = tags; + + break; } return 0; @@ -2049,15 +3099,21 @@ static int ohci_stop_iso(struct fw_iso_context *base) struct iso_context *ctx = container_of(base, struct iso_context, base); int index; - if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + switch (ctx->base.type) { + case FW_ISO_CONTEXT_TRANSMIT: index = ctx - ohci->it_context_list; reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index); - } else { + break; + + case FW_ISO_CONTEXT_RECEIVE: + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: index = ctx - ohci->ir_context_list; reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index); + break; } flush_writes(ohci); context_stop(&ctx->context); + tasklet_kill(&ctx->context.tasklet); return 0; } @@ -2075,24 +3131,85 @@ static void ohci_free_iso_context(struct fw_iso_context *base) spin_lock_irqsave(&ohci->lock, flags); - if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) { + switch (base->type) { + case FW_ISO_CONTEXT_TRANSMIT: index = ctx - ohci->it_context_list; ohci->it_context_mask |= 1 << index; - } else { + break; + + case FW_ISO_CONTEXT_RECEIVE: index = ctx - ohci->ir_context_list; ohci->ir_context_mask |= 1 << index; ohci->ir_context_channels |= 1ULL << base->channel; + break; + + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + index = ctx - ohci->ir_context_list; + ohci->ir_context_mask |= 1 << index; + ohci->ir_context_channels |= ohci->mc_channels; + ohci->mc_channels = 0; + ohci->mc_allocated = false; + break; } spin_unlock_irqrestore(&ohci->lock, flags); } -static int ohci_queue_iso_transmit(struct fw_iso_context *base, - struct fw_iso_packet *packet, - struct fw_iso_buffer *buffer, - unsigned long payload) +static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels) +{ + struct fw_ohci *ohci = fw_ohci(base->card); + unsigned long flags; + int ret; + + switch (base->type) { + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + + spin_lock_irqsave(&ohci->lock, flags); + + /* Don't allow multichannel to grab other contexts' channels. */ + if (~ohci->ir_context_channels & ~ohci->mc_channels & *channels) { + *channels = ohci->ir_context_channels; + ret = -EBUSY; + } else { + set_multichannel_mask(ohci, *channels); + ret = 0; + } + + spin_unlock_irqrestore(&ohci->lock, flags); + + break; + default: + ret = -EINVAL; + } + + return ret; +} + +#ifdef CONFIG_PM +static void ohci_resume_iso_dma(struct fw_ohci *ohci) +{ + int i; + struct iso_context *ctx; + + for (i = 0 ; i < ohci->n_ir ; i++) { + ctx = &ohci->ir_context_list[i]; + if (ctx->context.running) + ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); + } + + for (i = 0 ; i < ohci->n_it ; i++) { + ctx = &ohci->it_context_list[i]; + if (ctx->context.running) + ohci_start_iso(&ctx->base, 0, ctx->sync, ctx->tags); + } +} +#endif + +static int queue_iso_transmit(struct iso_context *ctx, + struct fw_iso_packet *packet, + struct fw_iso_buffer *buffer, + unsigned long payload) { - struct iso_context *ctx = container_of(base, struct iso_context, base); struct descriptor *d, *last, *pd; struct fw_iso_packet *p; __le32 *header; @@ -2101,11 +3218,6 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, u32 payload_index, payload_end_index, next_page_index; int page, end_page, i, length, offset; - /* - * FIXME: Cycle lost behavior should be configurable: lose - * packet, retransmit or terminate.. - */ - p = packet; payload_index = payload; @@ -2135,6 +3247,14 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, if (!p->skip) { d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE); d[0].req_count = cpu_to_le16(8); + /* + * Link the skip address to this descriptor itself. This causes + * a context to skip a cycle whenever lost cycles or FIFO + * overruns occur, without dropping the data. The application + * should then decide whether this is an error condition or not. + * FIXME: Make the context's cycle-lost behaviour configurable? + */ + d[0].branch_address = cpu_to_le32(d_bus | z); header = (__le32 *) &d[1]; header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) | @@ -2166,6 +3286,10 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, page_bus = page_private(buffer->pages[page]); pd[i].data_address = cpu_to_le32(page_bus + offset); + dma_sync_single_range_for_device(ctx->context.ohci->card.device, + page_bus, offset, length, + DMA_TO_DEVICE); + payload_index += length; } @@ -2185,100 +3309,13 @@ static int ohci_queue_iso_transmit(struct fw_iso_context *base, return 0; } -static int ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, - struct fw_iso_packet *packet, - struct fw_iso_buffer *buffer, - unsigned long payload) +static int queue_iso_packet_per_buffer(struct iso_context *ctx, + struct fw_iso_packet *packet, + struct fw_iso_buffer *buffer, + unsigned long payload) { - struct iso_context *ctx = container_of(base, struct iso_context, base); - struct db_descriptor *db = NULL; - struct descriptor *d; - struct fw_iso_packet *p; - dma_addr_t d_bus, page_bus; - u32 z, header_z, length, rest; - int page, offset, packet_count, header_size; - - /* - * FIXME: Cycle lost behavior should be configurable: lose - * packet, retransmit or terminate.. - */ - - p = packet; - z = 2; - - /* - * The OHCI controller puts the isochronous header and trailer in the - * buffer, so we need at least 8 bytes. - */ - packet_count = p->header_length / ctx->base.header_size; - header_size = packet_count * max(ctx->base.header_size, (size_t)8); - - /* Get header size in number of descriptors. */ - header_z = DIV_ROUND_UP(header_size, sizeof(*d)); - page = payload >> PAGE_SHIFT; - offset = payload & ~PAGE_MASK; - rest = p->payload_length; - /* - * The controllers I've tested have not worked correctly when - * second_req_count is zero. Rather than do something we know won't - * work, return an error - */ - if (rest == 0) - return -EINVAL; - - while (rest > 0) { - d = context_get_descriptors(&ctx->context, - z + header_z, &d_bus); - if (d == NULL) - return -ENOMEM; - - db = (struct db_descriptor *) d; - db->control = cpu_to_le16(DESCRIPTOR_STATUS | - DESCRIPTOR_BRANCH_ALWAYS); - db->first_size = - cpu_to_le16(max(ctx->base.header_size, (size_t)8)); - if (p->skip && rest == p->payload_length) { - db->control |= cpu_to_le16(DESCRIPTOR_WAIT); - db->first_req_count = db->first_size; - } else { - db->first_req_count = cpu_to_le16(header_size); - } - db->first_res_count = db->first_req_count; - db->first_buffer = cpu_to_le32(d_bus + sizeof(*db)); - - if (p->skip && rest == p->payload_length) - length = 4; - else if (offset + rest < PAGE_SIZE) - length = rest; - else - length = PAGE_SIZE - offset; - - db->second_req_count = cpu_to_le16(length); - db->second_res_count = db->second_req_count; - page_bus = page_private(buffer->pages[page]); - db->second_buffer = cpu_to_le32(page_bus + offset); - - if (p->interrupt && length == rest) - db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); - - context_append(&ctx->context, d, z, header_z); - offset = (offset + length) & ~PAGE_MASK; - rest -= length; - if (offset == 0) - page++; - } - - return 0; -} - -static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, - struct fw_iso_packet *packet, - struct fw_iso_buffer *buffer, - unsigned long payload) -{ - struct iso_context *ctx = container_of(base, struct iso_context, base); + struct device *device = ctx->context.ohci->card.device; struct descriptor *d, *pd; - struct fw_iso_packet *p = packet; dma_addr_t d_bus, page_bus; u32 z, header_z, rest; int i, j, length; @@ -2288,14 +3325,14 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, * The OHCI controller puts the isochronous header and trailer in the * buffer, so we need at least 8 bytes. */ - packet_count = p->header_length / ctx->base.header_size; + packet_count = packet->header_length / ctx->base.header_size; header_size = max(ctx->base.header_size, (size_t)8); /* Get header size in number of descriptors. */ header_z = DIV_ROUND_UP(header_size, sizeof(*d)); page = payload >> PAGE_SHIFT; offset = payload & ~PAGE_MASK; - payload_per_buffer = p->payload_length / packet_count; + payload_per_buffer = packet->payload_length / packet_count; for (i = 0; i < packet_count; i++) { /* d points to the header descriptor */ @@ -2307,7 +3344,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, d->control = cpu_to_le16(DESCRIPTOR_STATUS | DESCRIPTOR_INPUT_MORE); - if (p->skip && i == 0) + if (packet->skip && i == 0) d->control |= cpu_to_le16(DESCRIPTOR_WAIT); d->req_count = cpu_to_le16(header_size); d->res_count = d->req_count; @@ -2332,6 +3369,10 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, page_bus = page_private(buffer->pages[page]); pd->data_address = cpu_to_le32(page_bus + offset); + dma_sync_single_range_for_device(device, page_bus, + offset, length, + DMA_FROM_DEVICE); + offset = (offset + length) & ~PAGE_MASK; rest -= length; if (offset == 0) @@ -2340,7 +3381,7 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, pd->control = cpu_to_le16(DESCRIPTOR_STATUS | DESCRIPTOR_INPUT_LAST | DESCRIPTOR_BRANCH_ALWAYS); - if (p->interrupt && i == packet_count - 1) + if (packet->interrupt && i == packet_count - 1) pd->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); context_append(&ctx->context, d, z, header_z); @@ -2349,6 +3390,62 @@ static int ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base, return 0; } +static int queue_iso_buffer_fill(struct iso_context *ctx, + struct fw_iso_packet *packet, + struct fw_iso_buffer *buffer, + unsigned long payload) +{ + struct descriptor *d; + dma_addr_t d_bus, page_bus; + int page, offset, rest, z, i, length; + + page = payload >> PAGE_SHIFT; + offset = payload & ~PAGE_MASK; + rest = packet->payload_length; + + /* We need one descriptor for each page in the buffer. */ + z = DIV_ROUND_UP(offset + rest, PAGE_SIZE); + + if (WARN_ON(offset & 3 || rest & 3 || page + z > buffer->page_count)) + return -EFAULT; + + for (i = 0; i < z; i++) { + d = context_get_descriptors(&ctx->context, 1, &d_bus); + if (d == NULL) + return -ENOMEM; + + d->control = cpu_to_le16(DESCRIPTOR_INPUT_MORE | + DESCRIPTOR_BRANCH_ALWAYS); + if (packet->skip && i == 0) + d->control |= cpu_to_le16(DESCRIPTOR_WAIT); + if (packet->interrupt && i == z - 1) + d->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS); + + if (offset + rest < PAGE_SIZE) + length = rest; + else + length = PAGE_SIZE - offset; + d->req_count = cpu_to_le16(length); + d->res_count = d->req_count; + d->transfer_status = 0; + + page_bus = page_private(buffer->pages[page]); + d->data_address = cpu_to_le32(page_bus + offset); + + dma_sync_single_range_for_device(ctx->context.ohci->card.device, + page_bus, offset, length, + DMA_FROM_DEVICE); + + rest -= length; + offset = 0; + page++; + + context_append(&ctx->context, d, 1, 0); + } + + return 0; +} + static int ohci_queue_iso(struct fw_iso_context *base, struct fw_iso_packet *packet, struct fw_iso_buffer *buffer, @@ -2356,41 +3453,90 @@ static int ohci_queue_iso(struct fw_iso_context *base, { struct iso_context *ctx = container_of(base, struct iso_context, base); unsigned long flags; - int ret; + int ret = -ENOSYS; spin_lock_irqsave(&ctx->context.ohci->lock, flags); - if (base->type == FW_ISO_CONTEXT_TRANSMIT) - ret = ohci_queue_iso_transmit(base, packet, buffer, payload); - else if (ctx->context.ohci->use_dualbuffer) - ret = ohci_queue_iso_receive_dualbuffer(base, packet, - buffer, payload); - else - ret = ohci_queue_iso_receive_packet_per_buffer(base, packet, - buffer, payload); + switch (base->type) { + case FW_ISO_CONTEXT_TRANSMIT: + ret = queue_iso_transmit(ctx, packet, buffer, payload); + break; + case FW_ISO_CONTEXT_RECEIVE: + ret = queue_iso_packet_per_buffer(ctx, packet, buffer, payload); + break; + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + ret = queue_iso_buffer_fill(ctx, packet, buffer, payload); + break; + } spin_unlock_irqrestore(&ctx->context.ohci->lock, flags); return ret; } +static void ohci_flush_queue_iso(struct fw_iso_context *base) +{ + struct context *ctx = + &container_of(base, struct iso_context, base)->context; + + reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); +} + +static int ohci_flush_iso_completions(struct fw_iso_context *base) +{ + struct iso_context *ctx = container_of(base, struct iso_context, base); + int ret = 0; + + tasklet_disable(&ctx->context.tasklet); + + if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) { + context_tasklet((unsigned long)&ctx->context); + + switch (base->type) { + case FW_ISO_CONTEXT_TRANSMIT: + case FW_ISO_CONTEXT_RECEIVE: + if (ctx->header_length != 0) + flush_iso_completions(ctx); + break; + case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: + if (ctx->mc_completed != 0) + flush_ir_buffer_fill(ctx); + break; + default: + ret = -ENOSYS; + } + + clear_bit_unlock(0, &ctx->flushing_completions); + smp_mb__after_atomic(); + } + + tasklet_enable(&ctx->context.tasklet); + + return ret; +} + static const struct fw_card_driver ohci_driver = { .enable = ohci_enable, + .read_phy_reg = ohci_read_phy_reg, .update_phy_reg = ohci_update_phy_reg, .set_config_rom = ohci_set_config_rom, .send_request = ohci_send_request, .send_response = ohci_send_response, .cancel_packet = ohci_cancel_packet, .enable_phys_dma = ohci_enable_phys_dma, - .get_bus_time = ohci_get_bus_time, + .read_csr = ohci_read_csr, + .write_csr = ohci_write_csr, .allocate_iso_context = ohci_allocate_iso_context, .free_iso_context = ohci_free_iso_context, + .set_iso_channels = ohci_set_iso_channels, .queue_iso = ohci_queue_iso, + .flush_queue_iso = ohci_flush_queue_iso, + .flush_iso_completions = ohci_flush_iso_completions, .start_iso = ohci_start_iso, .stop_iso = ohci_stop_iso, }; #ifdef CONFIG_PPC_PMAC -static void ohci_pmac_on(struct pci_dev *dev) +static void pmac_ohci_on(struct pci_dev *dev) { if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(dev); @@ -2402,7 +3548,7 @@ static void ohci_pmac_on(struct pci_dev *dev) } } -static void ohci_pmac_off(struct pci_dev *dev) +static void pmac_ohci_off(struct pci_dev *dev) { if (machine_is(powermac)) { struct device_node *ofn = pci_device_to_OF_node(dev); @@ -2414,22 +3560,24 @@ static void ohci_pmac_off(struct pci_dev *dev) } } #else -#define ohci_pmac_on(dev) -#define ohci_pmac_off(dev) +static inline void pmac_ohci_on(struct pci_dev *dev) {} +static inline void pmac_ohci_off(struct pci_dev *dev) {} #endif /* CONFIG_PPC_PMAC */ -#define PCI_VENDOR_ID_AGERE PCI_VENDOR_ID_ATT -#define PCI_DEVICE_ID_AGERE_FW643 0x5901 - -static int __devinit pci_probe(struct pci_dev *dev, +static int pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { struct fw_ohci *ohci; u32 bus_options, max_receive, link_speed, version; u64 guid; - int err; + int i, err; size_t size; + if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) { + dev_err(&dev->dev, "Pinnacle MovieBoard is not yet supported\n"); + return -ENOSYS; + } + ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); if (ohci == NULL) { err = -ENOMEM; @@ -2438,11 +3586,11 @@ static int __devinit pci_probe(struct pci_dev *dev, fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev); - ohci_pmac_on(dev); + pmac_ohci_on(dev); err = pci_enable_device(dev); if (err) { - fw_error("Failed to enable OHCI hardware\n"); + dev_err(&dev->dev, "failed to enable OHCI hardware\n"); goto fail_free; } @@ -2451,92 +3599,102 @@ static int __devinit pci_probe(struct pci_dev *dev, pci_set_drvdata(dev, ohci); spin_lock_init(&ohci->lock); + mutex_init(&ohci->phy_reg_mutex); + + INIT_WORK(&ohci->bus_reset_work, bus_reset_work); - tasklet_init(&ohci->bus_reset_tasklet, - bus_reset_tasklet, (unsigned long)ohci); + if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) || + pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) { + ohci_err(ohci, "invalid MMIO resource\n"); + err = -ENXIO; + goto fail_disable; + } err = pci_request_region(dev, 0, ohci_driver_name); if (err) { - fw_error("MMIO resource unavailable\n"); + ohci_err(ohci, "MMIO resource unavailable\n"); goto fail_disable; } ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE); if (ohci->registers == NULL) { - fw_error("Failed to remap registers\n"); + ohci_err(ohci, "failed to remap registers\n"); err = -ENXIO; goto fail_iomem; } - version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; -#if 0 - /* FIXME: make it a context option or remove dual-buffer mode */ - ohci->use_dualbuffer = version >= OHCI_VERSION_1_1; -#endif - - /* dual-buffer mode is broken if more than one IR context is active */ - if (dev->vendor == PCI_VENDOR_ID_AGERE && - dev->device == PCI_DEVICE_ID_AGERE_FW643) - ohci->use_dualbuffer = false; - - /* dual-buffer mode is broken */ - if (dev->vendor == PCI_VENDOR_ID_RICOH && - dev->device == PCI_DEVICE_ID_RICOH_R5C832) - ohci->use_dualbuffer = false; - -/* x86-32 currently doesn't use highmem for dma_alloc_coherent */ -#if !defined(CONFIG_X86_32) - /* dual-buffer mode is broken with descriptor addresses above 2G */ - if (dev->vendor == PCI_VENDOR_ID_TI && - dev->device == PCI_DEVICE_ID_TI_TSB43AB22) - ohci->use_dualbuffer = false; -#endif + for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) + if ((ohci_quirks[i].vendor == dev->vendor) && + (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID || + ohci_quirks[i].device == dev->device) && + (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID || + ohci_quirks[i].revision >= dev->revision)) { + ohci->quirks = ohci_quirks[i].flags; + break; + } + if (param_quirks) + ohci->quirks = param_quirks; -#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) - ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE && - dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW; -#endif - ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI; + /* + * Because dma_alloc_coherent() allocates at least one page, + * we save space by using a common buffer for the AR request/ + * response descriptors and the self IDs buffer. + */ + BUILD_BUG_ON(AR_BUFFERS * sizeof(struct descriptor) > PAGE_SIZE/4); + BUILD_BUG_ON(SELF_ID_BUF_SIZE > PAGE_SIZE/2); + ohci->misc_buffer = dma_alloc_coherent(ohci->card.device, + PAGE_SIZE, + &ohci->misc_buffer_bus, + GFP_KERNEL); + if (!ohci->misc_buffer) { + err = -ENOMEM; + goto fail_iounmap; + } - ar_context_init(&ohci->ar_request_ctx, ohci, - OHCI1394_AsReqRcvContextControlSet); + err = ar_context_init(&ohci->ar_request_ctx, ohci, 0, + OHCI1394_AsReqRcvContextControlSet); + if (err < 0) + goto fail_misc_buf; - ar_context_init(&ohci->ar_response_ctx, ohci, - OHCI1394_AsRspRcvContextControlSet); + err = ar_context_init(&ohci->ar_response_ctx, ohci, PAGE_SIZE/4, + OHCI1394_AsRspRcvContextControlSet); + if (err < 0) + goto fail_arreq_ctx; - context_init(&ohci->at_request_ctx, ohci, - OHCI1394_AsReqTrContextControlSet, handle_at_packet); + err = context_init(&ohci->at_request_ctx, ohci, + OHCI1394_AsReqTrContextControlSet, handle_at_packet); + if (err < 0) + goto fail_arrsp_ctx; - context_init(&ohci->at_response_ctx, ohci, - OHCI1394_AsRspTrContextControlSet, handle_at_packet); + err = context_init(&ohci->at_response_ctx, ohci, + OHCI1394_AsRspTrContextControlSet, handle_at_packet); + if (err < 0) + goto fail_atreq_ctx; reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); - ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); + ohci->ir_context_channels = ~0ULL; + ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); - size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask); - ohci->it_context_list = kzalloc(size, GFP_KERNEL); + ohci->ir_context_mask = ohci->ir_context_support; + ohci->n_ir = hweight32(ohci->ir_context_mask); + size = sizeof(struct iso_context) * ohci->n_ir; + ohci->ir_context_list = kzalloc(size, GFP_KERNEL); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); - ohci->ir_context_channels = ~0ULL; - ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); + ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); - size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask); - ohci->ir_context_list = kzalloc(size, GFP_KERNEL); + ohci->it_context_mask = ohci->it_context_support; + ohci->n_it = hweight32(ohci->it_context_mask); + size = sizeof(struct iso_context) * ohci->n_it; + ohci->it_context_list = kzalloc(size, GFP_KERNEL); if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) { err = -ENOMEM; goto fail_contexts; } - /* self-id dma buffer allocation */ - ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device, - SELF_ID_BUF_SIZE, - &ohci->self_id_bus, - GFP_KERNEL); - if (ohci->self_id_cpu == NULL) { - err = -ENOMEM; - goto fail_contexts; - } + ohci->self_id = ohci->misc_buffer + PAGE_SIZE/2; + ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2; bus_options = reg_read(ohci, OHCI1394_BusOptions); max_receive = (bus_options >> 12) & 0xf; @@ -2544,47 +3702,74 @@ static int __devinit pci_probe(struct pci_dev *dev, guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) | reg_read(ohci, OHCI1394_GUIDLo); + if (!(ohci->quirks & QUIRK_NO_MSI)) + pci_enable_msi(dev); + if (request_irq(dev->irq, irq_handler, + pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, + ohci_driver_name, ohci)) { + ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq); + err = -EIO; + goto fail_msi; + } + err = fw_card_add(&ohci->card, max_receive, link_speed, guid); if (err) - goto fail_self_id; + goto fail_irq; - fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n", - dev_name(&dev->dev), version >> 16, version & 0xff); + version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; + ohci_notice(ohci, + "added OHCI v%x.%x device as card %d, " + "%d IR + %d IT contexts, quirks 0x%x%s\n", + version >> 16, version & 0xff, ohci->card.index, + ohci->n_ir, ohci->n_it, ohci->quirks, + reg_read(ohci, OHCI1394_PhyUpperBound) ? + ", physUB" : ""); return 0; - fail_self_id: - dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, - ohci->self_id_cpu, ohci->self_id_bus); + fail_irq: + free_irq(dev->irq, ohci); + fail_msi: + pci_disable_msi(dev); fail_contexts: kfree(ohci->ir_context_list); kfree(ohci->it_context_list); context_release(&ohci->at_response_ctx); + fail_atreq_ctx: context_release(&ohci->at_request_ctx); + fail_arrsp_ctx: ar_context_release(&ohci->ar_response_ctx); + fail_arreq_ctx: ar_context_release(&ohci->ar_request_ctx); + fail_misc_buf: + dma_free_coherent(ohci->card.device, PAGE_SIZE, + ohci->misc_buffer, ohci->misc_buffer_bus); + fail_iounmap: pci_iounmap(dev, ohci->registers); fail_iomem: pci_release_region(dev, 0); fail_disable: pci_disable_device(dev); fail_free: - kfree(&ohci->card); - ohci_pmac_off(dev); + kfree(ohci); + pmac_ohci_off(dev); fail: - if (err == -ENOMEM) - fw_error("Out of memory\n"); - return err; } static void pci_remove(struct pci_dev *dev) { - struct fw_ohci *ohci; + struct fw_ohci *ohci = pci_get_drvdata(dev); - ohci = pci_get_drvdata(dev); - reg_write(ohci, OHCI1394_IntMaskClear, ~0); - flush_writes(ohci); + /* + * If the removal is happening from the suspend state, LPS won't be + * enabled and host registers (eg., IntMaskClear) won't be accessible. + */ + if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) { + reg_write(ohci, OHCI1394_IntMaskClear, ~0); + flush_writes(ohci); + } + cancel_work_sync(&ohci->bus_reset_work); fw_core_remove_card(&ohci->card); /* @@ -2601,21 +3786,22 @@ static void pci_remove(struct pci_dev *dev) if (ohci->config_rom) dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, ohci->config_rom, ohci->config_rom_bus); - dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE, - ohci->self_id_cpu, ohci->self_id_bus); ar_context_release(&ohci->ar_request_ctx); ar_context_release(&ohci->ar_response_ctx); + dma_free_coherent(ohci->card.device, PAGE_SIZE, + ohci->misc_buffer, ohci->misc_buffer_bus); context_release(&ohci->at_request_ctx); context_release(&ohci->at_response_ctx); kfree(ohci->it_context_list); kfree(ohci->ir_context_list); + pci_disable_msi(dev); pci_iounmap(dev, ohci->registers); pci_release_region(dev, 0); pci_disable_device(dev); - kfree(&ohci->card); - ohci_pmac_off(dev); + kfree(ohci); + pmac_ohci_off(dev); - fw_notify("Removed fw-ohci device.\n"); + dev_notice(&dev->dev, "removed fw-ohci device\n"); } #ifdef CONFIG_PM @@ -2625,16 +3811,15 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state) int err; software_reset(ohci); - free_irq(dev->irq, ohci); err = pci_save_state(dev); if (err) { - fw_error("pci_save_state failed\n"); + ohci_err(ohci, "pci_save_state failed\n"); return err; } err = pci_set_power_state(dev, pci_choose_state(dev, state)); if (err) - fw_error("pci_set_power_state failed with %d\n", err); - ohci_pmac_off(dev); + ohci_err(ohci, "pci_set_power_state failed with %d\n", err); + pmac_ohci_off(dev); return 0; } @@ -2644,20 +3829,33 @@ static int pci_resume(struct pci_dev *dev) struct fw_ohci *ohci = pci_get_drvdata(dev); int err; - ohci_pmac_on(dev); + pmac_ohci_on(dev); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); err = pci_enable_device(dev); if (err) { - fw_error("pci_enable_device failed\n"); + ohci_err(ohci, "pci_enable_device failed\n"); return err; } - return ohci_enable(&ohci->card, NULL, 0); + /* Some systems don't setup GUID register on resume from ram */ + if (!reg_read(ohci, OHCI1394_GUIDLo) && + !reg_read(ohci, OHCI1394_GUIDHi)) { + reg_write(ohci, OHCI1394_GUIDLo, (u32)ohci->card.guid); + reg_write(ohci, OHCI1394_GUIDHi, (u32)(ohci->card.guid >> 32)); + } + + err = ohci_enable(&ohci->card, NULL, 0); + if (err) + return err; + + ohci_resume_iso_dma(ohci); + + return 0; } #endif -static struct pci_device_id pci_table[] = { +static const struct pci_device_id pci_table[] = { { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) }, { } }; @@ -2675,24 +3873,27 @@ static struct pci_driver fw_ohci_pci_driver = { #endif }; -MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); -MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers"); -MODULE_LICENSE("GPL"); - -/* Provide a module alias so root-on-sbp2 initrds don't break. */ -#ifndef CONFIG_IEEE1394_OHCI1394_MODULE -MODULE_ALIAS("ohci1394"); -#endif - static int __init fw_ohci_init(void) { + selfid_workqueue = alloc_workqueue(KBUILD_MODNAME, WQ_MEM_RECLAIM, 0); + if (!selfid_workqueue) + return -ENOMEM; + return pci_register_driver(&fw_ohci_pci_driver); } static void __exit fw_ohci_cleanup(void) { pci_unregister_driver(&fw_ohci_pci_driver); + destroy_workqueue(selfid_workqueue); } module_init(fw_ohci_init); module_exit(fw_ohci_cleanup); + +MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); +MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers"); +MODULE_LICENSE("GPL"); + +/* Provide a module alias so root-on-sbp2 initrds don't break. */ +MODULE_ALIAS("ohci1394"); diff --git a/drivers/firewire/ohci.h b/drivers/firewire/ohci.h index ba492d85c51..ef5e7336da6 100644 --- a/drivers/firewire/ohci.h +++ b/drivers/firewire/ohci.h @@ -60,6 +60,7 @@ #define OHCI1394_LinkControl_cycleSource (1 << 22) #define OHCI1394_NodeID 0x0E8 #define OHCI1394_NodeID_idValid 0x80000000 +#define OHCI1394_NodeID_root 0x40000000 #define OHCI1394_NodeID_nodeNumber 0x0000003f #define OHCI1394_NodeID_busNumber 0x0000ffc0 #define OHCI1394_PhyControl 0x0EC @@ -67,7 +68,7 @@ #define OHCI1394_PhyControl_ReadDone 0x80000000 #define OHCI1394_PhyControl_ReadData(r) (((r) & 0x00ff0000) >> 16) #define OHCI1394_PhyControl_Write(addr, data) (((addr) << 8) | (data) | 0x00004000) -#define OHCI1394_PhyControl_WriteDone 0x00004000 +#define OHCI1394_PhyControl_WritePending 0x00004000 #define OHCI1394_IsochronousCycleTimer 0x0F0 #define OHCI1394_AsReqFilterHiSet 0x100 #define OHCI1394_AsReqFilterHiClear 0x104 diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index d485cdd8cba..7aef911fdc7 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -52,7 +52,6 @@ #include <linux/workqueue.h> #include <asm/byteorder.h> -#include <asm/system.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -66,7 +65,7 @@ * * Concurrent logins are useful together with cluster filesystems. */ -static int sbp2_param_exclusive_login = 1; +static bool sbp2_param_exclusive_login = 1; module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644); MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " "(default = Y, use N for concurrent initiators)"); @@ -125,11 +124,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) ", or a combination)"); -/* I don't know why the SCSI stack doesn't define something like this... */ -typedef void (*scsi_done_fn_t)(struct scsi_cmnd *); - -static const char sbp2_driver_name[] = "sbp2"; - /* * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry * and one struct scsi_device per sbp2_logical_unit. @@ -152,19 +146,23 @@ struct sbp2_logical_unit { */ int generation; int retries; + work_func_t workfn; struct delayed_work work; bool has_sdev; bool blocked; }; +static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) +{ + queue_delayed_work(fw_workqueue, &lu->work, delay); +} + /* * We create one struct sbp2_target per IEEE 1212 Unit Directory * and one struct Scsi_Host per sbp2_target. */ struct sbp2_target { - struct kref kref; struct fw_unit *unit; - const char *bus_id; struct list_head lu_list; u64 management_agent_address; @@ -180,11 +178,21 @@ struct sbp2_target { int blocked; /* ditto */ }; -static struct fw_device *target_device(struct sbp2_target *tgt) +static struct fw_device *target_parent_device(struct sbp2_target *tgt) { return fw_parent_device(tgt->unit); } +static const struct device *tgt_dev(const struct sbp2_target *tgt) +{ + return &tgt->unit->device; +} + +static const struct device *lu_dev(const struct sbp2_logical_unit *lu) +{ + return &lu->tgt->unit->device; +} + /* Impossible login_id, to detect logout attempt before successful login */ #define INVALID_LOGIN_ID 0x10000 @@ -200,9 +208,8 @@ static struct fw_device *target_device(struct sbp2_target *tgt) #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 @@ -210,6 +217,7 @@ static struct fw_device *target_device(struct sbp2_target *tgt) #define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a #define SBP2_CSR_FIRMWARE_REVISION 0x3c #define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 +#define SBP2_CSR_UNIT_UNIQUE_ID 0x8d #define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 /* Management orb opcodes */ @@ -261,7 +269,6 @@ struct sbp2_orb { struct kref kref; dma_addr_t request_bus; int rcode; - struct sbp2_pointer pointer; void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); struct list_head link; }; @@ -314,7 +321,6 @@ struct sbp2_command_orb { u8 command_block[SBP2_MAX_CDB_SIZE]; } request; struct scsi_cmnd *cmd; - scsi_done_fn_t done; struct sbp2_logical_unit *lu; struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); @@ -410,8 +416,7 @@ static void free_orb(struct kref *kref) static void sbp2_status_write(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, - int generation, int speed, - unsigned long long offset, + int generation, unsigned long long offset, void *payload, size_t length, void *callback_data) { struct sbp2_logical_unit *lu = callback_data; @@ -432,7 +437,8 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, memcpy(status.data, payload + 8, length - 8); if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) { - fw_notify("non-orb related status write, not handled\n"); + dev_notice(lu_dev(lu), + "non-ORB related status write, not handled\n"); fw_send_response(card, request, RCODE_COMPLETE); return; } @@ -451,9 +457,9 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, if (&orb->link != &lu->orb_list) { orb->callback(orb, &status); - kref_put(&orb->kref, free_orb); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } else { - fw_error("status write for unknown orb\n"); + dev_err(lu_dev(lu), "status write for unknown ORB\n"); } fw_send_response(card, request, RCODE_COMPLETE); @@ -481,40 +487,41 @@ static void complete_transaction(struct fw_card *card, int rcode, if (orb->rcode != RCODE_COMPLETE) { list_del(&orb->link); spin_unlock_irqrestore(&card->lock, flags); + orb->callback(orb, NULL); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } else { spin_unlock_irqrestore(&card->lock, flags); } - kref_put(&orb->kref, free_orb); + kref_put(&orb->kref, free_orb); /* transaction callback reference */ } static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, int node_id, int generation, u64 offset) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); + struct sbp2_pointer orb_pointer; unsigned long flags; - orb->pointer.high = 0; - orb->pointer.low = cpu_to_be32(orb->request_bus); + orb_pointer.high = 0; + orb_pointer.low = cpu_to_be32(orb->request_bus); spin_lock_irqsave(&device->card->lock, flags); list_add_tail(&orb->link, &lu->orb_list); spin_unlock_irqrestore(&device->card->lock, flags); - /* Take a ref for the orb list and for the transaction callback. */ - kref_get(&orb->kref); - kref_get(&orb->kref); + kref_get(&orb->kref); /* transaction callback reference */ + kref_get(&orb->kref); /* orb callback reference */ fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, node_id, generation, device->max_speed, offset, - &orb->pointer, sizeof(orb->pointer), - complete_transaction, orb); + &orb_pointer, 8, complete_transaction, orb); } static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); struct sbp2_orb *orb, *next; struct list_head list; unsigned long flags; @@ -532,6 +539,7 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) orb->rcode = RCODE_CANCELLED; orb->callback(orb, NULL); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } return retval; @@ -552,7 +560,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, int generation, int function, int lun_or_login_id, void *response) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); struct sbp2_management_orb *orb; unsigned int timeout; int retval = -ENOMEM; @@ -560,7 +568,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device)) return 0; - orb = kzalloc(sizeof(*orb), GFP_ATOMIC); + orb = kzalloc(sizeof(*orb), GFP_NOIO); if (orb == NULL) return -ENOMEM; @@ -612,20 +620,20 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, retval = -EIO; if (sbp2_cancel_orbs(lu) == 0) { - fw_error("%s: orb reply timed out, rcode=0x%02x\n", - lu->tgt->bus_id, orb->base.rcode); + dev_err(lu_dev(lu), "ORB reply timed out, rcode 0x%02x\n", + orb->base.rcode); goto out; } if (orb->base.rcode != RCODE_COMPLETE) { - fw_error("%s: management write failed, rcode 0x%02x\n", - lu->tgt->bus_id, orb->base.rcode); + dev_err(lu_dev(lu), "management write failed, rcode 0x%02x\n", + orb->base.rcode); goto out; } if (STATUS_GET_RESPONSE(orb->status) != 0 || STATUS_GET_SBP_STATUS(orb->status) != 0) { - fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id, + dev_err(lu_dev(lu), "error status: %d:%d\n", STATUS_GET_RESPONSE(orb->status), STATUS_GET_SBP_STATUS(orb->status)); goto out; @@ -648,13 +656,13 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, static void sbp2_agent_reset(struct sbp2_logical_unit *lu) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); __be32 d = 0; fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, lu->command_block_agent_address + SBP2_AGENT_RESET, - &d, sizeof(d)); + &d, 4); } static void complete_agent_reset_write_no_wait(struct fw_card *card, @@ -665,7 +673,7 @@ static void complete_agent_reset_write_no_wait(struct fw_card *card, static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); struct fw_transaction *t; static __be32 d; @@ -676,7 +684,7 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, lu->command_block_agent_address + SBP2_AGENT_RESET, - &d, sizeof(d), complete_agent_reset_write_no_wait, t); + &d, 4, complete_agent_reset_write_no_wait, t); } static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) @@ -704,7 +712,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu) static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) { struct sbp2_target *tgt = lu->tgt; - struct fw_card *card = target_device(tgt)->card; + struct fw_card *card = target_parent_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -728,7 +736,7 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu) static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) { struct sbp2_target *tgt = lu->tgt; - struct fw_card *card = target_device(tgt)->card; + struct fw_card *card = target_parent_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -753,7 +761,7 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) */ static void sbp2_unblock(struct sbp2_target *tgt) { - struct fw_card *card = target_device(tgt)->card; + struct fw_card *card = target_parent_device(tgt)->card; struct Scsi_Host *shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); unsigned long flags; @@ -776,73 +784,6 @@ static int sbp2_lun2int(u16 lun) return scsilun_to_int(&eight_bytes_lun); } -static void sbp2_release_target(struct kref *kref) -{ - struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref); - struct sbp2_logical_unit *lu, *next; - struct Scsi_Host *shost = - container_of((void *)tgt, struct Scsi_Host, hostdata[0]); - struct scsi_device *sdev; - struct fw_device *device = target_device(tgt); - - /* prevent deadlocks */ - sbp2_unblock(tgt); - - list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { - sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } - if (lu->login_id != INVALID_LOGIN_ID) { - int generation, node_id; - /* - * tgt->node_id may be obsolete here if we failed - * during initial login or after a bus reset where - * the topology changed. - */ - generation = device->generation; - smp_rmb(); /* node_id vs. generation */ - node_id = device->node_id; - sbp2_send_management_orb(lu, node_id, generation, - SBP2_LOGOUT_REQUEST, - lu->login_id, NULL); - } - fw_core_remove_address_handler(&lu->address_handler); - list_del(&lu->link); - kfree(lu); - } - scsi_remove_host(shost); - fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); - - fw_unit_put(tgt->unit); - scsi_host_put(shost); - fw_device_put(device); -} - -static void sbp2_target_get(struct sbp2_target *tgt) -{ - kref_get(&tgt->kref); -} - -static void sbp2_target_put(struct sbp2_target *tgt) -{ - kref_put(&tgt->kref, sbp2_release_target); -} - -static struct workqueue_struct *sbp2_wq; - -/* - * Always get the target's kref when scheduling work on one its units. - * Each workqueue job is responsible to call sbp2_target_put() upon return. - */ -static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) -{ - sbp2_target_get(lu->tgt); - if (!queue_delayed_work(sbp2_wq, &lu->work, delay)) - sbp2_target_put(lu->tgt); -} - /* * Write retransmit retry values into the BUSY_TIMEOUT register. * - The single-phase retry protocol is supported by all SBP-2 devices, but the @@ -861,13 +802,12 @@ static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) */ static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) { - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); __be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT); fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, lu->tgt->node_id, lu->generation, device->max_speed, - CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, - &d, sizeof(d)); + CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &d, 4); } static void sbp2_reconnect(struct work_struct *work); @@ -877,14 +817,14 @@ static void sbp2_login(struct work_struct *work) struct sbp2_logical_unit *lu = container_of(work, struct sbp2_logical_unit, work.work); struct sbp2_target *tgt = lu->tgt; - struct fw_device *device = target_device(tgt); + struct fw_device *device = target_parent_device(tgt); struct Scsi_Host *shost; struct scsi_device *sdev; struct sbp2_login_response response; int generation, node_id, local_node_id; if (fw_device_is_shutdown(device)) - goto out; + return; generation = device->generation; smp_rmb(); /* node IDs must not be older than generation */ @@ -901,12 +841,12 @@ static void sbp2_login(struct work_struct *work) if (lu->retries++ < 5) { sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); } else { - fw_error("%s: failed to login to LUN %04x\n", - tgt->bus_id, lu->lun); + dev_err(tgt_dev(tgt), "failed to login to LUN %04x\n", + lu->lun); /* Let any waiting I/O fail from now on. */ sbp2_unblock(lu->tgt); } - goto out; + return; } tgt->node_id = node_id; @@ -919,20 +859,21 @@ static void sbp2_login(struct work_struct *work) << 32) | be32_to_cpu(response.command_block_agent.low); lu->login_id = be32_to_cpu(response.misc) & 0xffff; - fw_notify("%s: logged in to LUN %04x (%d retries)\n", - tgt->bus_id, lu->lun, lu->retries); + dev_notice(tgt_dev(tgt), "logged in to LUN %04x (%d retries)\n", + lu->lun, lu->retries); /* set appropriate retry limit(s) in BUSY_TIMEOUT register */ sbp2_set_busy_timeout(lu); - PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect); + lu->workfn = sbp2_reconnect; sbp2_agent_reset(lu); /* This was a re-login. */ if (lu->has_sdev) { sbp2_cancel_orbs(lu); sbp2_conditionally_unblock(lu); - goto out; + + return; } if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) @@ -964,7 +905,8 @@ static void sbp2_login(struct work_struct *work) lu->has_sdev = true; scsi_device_put(sdev); sbp2_allow_block(lu); - goto out; + + return; out_logout_login: smp_rmb(); /* generation may have changed */ @@ -977,9 +919,65 @@ static void sbp2_login(struct work_struct *work) * If a bus reset happened, sbp2_update will have requeued * lu->work already. Reset the work from reconnect to login. */ - PREPARE_DELAYED_WORK(&lu->work, sbp2_login); - out: - sbp2_target_put(tgt); + lu->workfn = sbp2_login; +} + +static void sbp2_reconnect(struct work_struct *work) +{ + struct sbp2_logical_unit *lu = + container_of(work, struct sbp2_logical_unit, work.work); + struct sbp2_target *tgt = lu->tgt; + struct fw_device *device = target_parent_device(tgt); + int generation, node_id, local_node_id; + + if (fw_device_is_shutdown(device)) + return; + + generation = device->generation; + smp_rmb(); /* node IDs must not be older than generation */ + node_id = device->node_id; + local_node_id = device->card->node_id; + + if (sbp2_send_management_orb(lu, node_id, generation, + SBP2_RECONNECT_REQUEST, + lu->login_id, NULL) < 0) { + /* + * If reconnect was impossible even though we are in the + * current generation, fall back and try to log in again. + * + * We could check for "Function rejected" status, but + * looking at the bus generation as simpler and more general. + */ + smp_rmb(); /* get current card generation */ + if (generation == device->card->generation || + lu->retries++ >= 5) { + dev_err(tgt_dev(tgt), "failed to reconnect\n"); + lu->retries = 0; + lu->workfn = sbp2_login; + } + sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); + + return; + } + + tgt->node_id = node_id; + tgt->address_high = local_node_id << 16; + smp_wmb(); /* node IDs must not be older than generation */ + lu->generation = generation; + + dev_notice(tgt_dev(tgt), "reconnected to LUN %04x (%d retries)\n", + lu->lun, lu->retries); + + sbp2_agent_reset(lu); + sbp2_cancel_orbs(lu); + sbp2_conditionally_unblock(lu); +} + +static void sbp2_lu_workfn(struct work_struct *work) +{ + struct sbp2_logical_unit *lu = container_of(to_delayed_work(work), + struct sbp2_logical_unit, work); + lu->workfn(work); } static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) @@ -1008,13 +1006,22 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) lu->blocked = false; ++tgt->dont_block; INIT_LIST_HEAD(&lu->orb_list); - INIT_DELAYED_WORK(&lu->work, sbp2_login); + lu->workfn = sbp2_login; + INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn); list_add_tail(&lu->link, &tgt->lu_list); return 0; } -static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory) +static void sbp2_get_unit_unique_id(struct sbp2_target *tgt, + const u32 *leaf) +{ + if ((leaf[0] & 0xffff0000) == 0x00020000) + tgt->guid = (u64)leaf[1] << 32 | leaf[2]; +} + +static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, + const u32 *directory) { struct fw_csr_iterator ci; int key, value; @@ -1027,7 +1034,7 @@ static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory) return 0; } -static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory, +static int sbp2_scan_unit_dir(struct sbp2_target *tgt, const u32 *directory, u32 *model, u32 *firmware_revision) { struct fw_csr_iterator ci; @@ -1064,6 +1071,10 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory, return -ENOMEM; break; + case SBP2_CSR_UNIT_UNIQUE_ID: + sbp2_get_unit_unique_id(tgt, ci.p - 1 + value); + break; + case SBP2_CSR_LOGICAL_UNIT_DIRECTORY: /* Adjust for the increment in the iterator */ if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0) @@ -1084,8 +1095,8 @@ static void sbp2_clamp_management_orb_timeout(struct sbp2_target *tgt) unsigned int timeout = tgt->mgt_orb_timeout; if (timeout > 40000) - fw_notify("%s: %ds mgt_ORB_timeout limited to 40s\n", - tgt->bus_id, timeout / 1000); + dev_notice(tgt_dev(tgt), "%ds mgt_ORB_timeout limited to 40s\n", + timeout / 1000); tgt->mgt_orb_timeout = clamp_val(timeout, 5000, 40000); } @@ -1097,9 +1108,9 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, unsigned int w = sbp2_param_workarounds; if (w) - fw_notify("Please notify linux1394-devel@lists.sourceforge.net " - "if you need the workarounds parameter for %s\n", - tgt->bus_id); + dev_notice(tgt_dev(tgt), + "Please notify linux1394-devel@lists.sf.net " + "if you need the workarounds parameter\n"); if (w & SBP2_WORKAROUND_OVERRIDE) goto out; @@ -1119,26 +1130,30 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, } out: if (w) - fw_notify("Workarounds for %s: 0x%x " - "(firmware_revision 0x%06x, model_id 0x%06x)\n", - tgt->bus_id, w, firmware_revision, model); + dev_notice(tgt_dev(tgt), "workarounds 0x%x " + "(firmware_revision 0x%06x, model_id 0x%06x)\n", + w, firmware_revision, model); tgt->workarounds = w; } static struct scsi_host_template scsi_driver_template; +static void sbp2_remove(struct fw_unit *unit); -static int sbp2_probe(struct device *dev) +static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) { - struct fw_unit *unit = fw_unit(dev); struct fw_device *device = fw_parent_device(unit); struct sbp2_target *tgt; struct sbp2_logical_unit *lu; struct Scsi_Host *shost; u32 model, firmware_revision; + /* cannot (or should not) handle targets on the local node */ + if (device->is_local) + return -ENODEV; + if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE) - BUG_ON(dma_set_max_seg_size(device->card->device, - SBP2_MAX_SEG_SIZE)); + WARN_ON(dma_set_max_seg_size(device->card->device, + SBP2_MAX_SEG_SIZE)); shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); if (shost == NULL) @@ -1147,9 +1162,7 @@ static int sbp2_probe(struct device *dev) tgt = (struct sbp2_target *)shost->hostdata; dev_set_drvdata(&unit->device, tgt); tgt->unit = unit; - kref_init(&tgt->kref); INIT_LIST_HEAD(&tgt->lu_list); - tgt->bus_id = dev_name(&unit->device); tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; if (fw_device_enable_phys_dma(device) < 0) @@ -1157,12 +1170,10 @@ 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; - fw_device_get(device); - fw_unit_get(unit); - /* implicit directory ID */ tgt->directory_id = ((unit->directory - device->config_rom) * 4 + CSR_CONFIG_ROM) & 0xffffff; @@ -1172,7 +1183,7 @@ static int sbp2_probe(struct device *dev) if (sbp2_scan_unit_dir(tgt, unit->directory, &model, &firmware_revision) < 0) - goto fail_tgt_put; + goto fail_remove; sbp2_clamp_management_orb_timeout(tgt); sbp2_init_workarounds(tgt, model, firmware_revision); @@ -1183,16 +1194,17 @@ static int sbp2_probe(struct device *dev) * specifies the max payload size as 2 ^ (max_payload + 2), so * if we set this to max_speed + 7, we get the right value. */ - tgt->max_payload = min(device->max_speed + 7, 10U); - tgt->max_payload = min(tgt->max_payload, device->card->max_receive - 1); + tgt->max_payload = min3(device->max_speed + 7, 10U, + device->card->max_receive - 1); /* Do the login in a workqueue so we can easily reschedule retries. */ list_for_each_entry(lu, &tgt->lu_list, link) sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); + return 0; - fail_tgt_put: - sbp2_target_put(tgt); + fail_remove: + sbp2_remove(unit); return -ENOMEM; fail_shost_put: @@ -1200,67 +1212,6 @@ static int sbp2_probe(struct device *dev) return -ENOMEM; } -static int sbp2_remove(struct device *dev) -{ - struct fw_unit *unit = fw_unit(dev); - struct sbp2_target *tgt = dev_get_drvdata(&unit->device); - - sbp2_target_put(tgt); - return 0; -} - -static void sbp2_reconnect(struct work_struct *work) -{ - struct sbp2_logical_unit *lu = - container_of(work, struct sbp2_logical_unit, work.work); - struct sbp2_target *tgt = lu->tgt; - struct fw_device *device = target_device(tgt); - int generation, node_id, local_node_id; - - if (fw_device_is_shutdown(device)) - goto out; - - generation = device->generation; - smp_rmb(); /* node IDs must not be older than generation */ - node_id = device->node_id; - local_node_id = device->card->node_id; - - if (sbp2_send_management_orb(lu, node_id, generation, - SBP2_RECONNECT_REQUEST, - lu->login_id, NULL) < 0) { - /* - * If reconnect was impossible even though we are in the - * current generation, fall back and try to log in again. - * - * We could check for "Function rejected" status, but - * looking at the bus generation as simpler and more general. - */ - smp_rmb(); /* get current card generation */ - if (generation == device->card->generation || - lu->retries++ >= 5) { - fw_error("%s: failed to reconnect\n", tgt->bus_id); - lu->retries = 0; - PREPARE_DELAYED_WORK(&lu->work, sbp2_login); - } - sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); - goto out; - } - - tgt->node_id = node_id; - tgt->address_high = local_node_id << 16; - 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); - - sbp2_agent_reset(lu); - sbp2_cancel_orbs(lu); - sbp2_conditionally_unblock(lu); - out: - sbp2_target_put(tgt); -} - static void sbp2_update(struct fw_unit *unit) { struct sbp2_target *tgt = dev_get_drvdata(&unit->device); @@ -1279,6 +1230,49 @@ static void sbp2_update(struct fw_unit *unit) } } +static void sbp2_remove(struct fw_unit *unit) +{ + struct fw_device *device = fw_parent_device(unit); + struct sbp2_target *tgt = dev_get_drvdata(&unit->device); + struct sbp2_logical_unit *lu, *next; + struct Scsi_Host *shost = + container_of((void *)tgt, struct Scsi_Host, hostdata[0]); + struct scsi_device *sdev; + + /* prevent deadlocks */ + sbp2_unblock(tgt); + + list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { + cancel_delayed_work_sync(&lu->work); + sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } + if (lu->login_id != INVALID_LOGIN_ID) { + int generation, node_id; + /* + * tgt->node_id may be obsolete here if we failed + * during initial login or after a bus reset where + * the topology changed. + */ + generation = device->generation; + smp_rmb(); /* node_id vs. generation */ + node_id = device->node_id; + sbp2_send_management_orb(lu, node_id, generation, + SBP2_LOGOUT_REQUEST, + lu->login_id, NULL); + } + fw_core_remove_address_handler(&lu->address_handler); + list_del(&lu->link); + kfree(lu); + } + scsi_remove_host(shost); + dev_notice(&unit->device, "released target %d:0:0\n", shost->host_no); + + scsi_host_put(shost); +} + #define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e #define SBP2_SW_VERSION_ENTRY 0x00010483 @@ -1295,22 +1289,19 @@ static const struct ieee1394_device_id sbp2_id_table[] = { static struct fw_driver sbp2_driver = { .driver = { .owner = THIS_MODULE, - .name = sbp2_driver_name, + .name = KBUILD_MODNAME, .bus = &fw_bus_type, - .probe = sbp2_probe, - .remove = sbp2_remove, }, + .probe = sbp2_probe, .update = sbp2_update, + .remove = sbp2_remove, .id_table = sbp2_id_table, }; 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, @@ -1320,10 +1311,19 @@ static void sbp2_unmap_scatterlist(struct device *card_device, static unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) { int sam_status; + int sfmt = (sbp2_status[0] >> 6) & 0x03; - sense_data[0] = 0x70; + if (sfmt == 2 || sfmt == 3) { + /* + * Reserved for future standardization (2) or + * Status block format vendor-dependent (3) + */ + return DID_ERROR << 16; + } + + sense_data[0] = 0x70 | sfmt | (sbp2_status[1] & 0x80); sense_data[1] = 0x0; - sense_data[2] = sbp2_status[1]; + sense_data[2] = ((sbp2_status[1] << 1) & 0xe0) | (sbp2_status[1] & 0x0f); sense_data[3] = sbp2_status[4]; sense_data[4] = sbp2_status[5]; sense_data[5] = sbp2_status[6]; @@ -1359,7 +1359,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, { struct sbp2_command_orb *orb = container_of(base_orb, struct sbp2_command_orb, base); - struct fw_device *device = target_device(orb->lu->tgt); + struct fw_device *device = target_parent_device(orb->lu->tgt); int result; if (status != NULL) { @@ -1398,7 +1398,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb, sbp2_unmap_scatterlist(device->card->device, orb); orb->cmd->result = result; - orb->done(orb->cmd); + orb->cmd->scsi_done(orb->cmd); } static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, @@ -1407,9 +1407,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; /* @@ -1455,18 +1454,18 @@ 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; } /* SCSI stack integration */ -static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) +static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; - struct fw_device *device = target_device(lu->tgt); + struct fw_device *device = target_parent_device(lu->tgt); struct sbp2_command_orb *orb; int generation, retval = SCSI_MLQUEUE_HOST_BUSY; @@ -1475,26 +1474,21 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) * transfer direction not handled. */ if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) { - fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n"); + dev_err(lu_dev(lu), "cannot handle bidirectional command\n"); cmd->result = DID_ERROR << 16; - done(cmd); + cmd->scsi_done(cmd); return 0; } orb = kzalloc(sizeof(*orb), GFP_ATOMIC); - if (orb == NULL) { - fw_notify("failed to alloc orb\n"); + if (orb == NULL) return SCSI_MLQUEUE_HOST_BUSY; - } /* Initialize rcode to something not RCODE_COMPLETE. */ orb->base.rcode = -1; kref_init(&orb->base.kref); - - orb->lu = lu; - orb->done = done; - orb->cmd = cmd; - + orb->lu = lu; + orb->cmd = cmd; orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); orb->request.misc = cpu_to_be32( COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) | @@ -1539,7 +1533,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) @@ -1571,9 +1568,7 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) sdev->start_stop_pwr_cond = 1; if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) - blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512); - - blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE); + blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512); return 0; } @@ -1586,7 +1581,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; - fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id); + dev_notice(lu_dev(lu), "sbp2_scsi_abort\n"); sbp2_agent_reset(lu); sbp2_cancel_orbs(lu); @@ -1626,7 +1621,7 @@ static struct device_attribute *sbp2_scsi_sysfs_attrs[] = { static struct scsi_host_template scsi_driver_template = { .module = THIS_MODULE, .name = "SBP-2 IEEE-1394", - .proc_name = sbp2_driver_name, + .proc_name = "sbp2", .queuecommand = sbp2_scsi_queuecommand, .slave_alloc = sbp2_scsi_slave_alloc, .slave_configure = sbp2_scsi_slave_configure, @@ -1645,23 +1640,16 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); /* Provide a module alias so root-on-sbp2 initrds don't break. */ -#ifndef CONFIG_IEEE1394_SBP2_MODULE MODULE_ALIAS("sbp2"); -#endif static int __init sbp2_init(void) { - sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME); - if (!sbp2_wq) - return -ENOMEM; - return driver_register(&sbp2_driver.driver); } static void __exit sbp2_cleanup(void) { driver_unregister(&sbp2_driver.driver); - destroy_workqueue(sbp2_wq); } module_init(sbp2_init); |
