diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 16:55:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-03 16:55:12 -0400 |
commit | df5a2a1fbca44bebeebb78530ac93c734f289707 (patch) | |
tree | 6a2522fee4c7e736e5d00a7ec1a978baab5ec145 | |
parent | 9b2e077c42a97fcbdc0dd71edb1fc9d15c74ad29 (diff) | |
parent | 4d50c44381c981c9caa74e82ab894d4938dac9ca (diff) |
Merge tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull firewire updates from Stefan Richter:
- feed GUIDs of FireWire nodes to the random pool
- more complete quirk handling of a TI S400B phy
- avoid holding a core lock while calling into highlevel drivers
* tag 'firewire-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
firewire: addendum to address handler RCU conversion
firewire: remove global lock around address handlers, convert to RCU
firewire: ohci: get IR bit from TSB41BA3D phy
firewire: core: feed /dev/random with devices' GUIDs
-rw-r--r-- | drivers/firewire/core-device.c | 3 | ||||
-rw-r--r-- | drivers/firewire/core-transaction.c | 33 | ||||
-rw-r--r-- | drivers/firewire/ohci.c | 28 | ||||
-rw-r--r-- | include/linux/firewire.h | 12 |
4 files changed, 59 insertions, 17 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 7a05fd24d68b..3873d535b28d 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/mod_devicetable.h> | 32 | #include <linux/mod_devicetable.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
35 | #include <linux/random.h> | ||
35 | #include <linux/rwsem.h> | 36 | #include <linux/rwsem.h> |
36 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
37 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
@@ -1066,6 +1067,8 @@ static void fw_device_init(struct work_struct *work) | |||
1066 | device->config_rom_retries = 0; | 1067 | device->config_rom_retries = 0; |
1067 | 1068 | ||
1068 | set_broadcast_channel(device, device->generation); | 1069 | set_broadcast_channel(device, device->generation); |
1070 | |||
1071 | add_device_randomness(&device->config_rom[3], 8); | ||
1069 | } | 1072 | } |
1070 | 1073 | ||
1071 | /* | 1074 | /* |
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 87d6f2d2f02d..28a94c7ec6e5 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
32 | #include <linux/list.h> | 32 | #include <linux/list.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/rculist.h> | ||
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
35 | #include <linux/spinlock.h> | 36 | #include <linux/spinlock.h> |
36 | #include <linux/string.h> | 37 | #include <linux/string.h> |
@@ -489,7 +490,7 @@ static struct fw_address_handler *lookup_overlapping_address_handler( | |||
489 | { | 490 | { |
490 | struct fw_address_handler *handler; | 491 | struct fw_address_handler *handler; |
491 | 492 | ||
492 | list_for_each_entry(handler, list, link) { | 493 | list_for_each_entry_rcu(handler, list, link) { |
493 | if (handler->offset < offset + length && | 494 | if (handler->offset < offset + length && |
494 | offset < handler->offset + handler->length) | 495 | offset < handler->offset + handler->length) |
495 | return handler; | 496 | return handler; |
@@ -510,7 +511,7 @@ static struct fw_address_handler *lookup_enclosing_address_handler( | |||
510 | { | 511 | { |
511 | struct fw_address_handler *handler; | 512 | struct fw_address_handler *handler; |
512 | 513 | ||
513 | list_for_each_entry(handler, list, link) { | 514 | list_for_each_entry_rcu(handler, list, link) { |
514 | if (is_enclosing_handler(handler, offset, length)) | 515 | if (is_enclosing_handler(handler, offset, length)) |
515 | return handler; | 516 | return handler; |
516 | } | 517 | } |
@@ -518,7 +519,7 @@ static struct fw_address_handler *lookup_enclosing_address_handler( | |||
518 | return NULL; | 519 | return NULL; |
519 | } | 520 | } |
520 | 521 | ||
521 | static DEFINE_SPINLOCK(address_handler_lock); | 522 | static DEFINE_SPINLOCK(address_handler_list_lock); |
522 | static LIST_HEAD(address_handler_list); | 523 | static LIST_HEAD(address_handler_list); |
523 | 524 | ||
524 | const struct fw_address_region fw_high_memory_region = | 525 | const struct fw_address_region fw_high_memory_region = |
@@ -555,6 +556,7 @@ static bool is_in_fcp_region(u64 offset, size_t length) | |||
555 | * the specified callback is invoked. The parameters passed to the callback | 556 | * the specified callback is invoked. The parameters passed to the callback |
556 | * give the details of the particular request. | 557 | * give the details of the particular request. |
557 | * | 558 | * |
559 | * To be called in process context. | ||
558 | * Return value: 0 on success, non-zero otherwise. | 560 | * Return value: 0 on success, non-zero otherwise. |
559 | * | 561 | * |
560 | * The start offset of the handler's address region is determined by | 562 | * The start offset of the handler's address region is determined by |
@@ -575,7 +577,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, | |||
575 | handler->length == 0) | 577 | handler->length == 0) |
576 | return -EINVAL; | 578 | return -EINVAL; |
577 | 579 | ||
578 | spin_lock_bh(&address_handler_lock); | 580 | spin_lock(&address_handler_list_lock); |
579 | 581 | ||
580 | handler->offset = region->start; | 582 | handler->offset = region->start; |
581 | while (handler->offset + handler->length <= region->end) { | 583 | while (handler->offset + handler->length <= region->end) { |
@@ -588,13 +590,13 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, | |||
588 | if (other != NULL) { | 590 | if (other != NULL) { |
589 | handler->offset += other->length; | 591 | handler->offset += other->length; |
590 | } else { | 592 | } else { |
591 | list_add_tail(&handler->link, &address_handler_list); | 593 | list_add_tail_rcu(&handler->link, &address_handler_list); |
592 | ret = 0; | 594 | ret = 0; |
593 | break; | 595 | break; |
594 | } | 596 | } |
595 | } | 597 | } |
596 | 598 | ||
597 | spin_unlock_bh(&address_handler_lock); | 599 | spin_unlock(&address_handler_list_lock); |
598 | 600 | ||
599 | return ret; | 601 | return ret; |
600 | } | 602 | } |
@@ -603,14 +605,17 @@ EXPORT_SYMBOL(fw_core_add_address_handler); | |||
603 | /** | 605 | /** |
604 | * fw_core_remove_address_handler() - unregister an address handler | 606 | * fw_core_remove_address_handler() - unregister an address handler |
605 | * | 607 | * |
608 | * To be called in process context. | ||
609 | * | ||
606 | * When fw_core_remove_address_handler() returns, @handler->callback() is | 610 | * When fw_core_remove_address_handler() returns, @handler->callback() is |
607 | * guaranteed to not run on any CPU anymore. | 611 | * guaranteed to not run on any CPU anymore. |
608 | */ | 612 | */ |
609 | void fw_core_remove_address_handler(struct fw_address_handler *handler) | 613 | void fw_core_remove_address_handler(struct fw_address_handler *handler) |
610 | { | 614 | { |
611 | spin_lock_bh(&address_handler_lock); | 615 | spin_lock(&address_handler_list_lock); |
612 | list_del(&handler->link); | 616 | list_del_rcu(&handler->link); |
613 | spin_unlock_bh(&address_handler_lock); | 617 | spin_unlock(&address_handler_list_lock); |
618 | synchronize_rcu(); | ||
614 | } | 619 | } |
615 | EXPORT_SYMBOL(fw_core_remove_address_handler); | 620 | EXPORT_SYMBOL(fw_core_remove_address_handler); |
616 | 621 | ||
@@ -844,7 +849,7 @@ static void handle_exclusive_region_request(struct fw_card *card, | |||
844 | if (tcode == TCODE_LOCK_REQUEST) | 849 | if (tcode == TCODE_LOCK_REQUEST) |
845 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); | 850 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); |
846 | 851 | ||
847 | spin_lock_bh(&address_handler_lock); | 852 | rcu_read_lock(); |
848 | handler = lookup_enclosing_address_handler(&address_handler_list, | 853 | handler = lookup_enclosing_address_handler(&address_handler_list, |
849 | offset, request->length); | 854 | offset, request->length); |
850 | if (handler) | 855 | if (handler) |
@@ -853,7 +858,7 @@ static void handle_exclusive_region_request(struct fw_card *card, | |||
853 | p->generation, offset, | 858 | p->generation, offset, |
854 | request->data, request->length, | 859 | request->data, request->length, |
855 | handler->callback_data); | 860 | handler->callback_data); |
856 | spin_unlock_bh(&address_handler_lock); | 861 | rcu_read_unlock(); |
857 | 862 | ||
858 | if (!handler) | 863 | if (!handler) |
859 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 864 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
@@ -886,8 +891,8 @@ static void handle_fcp_region_request(struct fw_card *card, | |||
886 | return; | 891 | return; |
887 | } | 892 | } |
888 | 893 | ||
889 | spin_lock_bh(&address_handler_lock); | 894 | rcu_read_lock(); |
890 | list_for_each_entry(handler, &address_handler_list, link) { | 895 | list_for_each_entry_rcu(handler, &address_handler_list, link) { |
891 | if (is_enclosing_handler(handler, offset, request->length)) | 896 | if (is_enclosing_handler(handler, offset, request->length)) |
892 | handler->address_callback(card, NULL, tcode, | 897 | handler->address_callback(card, NULL, tcode, |
893 | destination, source, | 898 | destination, source, |
@@ -896,7 +901,7 @@ static void handle_fcp_region_request(struct fw_card *card, | |||
896 | request->length, | 901 | request->length, |
897 | handler->callback_data); | 902 | handler->callback_data); |
898 | } | 903 | } |
899 | spin_unlock_bh(&address_handler_lock); | 904 | rcu_read_unlock(); |
900 | 905 | ||
901 | fw_send_response(card, request, RCODE_COMPLETE); | 906 | fw_send_response(card, request, RCODE_COMPLETE); |
902 | } | 907 | } |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c788dbdaf3bc..834e71d2324d 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -1777,11 +1777,35 @@ static int get_self_id_pos(struct fw_ohci *ohci, u32 self_id, | |||
1777 | return i; | 1777 | return i; |
1778 | } | 1778 | } |
1779 | 1779 | ||
1780 | static int initiated_reset(struct fw_ohci *ohci) | ||
1781 | { | ||
1782 | int reg; | ||
1783 | int ret = 0; | ||
1784 | |||
1785 | mutex_lock(&ohci->phy_reg_mutex); | ||
1786 | reg = write_phy_reg(ohci, 7, 0xe0); /* Select page 7 */ | ||
1787 | if (reg >= 0) { | ||
1788 | reg = read_phy_reg(ohci, 8); | ||
1789 | reg |= 0x40; | ||
1790 | reg = write_phy_reg(ohci, 8, reg); /* set PMODE bit */ | ||
1791 | if (reg >= 0) { | ||
1792 | reg = read_phy_reg(ohci, 12); /* read register 12 */ | ||
1793 | if (reg >= 0) { | ||
1794 | if ((reg & 0x08) == 0x08) { | ||
1795 | /* bit 3 indicates "initiated reset" */ | ||
1796 | ret = 0x2; | ||
1797 | } | ||
1798 | } | ||
1799 | } | ||
1800 | } | ||
1801 | mutex_unlock(&ohci->phy_reg_mutex); | ||
1802 | return ret; | ||
1803 | } | ||
1804 | |||
1780 | /* | 1805 | /* |
1781 | * TI TSB82AA2B and TSB12LV26 do not receive the selfID of a locally | 1806 | * TI TSB82AA2B and TSB12LV26 do not receive the selfID of a locally |
1782 | * attached TSB41BA3D phy; see http://www.ti.com/litv/pdf/sllz059. | 1807 | * attached TSB41BA3D phy; see http://www.ti.com/litv/pdf/sllz059. |
1783 | * Construct the selfID from phy register contents. | 1808 | * Construct the selfID from phy register contents. |
1784 | * FIXME: How to determine the selfID.i flag? | ||
1785 | */ | 1809 | */ |
1786 | static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) | 1810 | static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) |
1787 | { | 1811 | { |
@@ -1814,6 +1838,8 @@ static int find_and_insert_self_id(struct fw_ohci *ohci, int self_id_count) | |||
1814 | self_id |= ((status & 0x3) << (6 - (i * 2))); | 1838 | self_id |= ((status & 0x3) << (6 - (i * 2))); |
1815 | } | 1839 | } |
1816 | 1840 | ||
1841 | self_id |= initiated_reset(ohci); | ||
1842 | |||
1817 | pos = get_self_id_pos(ohci, self_id, self_id_count); | 1843 | pos = get_self_id_pos(ohci, self_id, self_id_count); |
1818 | if (pos >= 0) { | 1844 | if (pos >= 0) { |
1819 | memmove(&(ohci->self_id_buffer[pos+1]), | 1845 | memmove(&(ohci->self_id_buffer[pos+1]), |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index db04ec5121cb..191501afd7fb 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
@@ -265,8 +265,16 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode, | |||
265 | void *data, size_t length, | 265 | void *data, size_t length, |
266 | void *callback_data); | 266 | void *callback_data); |
267 | /* | 267 | /* |
268 | * Important note: Except for the FCP registers, the callback must guarantee | 268 | * This callback handles an inbound request subaction. It is called in |
269 | * that either fw_send_response() or kfree() is called on the @request. | 269 | * RCU read-side context, therefore must not sleep. |
270 | * | ||
271 | * The callback should not initiate outbound request subactions directly. | ||
272 | * Otherwise there is a danger of recursion of inbound and outbound | ||
273 | * transactions from and to the local node. | ||
274 | * | ||
275 | * The callback is responsible that either fw_send_response() or kfree() | ||
276 | * is called on the @request, except for FCP registers for which the core | ||
277 | * takes care of that. | ||
270 | */ | 278 | */ |
271 | typedef void (*fw_address_callback_t)(struct fw_card *card, | 279 | typedef void (*fw_address_callback_t)(struct fw_card *card, |
272 | struct fw_request *request, | 280 | struct fw_request *request, |