aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-device.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2008-03-24 15:54:28 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2008-04-18 11:55:36 -0400
commitc9755e14a01987ada4063e8b4c50c2b6738d879e (patch)
tree41a593c4b9ac10ccc4ad031510438e4551e51b5b /drivers/firewire/fw-device.c
parent1dadff71d6356ebb804c3f4f1d3049247e16111c (diff)
firewire: reread config ROM when device reset the bus
When a device changes its configuration ROM, it announces this with a bus reset. firewire-core has to check which node initiated a bus reset and whether any unit directories went away or were added on this node. Tested with an IOI FWB-IDE01AB which has its link-on bit set if bus power is available but does not respond to ROM read requests if self power is off. This implements - recognition of the units if self power is switched on after fw-core gave up the initial attempt to read the config ROM, - shutdown of the units when self power is switched off. Also tested with a second PC running Linux/ieee1394. When the eth1394 driver is inserted and removed on that node, fw-core now notices the addition and removal of the IPv4 unit on the ieee1394 node. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-device.c')
-rw-r--r--drivers/firewire/fw-device.c222
1 files changed, 188 insertions, 34 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 20ac9a5afc37..75365cd0008a 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -25,7 +25,7 @@
25#include <linux/device.h> 25#include <linux/device.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/idr.h> 27#include <linux/idr.h>
28#include <linux/rwsem.h> 28#include <linux/string.h>
29#include <asm/semaphore.h> 29#include <asm/semaphore.h>
30#include <asm/system.h> 30#include <asm/system.h>
31#include <linux/ctype.h> 31#include <linux/ctype.h>
@@ -160,9 +160,9 @@ static void fw_device_release(struct device *dev)
160 * Take the card lock so we don't set this to NULL while a 160 * Take the card lock so we don't set this to NULL while a
161 * FW_NODE_UPDATED callback is being handled. 161 * FW_NODE_UPDATED callback is being handled.
162 */ 162 */
163 spin_lock_irqsave(&device->card->lock, flags); 163 spin_lock_irqsave(&card->lock, flags);
164 device->node->data = NULL; 164 device->node->data = NULL;
165 spin_unlock_irqrestore(&device->card->lock, flags); 165 spin_unlock_irqrestore(&card->lock, flags);
166 166
167 fw_node_put(device->node); 167 fw_node_put(device->node);
168 kfree(device->config_rom); 168 kfree(device->config_rom);
@@ -195,7 +195,9 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
195 container_of(dattr, struct config_rom_attribute, attr); 195 container_of(dattr, struct config_rom_attribute, attr);
196 struct fw_csr_iterator ci; 196 struct fw_csr_iterator ci;
197 u32 *dir; 197 u32 *dir;
198 int key, value; 198 int key, value, ret = -ENOENT;
199
200 down_read(&fw_device_rwsem);
199 201
200 if (is_fw_unit(dev)) 202 if (is_fw_unit(dev))
201 dir = fw_unit(dev)->directory; 203 dir = fw_unit(dev)->directory;
@@ -204,11 +206,15 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
204 206
205 fw_csr_iterator_init(&ci, dir); 207 fw_csr_iterator_init(&ci, dir);
206 while (fw_csr_iterator_next(&ci, &key, &value)) 208 while (fw_csr_iterator_next(&ci, &key, &value))
207 if (attr->key == key) 209 if (attr->key == key) {
208 return snprintf(buf, buf ? PAGE_SIZE : 0, 210 ret = snprintf(buf, buf ? PAGE_SIZE : 0,
209 "0x%06x\n", value); 211 "0x%06x\n", value);
212 break;
213 }
214
215 up_read(&fw_device_rwsem);
210 216
211 return -ENOENT; 217 return ret;
212} 218}
213 219
214#define IMMEDIATE_ATTR(name, key) \ 220#define IMMEDIATE_ATTR(name, key) \
@@ -221,9 +227,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
221 container_of(dattr, struct config_rom_attribute, attr); 227 container_of(dattr, struct config_rom_attribute, attr);
222 struct fw_csr_iterator ci; 228 struct fw_csr_iterator ci;
223 u32 *dir, *block = NULL, *p, *end; 229 u32 *dir, *block = NULL, *p, *end;
224 int length, key, value, last_key = 0; 230 int length, key, value, last_key = 0, ret = -ENOENT;
225 char *b; 231 char *b;
226 232
233 down_read(&fw_device_rwsem);
234
227 if (is_fw_unit(dev)) 235 if (is_fw_unit(dev))
228 dir = fw_unit(dev)->directory; 236 dir = fw_unit(dev)->directory;
229 else 237 else
@@ -238,18 +246,20 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
238 } 246 }
239 247
240 if (block == NULL) 248 if (block == NULL)
241 return -ENOENT; 249 goto out;
242 250
243 length = min(block[0] >> 16, 256U); 251 length = min(block[0] >> 16, 256U);
244 if (length < 3) 252 if (length < 3)
245 return -ENOENT; 253 goto out;
246 254
247 if (block[1] != 0 || block[2] != 0) 255 if (block[1] != 0 || block[2] != 0)
248 /* Unknown encoding. */ 256 /* Unknown encoding. */
249 return -ENOENT; 257 goto out;
250 258
251 if (buf == NULL) 259 if (buf == NULL) {
252 return length * 4; 260 ret = length * 4;
261 goto out;
262 }
253 263
254 b = buf; 264 b = buf;
255 end = &block[length + 1]; 265 end = &block[length + 1];
@@ -259,8 +269,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
259 /* Strip trailing whitespace and add newline. */ 269 /* Strip trailing whitespace and add newline. */
260 while (b--, (isspace(*b) || *b == '\0') && b > buf); 270 while (b--, (isspace(*b) || *b == '\0') && b > buf);
261 strcpy(b + 1, "\n"); 271 strcpy(b + 1, "\n");
272 ret = b + 2 - buf;
273 out:
274 up_read(&fw_device_rwsem);
262 275
263 return b + 2 - buf; 276 return ret;
264} 277}
265 278
266#define TEXT_LEAF_ATTR(name, key) \ 279#define TEXT_LEAF_ATTR(name, key) \
@@ -337,19 +350,28 @@ static ssize_t
337config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) 350config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
338{ 351{
339 struct fw_device *device = fw_device(dev); 352 struct fw_device *device = fw_device(dev);
353 size_t length;
340 354
341 memcpy(buf, device->config_rom, device->config_rom_length * 4); 355 down_read(&fw_device_rwsem);
356 length = device->config_rom_length * 4;
357 memcpy(buf, device->config_rom, length);
358 up_read(&fw_device_rwsem);
342 359
343 return device->config_rom_length * 4; 360 return length;
344} 361}
345 362
346static ssize_t 363static ssize_t
347guid_show(struct device *dev, struct device_attribute *attr, char *buf) 364guid_show(struct device *dev, struct device_attribute *attr, char *buf)
348{ 365{
349 struct fw_device *device = fw_device(dev); 366 struct fw_device *device = fw_device(dev);
367 int ret;
368
369 down_read(&fw_device_rwsem);
370 ret = snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
371 device->config_rom[3], device->config_rom[4]);
372 up_read(&fw_device_rwsem);
350 373
351 return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", 374 return ret;
352 device->config_rom[3], device->config_rom[4]);
353} 375}
354 376
355static struct device_attribute fw_device_attributes[] = { 377static struct device_attribute fw_device_attributes[] = {
@@ -412,7 +434,7 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data)
412 */ 434 */
413static int read_bus_info_block(struct fw_device *device, int generation) 435static int read_bus_info_block(struct fw_device *device, int generation)
414{ 436{
415 u32 *rom, *stack; 437 u32 *rom, *stack, *old_rom, *new_rom;
416 u32 sp, key; 438 u32 sp, key;
417 int i, end, length, ret = -1; 439 int i, end, length, ret = -1;
418 440
@@ -527,12 +549,19 @@ static int read_bus_info_block(struct fw_device *device, int generation)
527 length = i; 549 length = i;
528 } 550 }
529 551
530 device->config_rom = kmalloc(length * 4, GFP_KERNEL); 552 old_rom = device->config_rom;
531 if (device->config_rom == NULL) 553 new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
554 if (new_rom == NULL)
532 goto out; 555 goto out;
533 memcpy(device->config_rom, rom, length * 4); 556
557 down_write(&fw_device_rwsem);
558 device->config_rom = new_rom;
534 device->config_rom_length = length; 559 device->config_rom_length = length;
560 up_write(&fw_device_rwsem);
561
562 kfree(old_rom);
535 ret = 0; 563 ret = 0;
564 device->cmc = rom[2] & 1 << 30;
536 out: 565 out:
537 kfree(rom); 566 kfree(rom);
538 567
@@ -605,7 +634,14 @@ static int shutdown_unit(struct device *device, void *data)
605 return 0; 634 return 0;
606} 635}
607 636
608static DECLARE_RWSEM(idr_rwsem); 637/*
638 * fw_device_rwsem acts as dual purpose mutex:
639 * - serializes accesses to fw_device_idr,
640 * - serializes accesses to fw_device.config_rom/.config_rom_length and
641 * fw_unit.directory, unless those accesses happen at safe occasions
642 */
643DECLARE_RWSEM(fw_device_rwsem);
644
609static DEFINE_IDR(fw_device_idr); 645static DEFINE_IDR(fw_device_idr);
610int fw_cdev_major; 646int fw_cdev_major;
611 647
@@ -613,11 +649,11 @@ struct fw_device *fw_device_get_by_devt(dev_t devt)
613{ 649{
614 struct fw_device *device; 650 struct fw_device *device;
615 651
616 down_read(&idr_rwsem); 652 down_read(&fw_device_rwsem);
617 device = idr_find(&fw_device_idr, MINOR(devt)); 653 device = idr_find(&fw_device_idr, MINOR(devt));
618 if (device) 654 if (device)
619 fw_device_get(device); 655 fw_device_get(device);
620 up_read(&idr_rwsem); 656 up_read(&fw_device_rwsem);
621 657
622 return device; 658 return device;
623} 659}
@@ -632,9 +668,9 @@ static void fw_device_shutdown(struct work_struct *work)
632 device_for_each_child(&device->device, NULL, shutdown_unit); 668 device_for_each_child(&device->device, NULL, shutdown_unit);
633 device_unregister(&device->device); 669 device_unregister(&device->device);
634 670
635 down_write(&idr_rwsem); 671 down_write(&fw_device_rwsem);
636 idr_remove(&fw_device_idr, minor); 672 idr_remove(&fw_device_idr, minor);
637 up_write(&idr_rwsem); 673 up_write(&fw_device_rwsem);
638 fw_device_put(device); 674 fw_device_put(device);
639} 675}
640 676
@@ -687,10 +723,10 @@ static void fw_device_init(struct work_struct *work)
687 err = -ENOMEM; 723 err = -ENOMEM;
688 724
689 fw_device_get(device); 725 fw_device_get(device);
690 down_write(&idr_rwsem); 726 down_write(&fw_device_rwsem);
691 if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) 727 if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
692 err = idr_get_new(&fw_device_idr, device, &minor); 728 err = idr_get_new(&fw_device_idr, device, &minor);
693 up_write(&idr_rwsem); 729 up_write(&fw_device_rwsem);
694 730
695 if (err < 0) 731 if (err < 0)
696 goto error; 732 goto error;
@@ -724,7 +760,7 @@ static void fw_device_init(struct work_struct *work)
724 if (atomic_cmpxchg(&device->state, 760 if (atomic_cmpxchg(&device->state,
725 FW_DEVICE_INITIALIZING, 761 FW_DEVICE_INITIALIZING,
726 FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { 762 FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
727 fw_device_shutdown(&device->work.work); 763 fw_device_shutdown(work);
728 } else { 764 } else {
729 if (device->config_rom_retries) 765 if (device->config_rom_retries)
730 fw_notify("created device %s: GUID %08x%08x, S%d00, " 766 fw_notify("created device %s: GUID %08x%08x, S%d00, "
@@ -738,6 +774,7 @@ static void fw_device_init(struct work_struct *work)
738 device->device.bus_id, 774 device->device.bus_id,
739 device->config_rom[3], device->config_rom[4], 775 device->config_rom[3], device->config_rom[4],
740 1 << device->max_speed); 776 1 << device->max_speed);
777 device->config_rom_retries = 0;
741 } 778 }
742 779
743 /* 780 /*
@@ -752,9 +789,9 @@ static void fw_device_init(struct work_struct *work)
752 return; 789 return;
753 790
754 error_with_cdev: 791 error_with_cdev:
755 down_write(&idr_rwsem); 792 down_write(&fw_device_rwsem);
756 idr_remove(&fw_device_idr, minor); 793 idr_remove(&fw_device_idr, minor);
757 up_write(&idr_rwsem); 794 up_write(&fw_device_rwsem);
758 error: 795 error:
759 fw_device_put(device); /* fw_device_idr's reference */ 796 fw_device_put(device); /* fw_device_idr's reference */
760 797
@@ -784,6 +821,106 @@ static void fw_device_update(struct work_struct *work)
784 device_for_each_child(&device->device, NULL, update_unit); 821 device_for_each_child(&device->device, NULL, update_unit);
785} 822}
786 823
824enum {
825 REREAD_BIB_ERROR,
826 REREAD_BIB_GONE,
827 REREAD_BIB_UNCHANGED,
828 REREAD_BIB_CHANGED,
829};
830
831/* Reread and compare bus info block and header of root directory */
832static int reread_bus_info_block(struct fw_device *device, int generation)
833{
834 u32 q;
835 int i;
836
837 for (i = 0; i < 6; i++) {
838 if (read_rom(device, generation, i, &q) != RCODE_COMPLETE)
839 return REREAD_BIB_ERROR;
840
841 if (i == 0 && q == 0)
842 return REREAD_BIB_GONE;
843
844 if (i > device->config_rom_length || q != device->config_rom[i])
845 return REREAD_BIB_CHANGED;
846 }
847
848 return REREAD_BIB_UNCHANGED;
849}
850
851static void fw_device_refresh(struct work_struct *work)
852{
853 struct fw_device *device =
854 container_of(work, struct fw_device, work.work);
855 struct fw_card *card = device->card;
856 int node_id = device->node_id;
857
858 switch (reread_bus_info_block(device, device->generation)) {
859 case REREAD_BIB_ERROR:
860 if (device->config_rom_retries < MAX_RETRIES / 2 &&
861 atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
862 device->config_rom_retries++;
863 schedule_delayed_work(&device->work, RETRY_DELAY / 2);
864
865 return;
866 }
867 goto give_up;
868
869 case REREAD_BIB_GONE:
870 goto gone;
871
872 case REREAD_BIB_UNCHANGED:
873 if (atomic_cmpxchg(&device->state,
874 FW_DEVICE_INITIALIZING,
875 FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
876 goto gone;
877
878 fw_device_update(work);
879 device->config_rom_retries = 0;
880 goto out;
881
882 case REREAD_BIB_CHANGED:
883 break;
884 }
885
886 /*
887 * Something changed. We keep things simple and don't investigate
888 * further. We just destroy all previous units and create new ones.
889 */
890 device_for_each_child(&device->device, NULL, shutdown_unit);
891
892 if (read_bus_info_block(device, device->generation) < 0) {
893 if (device->config_rom_retries < MAX_RETRIES &&
894 atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
895 device->config_rom_retries++;
896 schedule_delayed_work(&device->work, RETRY_DELAY);
897
898 return;
899 }
900 goto give_up;
901 }
902
903 create_units(device);
904
905 if (atomic_cmpxchg(&device->state,
906 FW_DEVICE_INITIALIZING,
907 FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
908 goto gone;
909
910 fw_notify("refreshed device %s\n", device->device.bus_id);
911 device->config_rom_retries = 0;
912 goto out;
913
914 give_up:
915 fw_notify("giving up on refresh of device %s\n", device->device.bus_id);
916 gone:
917 atomic_set(&device->state, FW_DEVICE_SHUTDOWN);
918 fw_device_shutdown(work);
919 out:
920 if (node_id == card->root_node->node_id)
921 schedule_delayed_work(&card->work, 0);
922}
923
787void fw_node_event(struct fw_card *card, struct fw_node *node, int event) 924void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
788{ 925{
789 struct fw_device *device; 926 struct fw_device *device;
@@ -793,7 +930,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
793 case FW_NODE_LINK_ON: 930 case FW_NODE_LINK_ON:
794 if (!node->link_on) 931 if (!node->link_on)
795 break; 932 break;
796 933 create:
797 device = kzalloc(sizeof(*device), GFP_ATOMIC); 934 device = kzalloc(sizeof(*device), GFP_ATOMIC);
798 if (device == NULL) 935 if (device == NULL)
799 break; 936 break;
@@ -832,6 +969,23 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
832 schedule_delayed_work(&device->work, INITIAL_DELAY); 969 schedule_delayed_work(&device->work, INITIAL_DELAY);
833 break; 970 break;
834 971
972 case FW_NODE_INITIATED_RESET:
973 device = node->data;
974 if (device == NULL)
975 goto create;
976
977 device->node_id = node->node_id;
978 smp_wmb(); /* update node_id before generation */
979 device->generation = card->generation;
980 if (atomic_cmpxchg(&device->state,
981 FW_DEVICE_RUNNING,
982 FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
983 PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
984 schedule_delayed_work(&device->work,
985 node == card->local_node ? 0 : INITIAL_DELAY);
986 }
987 break;
988
835 case FW_NODE_UPDATED: 989 case FW_NODE_UPDATED:
836 if (!node->link_on || node->data == NULL) 990 if (!node->link_on || node->data == NULL)
837 break; 991 break;