diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-03 11:08:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-03 11:08:44 -0500 |
commit | c1dcb4bb1e3e16e9baee578d9bb040e5fba1063e (patch) | |
tree | 1bba995740aed8ef9a47111c1ee6ceeda84af836 /drivers/firewire/core-device.c | |
parent | 60f8a8d4c6c46bb080e8e65d30be31b172a39a78 (diff) | |
parent | 6fdb2ee243404c7cbf530387bf904ad1841ebf5b (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (23 commits)
firewire: ohci: extend initialization log message
firewire: ohci: fix IR/IT context mask mixup
firewire: ohci: add module parameter to activate quirk fixes
firewire: ohci: use an ID table for quirks detection
firewire: ohci: reorder struct fw_ohci for better cache efficiency
firewire: ohci: remove unused dualbuffer IR code
firewire: core: combine a bit of repeated code
firewire: core: change type of a data buffer
firewire: cdev: increment ABI version number
firewire: cdev: add more flexible cycle timer ioctl
firewire: core: rename an internal function
firewire: core: fix an information leak
firewire: core: increase stack size of config ROM reader
firewire: core: don't fail device creation in case of too large config ROM blocks
firewire: core: fix "giving up on config rom" with Panasonic AG-DV2500
firewire: remove incomplete Bus_Time CSR support
firewire: get_cycle_timer optimization and cleanup
firewire: ohci: enable cycle timer fix on ALi and NEC controllers
firewire: ohci: work around cycle timer bugs on VIA controllers
firewire: make PCI device id constant
...
Diffstat (limited to 'drivers/firewire/core-device.c')
-rw-r--r-- | drivers/firewire/core-device.c | 198 |
1 files changed, 132 insertions, 66 deletions
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 9d0dfcbe2c1c..014cabd3afda 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/bug.h> | ||
21 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
22 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
23 | #include <linux/device.h> | 24 | #include <linux/device.h> |
@@ -43,7 +44,7 @@ | |||
43 | 44 | ||
44 | #include "core.h" | 45 | #include "core.h" |
45 | 46 | ||
46 | void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p) | 47 | void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p) |
47 | { | 48 | { |
48 | ci->p = p + 1; | 49 | ci->p = p + 1; |
49 | ci->end = ci->p + (p[0] >> 16); | 50 | ci->end = ci->p + (p[0] >> 16); |
@@ -59,9 +60,76 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) | |||
59 | } | 60 | } |
60 | EXPORT_SYMBOL(fw_csr_iterator_next); | 61 | EXPORT_SYMBOL(fw_csr_iterator_next); |
61 | 62 | ||
63 | static const u32 *search_leaf(const u32 *directory, int search_key) | ||
64 | { | ||
65 | struct fw_csr_iterator ci; | ||
66 | int last_key = 0, key, value; | ||
67 | |||
68 | fw_csr_iterator_init(&ci, directory); | ||
69 | while (fw_csr_iterator_next(&ci, &key, &value)) { | ||
70 | if (last_key == search_key && | ||
71 | key == (CSR_DESCRIPTOR | CSR_LEAF)) | ||
72 | return ci.p - 1 + value; | ||
73 | |||
74 | last_key = key; | ||
75 | } | ||
76 | |||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | static int textual_leaf_to_string(const u32 *block, char *buf, size_t size) | ||
81 | { | ||
82 | unsigned int quadlets, i; | ||
83 | char c; | ||
84 | |||
85 | if (!size || !buf) | ||
86 | return -EINVAL; | ||
87 | |||
88 | quadlets = min(block[0] >> 16, 256U); | ||
89 | if (quadlets < 2) | ||
90 | return -ENODATA; | ||
91 | |||
92 | if (block[1] != 0 || block[2] != 0) | ||
93 | /* unknown language/character set */ | ||
94 | return -ENODATA; | ||
95 | |||
96 | block += 3; | ||
97 | quadlets -= 2; | ||
98 | for (i = 0; i < quadlets * 4 && i < size - 1; i++) { | ||
99 | c = block[i / 4] >> (24 - 8 * (i % 4)); | ||
100 | if (c == '\0') | ||
101 | break; | ||
102 | buf[i] = c; | ||
103 | } | ||
104 | buf[i] = '\0'; | ||
105 | |||
106 | return i; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * fw_csr_string - reads a string from the configuration ROM | ||
111 | * @directory: e.g. root directory or unit directory | ||
112 | * @key: the key of the preceding directory entry | ||
113 | * @buf: where to put the string | ||
114 | * @size: size of @buf, in bytes | ||
115 | * | ||
116 | * The string is taken from a minimal ASCII text descriptor leaf after | ||
117 | * the immediate entry with @key. The string is zero-terminated. | ||
118 | * Returns strlen(buf) or a negative error code. | ||
119 | */ | ||
120 | int fw_csr_string(const u32 *directory, int key, char *buf, size_t size) | ||
121 | { | ||
122 | const u32 *leaf = search_leaf(directory, key); | ||
123 | if (!leaf) | ||
124 | return -ENOENT; | ||
125 | |||
126 | return textual_leaf_to_string(leaf, buf, size); | ||
127 | } | ||
128 | EXPORT_SYMBOL(fw_csr_string); | ||
129 | |||
62 | static bool is_fw_unit(struct device *dev); | 130 | static bool is_fw_unit(struct device *dev); |
63 | 131 | ||
64 | static int match_unit_directory(u32 *directory, u32 match_flags, | 132 | static int match_unit_directory(const u32 *directory, u32 match_flags, |
65 | const struct ieee1394_device_id *id) | 133 | const struct ieee1394_device_id *id) |
66 | { | 134 | { |
67 | struct fw_csr_iterator ci; | 135 | struct fw_csr_iterator ci; |
@@ -195,7 +263,7 @@ static ssize_t show_immediate(struct device *dev, | |||
195 | struct config_rom_attribute *attr = | 263 | struct config_rom_attribute *attr = |
196 | container_of(dattr, struct config_rom_attribute, attr); | 264 | container_of(dattr, struct config_rom_attribute, attr); |
197 | struct fw_csr_iterator ci; | 265 | struct fw_csr_iterator ci; |
198 | u32 *dir; | 266 | const u32 *dir; |
199 | int key, value, ret = -ENOENT; | 267 | int key, value, ret = -ENOENT; |
200 | 268 | ||
201 | down_read(&fw_device_rwsem); | 269 | down_read(&fw_device_rwsem); |
@@ -226,10 +294,10 @@ static ssize_t show_text_leaf(struct device *dev, | |||
226 | { | 294 | { |
227 | struct config_rom_attribute *attr = | 295 | struct config_rom_attribute *attr = |
228 | container_of(dattr, struct config_rom_attribute, attr); | 296 | container_of(dattr, struct config_rom_attribute, attr); |
229 | struct fw_csr_iterator ci; | 297 | const u32 *dir; |
230 | u32 *dir, *block = NULL, *p, *end; | 298 | size_t bufsize; |
231 | int length, key, value, last_key = 0, ret = -ENOENT; | 299 | char dummy_buf[2]; |
232 | char *b; | 300 | int ret; |
233 | 301 | ||
234 | down_read(&fw_device_rwsem); | 302 | down_read(&fw_device_rwsem); |
235 | 303 | ||
@@ -238,40 +306,23 @@ static ssize_t show_text_leaf(struct device *dev, | |||
238 | else | 306 | else |
239 | dir = fw_device(dev)->config_rom + 5; | 307 | dir = fw_device(dev)->config_rom + 5; |
240 | 308 | ||
241 | fw_csr_iterator_init(&ci, dir); | 309 | if (buf) { |
242 | while (fw_csr_iterator_next(&ci, &key, &value)) { | 310 | bufsize = PAGE_SIZE - 1; |
243 | if (attr->key == last_key && | 311 | } else { |
244 | key == (CSR_DESCRIPTOR | CSR_LEAF)) | 312 | buf = dummy_buf; |
245 | block = ci.p - 1 + value; | 313 | bufsize = 1; |
246 | last_key = key; | ||
247 | } | 314 | } |
248 | 315 | ||
249 | if (block == NULL) | 316 | ret = fw_csr_string(dir, attr->key, buf, bufsize); |
250 | goto out; | ||
251 | |||
252 | length = min(block[0] >> 16, 256U); | ||
253 | if (length < 3) | ||
254 | goto out; | ||
255 | |||
256 | if (block[1] != 0 || block[2] != 0) | ||
257 | /* Unknown encoding. */ | ||
258 | goto out; | ||
259 | 317 | ||
260 | if (buf == NULL) { | 318 | if (ret >= 0) { |
261 | ret = length * 4; | 319 | /* Strip trailing whitespace and add newline. */ |
262 | goto out; | 320 | while (ret > 0 && isspace(buf[ret - 1])) |
321 | ret--; | ||
322 | strcpy(buf + ret, "\n"); | ||
323 | ret++; | ||
263 | } | 324 | } |
264 | 325 | ||
265 | b = buf; | ||
266 | end = &block[length + 1]; | ||
267 | for (p = &block[3]; p < end; p++, b += 4) | ||
268 | * (u32 *) b = (__force u32) __cpu_to_be32(*p); | ||
269 | |||
270 | /* Strip trailing whitespace and add newline. */ | ||
271 | while (b--, (isspace(*b) || *b == '\0') && b > buf); | ||
272 | strcpy(b + 1, "\n"); | ||
273 | ret = b + 2 - buf; | ||
274 | out: | ||
275 | up_read(&fw_device_rwsem); | 326 | up_read(&fw_device_rwsem); |
276 | 327 | ||
277 | return ret; | 328 | return ret; |
@@ -371,7 +422,7 @@ static ssize_t guid_show(struct device *dev, | |||
371 | return ret; | 422 | return ret; |
372 | } | 423 | } |
373 | 424 | ||
374 | static int units_sprintf(char *buf, u32 *directory) | 425 | static int units_sprintf(char *buf, const u32 *directory) |
375 | { | 426 | { |
376 | struct fw_csr_iterator ci; | 427 | struct fw_csr_iterator ci; |
377 | int key, value; | 428 | int key, value; |
@@ -441,28 +492,29 @@ static int read_rom(struct fw_device *device, | |||
441 | return rcode; | 492 | return rcode; |
442 | } | 493 | } |
443 | 494 | ||
444 | #define READ_BIB_ROM_SIZE 256 | 495 | #define MAX_CONFIG_ROM_SIZE 256 |
445 | #define READ_BIB_STACK_SIZE 16 | ||
446 | 496 | ||
447 | /* | 497 | /* |
448 | * Read the bus info block, perform a speed probe, and read all of the rest of | 498 | * Read the bus info block, perform a speed probe, and read all of the rest of |
449 | * the config ROM. We do all this with a cached bus generation. If the bus | 499 | * the config ROM. We do all this with a cached bus generation. If the bus |
450 | * generation changes under us, read_bus_info_block will fail and get retried. | 500 | * generation changes under us, read_config_rom will fail and get retried. |
451 | * It's better to start all over in this case because the node from which we | 501 | * It's better to start all over in this case because the node from which we |
452 | * are reading the ROM may have changed the ROM during the reset. | 502 | * are reading the ROM may have changed the ROM during the reset. |
453 | */ | 503 | */ |
454 | static int read_bus_info_block(struct fw_device *device, int generation) | 504 | static int read_config_rom(struct fw_device *device, int generation) |
455 | { | 505 | { |
456 | u32 *rom, *stack, *old_rom, *new_rom; | 506 | const u32 *old_rom, *new_rom; |
507 | u32 *rom, *stack; | ||
457 | u32 sp, key; | 508 | u32 sp, key; |
458 | int i, end, length, ret = -1; | 509 | int i, end, length, ret = -1; |
459 | 510 | ||
460 | rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE + | 511 | rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE + |
461 | sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); | 512 | sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL); |
462 | if (rom == NULL) | 513 | if (rom == NULL) |
463 | return -ENOMEM; | 514 | return -ENOMEM; |
464 | 515 | ||
465 | stack = &rom[READ_BIB_ROM_SIZE]; | 516 | stack = &rom[MAX_CONFIG_ROM_SIZE]; |
517 | memset(rom, 0, sizeof(*rom) * MAX_CONFIG_ROM_SIZE); | ||
466 | 518 | ||
467 | device->max_speed = SCODE_100; | 519 | device->max_speed = SCODE_100; |
468 | 520 | ||
@@ -529,40 +581,54 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
529 | */ | 581 | */ |
530 | key = stack[--sp]; | 582 | key = stack[--sp]; |
531 | i = key & 0xffffff; | 583 | i = key & 0xffffff; |
532 | if (i >= READ_BIB_ROM_SIZE) | 584 | if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) |
533 | /* | ||
534 | * The reference points outside the standard | ||
535 | * config rom area, something's fishy. | ||
536 | */ | ||
537 | goto out; | 585 | goto out; |
538 | 586 | ||
539 | /* Read header quadlet for the block to get the length. */ | 587 | /* Read header quadlet for the block to get the length. */ |
540 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) | 588 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
541 | goto out; | 589 | goto out; |
542 | end = i + (rom[i] >> 16) + 1; | 590 | end = i + (rom[i] >> 16) + 1; |
543 | i++; | 591 | if (end > MAX_CONFIG_ROM_SIZE) { |
544 | if (end > READ_BIB_ROM_SIZE) | ||
545 | /* | 592 | /* |
546 | * This block extends outside standard config | 593 | * This block extends outside the config ROM which is |
547 | * area (and the array we're reading it | 594 | * a firmware bug. Ignore this whole block, i.e. |
548 | * into). That's broken, so ignore this | 595 | * simply set a fake block length of 0. |
549 | * device. | ||
550 | */ | 596 | */ |
551 | goto out; | 597 | fw_error("skipped invalid ROM block %x at %llx\n", |
598 | rom[i], | ||
599 | i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM); | ||
600 | rom[i] = 0; | ||
601 | end = i; | ||
602 | } | ||
603 | i++; | ||
552 | 604 | ||
553 | /* | 605 | /* |
554 | * Now read in the block. If this is a directory | 606 | * Now read in the block. If this is a directory |
555 | * block, check the entries as we read them to see if | 607 | * block, check the entries as we read them to see if |
556 | * it references another block, and push it in that case. | 608 | * it references another block, and push it in that case. |
557 | */ | 609 | */ |
558 | while (i < end) { | 610 | for (; i < end; i++) { |
559 | if (read_rom(device, generation, i, &rom[i]) != | 611 | if (read_rom(device, generation, i, &rom[i]) != |
560 | RCODE_COMPLETE) | 612 | RCODE_COMPLETE) |
561 | goto out; | 613 | goto out; |
562 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && | 614 | |
563 | sp < READ_BIB_STACK_SIZE) | 615 | if ((key >> 30) != 3 || (rom[i] >> 30) < 2) |
564 | stack[sp++] = i + rom[i]; | 616 | continue; |
565 | i++; | 617 | /* |
618 | * Offset points outside the ROM. May be a firmware | ||
619 | * bug or an Extended ROM entry (IEEE 1212-2001 clause | ||
620 | * 7.7.18). Simply overwrite this pointer here by a | ||
621 | * fake immediate entry so that later iterators over | ||
622 | * the ROM don't have to check offsets all the time. | ||
623 | */ | ||
624 | if (i + (rom[i] & 0xffffff) >= MAX_CONFIG_ROM_SIZE) { | ||
625 | fw_error("skipped unsupported ROM entry %x at %llx\n", | ||
626 | rom[i], | ||
627 | i * 4 | CSR_REGISTER_BASE | CSR_CONFIG_ROM); | ||
628 | rom[i] = 0; | ||
629 | continue; | ||
630 | } | ||
631 | stack[sp++] = i + rom[i]; | ||
566 | } | 632 | } |
567 | if (length < i) | 633 | if (length < i) |
568 | length = i; | 634 | length = i; |
@@ -905,7 +971,7 @@ static void fw_device_init(struct work_struct *work) | |||
905 | * device. | 971 | * device. |
906 | */ | 972 | */ |
907 | 973 | ||
908 | if (read_bus_info_block(device, device->generation) < 0) { | 974 | if (read_config_rom(device, device->generation) < 0) { |
909 | if (device->config_rom_retries < MAX_RETRIES && | 975 | if (device->config_rom_retries < MAX_RETRIES && |
910 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { | 976 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { |
911 | device->config_rom_retries++; | 977 | device->config_rom_retries++; |
@@ -1022,7 +1088,7 @@ enum { | |||
1022 | }; | 1088 | }; |
1023 | 1089 | ||
1024 | /* Reread and compare bus info block and header of root directory */ | 1090 | /* Reread and compare bus info block and header of root directory */ |
1025 | static int reread_bus_info_block(struct fw_device *device, int generation) | 1091 | static int reread_config_rom(struct fw_device *device, int generation) |
1026 | { | 1092 | { |
1027 | u32 q; | 1093 | u32 q; |
1028 | int i; | 1094 | int i; |
@@ -1048,7 +1114,7 @@ static void fw_device_refresh(struct work_struct *work) | |||
1048 | struct fw_card *card = device->card; | 1114 | struct fw_card *card = device->card; |
1049 | int node_id = device->node_id; | 1115 | int node_id = device->node_id; |
1050 | 1116 | ||
1051 | switch (reread_bus_info_block(device, device->generation)) { | 1117 | switch (reread_config_rom(device, device->generation)) { |
1052 | case REREAD_BIB_ERROR: | 1118 | case REREAD_BIB_ERROR: |
1053 | if (device->config_rom_retries < MAX_RETRIES / 2 && | 1119 | if (device->config_rom_retries < MAX_RETRIES / 2 && |
1054 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { | 1120 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { |
@@ -1082,7 +1148,7 @@ static void fw_device_refresh(struct work_struct *work) | |||
1082 | */ | 1148 | */ |
1083 | device_for_each_child(&device->device, NULL, shutdown_unit); | 1149 | device_for_each_child(&device->device, NULL, shutdown_unit); |
1084 | 1150 | ||
1085 | if (read_bus_info_block(device, device->generation) < 0) { | 1151 | if (read_config_rom(device, device->generation) < 0) { |
1086 | if (device->config_rom_retries < MAX_RETRIES && | 1152 | if (device->config_rom_retries < MAX_RETRIES && |
1087 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { | 1153 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { |
1088 | device->config_rom_retries++; | 1154 | device->config_rom_retries++; |