From 188726ecb66f022e92ec110ca85c62a937184636 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 24 May 2012 19:28:17 +0200 Subject: firewire: core: make address handler length 64 bits The type of the length field of the fw_address_handler structure was size_t, which restricted it to 32 bits on 32-bit architectures. While making it u32 would match the userspace API, all calculations on this field use 64 bits anyway, and the ability to use 4 GB or larger address ranges is useful in the kernel. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 584826b..d77f60c 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -307,7 +307,7 @@ struct fw_transaction { struct fw_address_handler { u64 offset; - size_t length; + u64 length; fw_address_callback_t address_callback; void *callback_data; struct list_head link; -- cgit v0.10.2 From f07d42ac7f2a7d650125d0cd7a79631c4522edaf Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 24 May 2012 19:28:58 +0200 Subject: firewire: core: allocate the low memory region Prevent userspace applications from allocating low memory address ranges. Otherwise, if some application happens to allocate such a range and intends for a remote node to access it, and if that node also implements SBP-2 (which will become more likely with the upcoming SBP-2 target support), these accesses would be routed by the physical DMA unit to some wrong memory address. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 1c4980c..fc2ad65 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -525,9 +525,10 @@ const struct fw_address_region fw_high_memory_region = { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; EXPORT_SYMBOL(fw_high_memory_region); -#if 0 -const struct fw_address_region fw_low_memory_region = +static const struct fw_address_region low_memory_region = { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; + +#if 0 const struct fw_address_region fw_private_region = { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; const struct fw_address_region fw_csr_region = @@ -1189,6 +1190,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 = 0x000100000000ULL, + .address_callback = handle_low_memory, +}; + MODULE_AUTHOR("Kristian Hoegsberg "); MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); MODULE_LICENSE("GPL"); @@ -1250,6 +1268,7 @@ static int __init fw_core_init(void) 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); -- cgit v0.10.2 From 9d60ef2bd87f201c509cfae13ba6c9013446673d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 24 May 2012 19:29:19 +0200 Subject: firewire: ohci: lazy bus time initialization The Bus_Time CSR is virtually never used, so we can avoid burning CPU in interrupt context for 1 or 3 IsochronousCycleTimer accesses every minute by not tracking the bus time until the CSR is actually accessed for the first time. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c1af05e..1c365b8 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -191,6 +191,7 @@ struct fw_ohci { 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; @@ -1726,6 +1727,13 @@ 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; @@ -2213,7 +2221,7 @@ static int ohci_enable(struct fw_card *card, { struct fw_ohci *ohci = fw_ohci(card); struct pci_dev *dev = to_pci_dev(card->device); - u32 lps, seconds, version, irqs; + u32 lps, version, irqs; int i, ret; if (software_reset(ohci)) { @@ -2269,9 +2277,7 @@ static int ohci_enable(struct fw_card *card, (OHCI1394_MAX_PHYS_RESP_RETRIES << 8) | (200 << 16)); - seconds = lower_32_bits(get_seconds()); - reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25); - ohci->bus_time = seconds & ~0x3f; + ohci->bus_time_running = false; version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; if (version >= OHCI_VERSION_1_1) { @@ -2369,7 +2375,6 @@ static int ohci_enable(struct fw_card *card, OHCI1394_postedWriteErr | OHCI1394_selfIDComplete | OHCI1394_regAccessFail | - OHCI1394_cycle64Seconds | OHCI1394_cycleInconsistent | OHCI1394_unrecoverableError | OHCI1394_cycleTooLong | @@ -2658,7 +2663,8 @@ static void ohci_write_csr(struct fw_card *card, int csr_offset, u32 value) case CSR_BUS_TIME: spin_lock_irqsave(&ohci->lock, flags); - ohci->bus_time = (ohci->bus_time & 0x7f) | (value & ~0x7f); + ohci->bus_time = (update_bus_time(ohci) & 0x40) | + (value & ~0x7f); spin_unlock_irqrestore(&ohci->lock, flags); break; -- cgit v0.10.2 From 7baab9acfb25934a32541d617cbc676abd1fbf5b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 4 Jun 2012 21:28:07 +0200 Subject: firewire: ohci: sanity-check MMIO resource pci_request_region() does not fail on resources that have not been allocated by the BIOS or by the kernel, so to avoid accessing registers that are not there, we have to check for this explicitly. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 1c365b8..922cd26 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3545,6 +3545,13 @@ static int __devinit pci_probe(struct pci_dev *dev, INIT_WORK(&ohci->bus_reset_work, bus_reset_work); + if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM) || + pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE) { + dev_err(&dev->dev, "invalid MMIO resource\n"); + err = -ENXIO; + goto fail_disable; + } + err = pci_request_region(dev, 0, ohci_driver_name); if (err) { dev_err(&dev->dev, "MMIO resource unavailable\n"); -- cgit v0.10.2 From 9d23f9e946ad757344792a20ba5152f3a921688b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 13 Jun 2012 22:28:24 +0200 Subject: firewire: core: fix multichannel IR with buffers larger than 2 GB With a 32-bit i, computing i< Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 8382e27..38c0aa6 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -146,7 +146,7 @@ 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) { - int i; + size_t i; dma_addr_t address; ssize_t offset; -- cgit v0.10.2 From e18907cc8a3cd6e09510632b753b8b6fefa1752a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 13 Jun 2012 22:29:20 +0200 Subject: firewire: ohci: initialize multiChanMode bits after reset OHCI 1.1 says: | Since the value of this bit is undefined after reset in all IR | contexts, software shall initialize this bit to zero in all contexts | whether or not active to maintain the exclusive nature of this bit. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 922cd26..c788dbd 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2279,6 +2279,11 @@ static int ohci_enable(struct fw_card *card, 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, -- cgit v0.10.2 From baedee177e6c553af455865718971d9a9c75e537 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 17 Jun 2012 16:40:36 +0200 Subject: firewire: core: add is_local sysfs device attribute Making this information available in sysfs allows to differentiate between controllers in the local and remote Linux PCs, and thus is useful for servers that are started with udev rules. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 4d460ef..7a05fd2 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -398,6 +398,14 @@ static ssize_t guid_show(struct device *dev, return ret; } +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; @@ -447,6 +455,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, }; diff --git a/include/linux/firewire.h b/include/linux/firewire.h index d77f60c..cb2445e 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -138,7 +138,7 @@ struct fw_card { struct fw_attribute_group { struct attribute_group *groups[2]; struct attribute_group group; - struct attribute *attrs[12]; + struct attribute *attrs[13]; }; enum fw_device_state { -- cgit v0.10.2 From e3cbd92002a30aecae8cb8b31a5e1916eb270a14 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 17 Jun 2012 19:57:23 +0200 Subject: firewire: core: document is_local sysfs attribute Signed-off-by: Stefan Richter diff --git a/Documentation/ABI/stable/sysfs-bus-firewire b/Documentation/ABI/stable/sysfs-bus-firewire index 3d484e5..41e5a0c 100644 --- a/Documentation/ABI/stable/sysfs-bus-firewire +++ b/Documentation/ABI/stable/sysfs-bus-firewire @@ -39,6 +39,17 @@ Users: udev rules to set ownership and access permissions or ACLs of /dev/fw[0-9]+ character device files +What: /sys/bus/firewire/devices/fw[0-9]+/is_local +Date: July 2012 +KernelVersion: 3.6 +Contact: linux1394-devel@lists.sourceforge.net +Description: + IEEE 1394 node device attribute. + Read-only and immutable. +Values: 1: The sysfs entry represents a local node (a controller card). + 0: The sysfs entry represents a remote node. + + What: /sys/bus/firewire/devices/fw[0-9]+[.][0-9]+/ Date: May 2007 KernelVersion: 2.6.22 -- cgit v0.10.2