diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-01-17 13:30:53 -0500 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-02-17 11:48:26 -0500 |
commit | af461fc1875b6ec18e23b5f670af36c4ed35c84e (patch) | |
tree | fa09a446c94d533c169b9e28e97c0e8c03d36912 /drivers/pcmcia/ds.c | |
parent | f971dbd5da4e2fbf756d07b938a9c65a9c75178b (diff) |
pcmcia: delay re-scanning and re-querying of PCMCIA bus
After a CIS update -- or the finalization of the resource database --,
proceed with the re-scanning or re-querying of PCMCIA cards only in
a separate thread to avoid deadlocks.
Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 76a21638291b..5400e20c664e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -432,16 +432,20 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
432 | 432 | ||
433 | if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, | 433 | if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, |
434 | CISTPL_MANFID, &manf_id)) { | 434 | CISTPL_MANFID, &manf_id)) { |
435 | mutex_lock(&p_dev->socket->ops_mutex); | ||
435 | p_dev->manf_id = manf_id.manf; | 436 | p_dev->manf_id = manf_id.manf; |
436 | p_dev->card_id = manf_id.card; | 437 | p_dev->card_id = manf_id.card; |
437 | p_dev->has_manf_id = 1; | 438 | p_dev->has_manf_id = 1; |
438 | p_dev->has_card_id = 1; | 439 | p_dev->has_card_id = 1; |
440 | mutex_unlock(&p_dev->socket->ops_mutex); | ||
439 | } | 441 | } |
440 | 442 | ||
441 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, | 443 | if (!pccard_read_tuple(p_dev->socket, p_dev->func, |
442 | CISTPL_FUNCID, &func_id)) { | 444 | CISTPL_FUNCID, &func_id)) { |
445 | mutex_lock(&p_dev->socket->ops_mutex); | ||
443 | p_dev->func_id = func_id.func; | 446 | p_dev->func_id = func_id.func; |
444 | p_dev->has_func_id = 1; | 447 | p_dev->has_func_id = 1; |
448 | mutex_unlock(&p_dev->socket->ops_mutex); | ||
445 | } else { | 449 | } else { |
446 | /* rule of thumb: cards with no FUNCID, but with | 450 | /* rule of thumb: cards with no FUNCID, but with |
447 | * common memory device geometry information, are | 451 | * common memory device geometry information, are |
@@ -458,14 +462,17 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
458 | dev_dbg(&p_dev->dev, | 462 | dev_dbg(&p_dev->dev, |
459 | "mem device geometry probably means " | 463 | "mem device geometry probably means " |
460 | "FUNCID_MEMORY\n"); | 464 | "FUNCID_MEMORY\n"); |
465 | mutex_lock(&p_dev->socket->ops_mutex); | ||
461 | p_dev->func_id = CISTPL_FUNCID_MEMORY; | 466 | p_dev->func_id = CISTPL_FUNCID_MEMORY; |
462 | p_dev->has_func_id = 1; | 467 | p_dev->has_func_id = 1; |
468 | mutex_unlock(&p_dev->socket->ops_mutex); | ||
463 | } | 469 | } |
464 | kfree(devgeo); | 470 | kfree(devgeo); |
465 | } | 471 | } |
466 | 472 | ||
467 | if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1, | 473 | if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1, |
468 | vers1)) { | 474 | vers1)) { |
475 | mutex_lock(&p_dev->socket->ops_mutex); | ||
469 | for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) { | 476 | for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) { |
470 | char *tmp; | 477 | char *tmp; |
471 | unsigned int length; | 478 | unsigned int length; |
@@ -484,6 +491,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
484 | p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], | 491 | p_dev->prod_id[i] = strncpy(p_dev->prod_id[i], |
485 | tmp, length); | 492 | tmp, length); |
486 | } | 493 | } |
494 | mutex_unlock(&p_dev->socket->ops_mutex); | ||
487 | } | 495 | } |
488 | 496 | ||
489 | kfree(vers1); | 497 | kfree(vers1); |
@@ -660,7 +668,7 @@ static void pcmcia_delayed_add_device(struct work_struct *work) | |||
660 | pcmcia_device_add(s, mfc_pfc); | 668 | pcmcia_device_add(s, mfc_pfc); |
661 | } | 669 | } |
662 | 670 | ||
663 | static int pcmcia_requery(struct device *dev, void * _data) | 671 | static int pcmcia_requery_callback(struct device *dev, void * _data) |
664 | { | 672 | { |
665 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 673 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
666 | if (!p_dev->dev.driver) { | 674 | if (!p_dev->dev.driver) { |
@@ -671,44 +679,57 @@ static int pcmcia_requery(struct device *dev, void * _data) | |||
671 | return 0; | 679 | return 0; |
672 | } | 680 | } |
673 | 681 | ||
674 | static void pcmcia_bus_rescan(struct pcmcia_socket *skt, int new_cis) | 682 | static void pcmcia_requery(struct pcmcia_socket *s) |
675 | { | 683 | { |
676 | int no_devices = 0; | 684 | int present; |
677 | int ret = 0; | ||
678 | |||
679 | /* must be called with skt_mutex held */ | ||
680 | dev_dbg(&skt->dev, "re-scanning socket %d\n", skt->sock); | ||
681 | 685 | ||
682 | mutex_lock(&skt->ops_mutex); | 686 | mutex_lock(&s->ops_mutex); |
683 | if (list_empty(&skt->devices_list)) | 687 | present = s->pcmcia_state.present; |
684 | no_devices = 1; | 688 | mutex_unlock(&s->ops_mutex); |
685 | mutex_unlock(&skt->ops_mutex); | ||
686 | 689 | ||
687 | /* If this is because of a CIS override, start over */ | 690 | if (!present) |
688 | if (new_cis && !no_devices) | 691 | return; |
689 | pcmcia_card_remove(skt, NULL); | ||
690 | 692 | ||
691 | /* if no devices were added for this socket yet because of | 693 | if (s->functions == 0) { |
692 | * missing resource information or other trouble, we need to | 694 | pcmcia_card_add(s); |
693 | * do this now. */ | 695 | return; |
694 | if (no_devices || new_cis) { | ||
695 | ret = pcmcia_card_add(skt); | ||
696 | if (ret) | ||
697 | return; | ||
698 | } | 696 | } |
699 | 697 | ||
700 | /* some device information might have changed because of a CIS | 698 | /* some device information might have changed because of a CIS |
701 | * update or because we can finally read it correctly... so | 699 | * update or because we can finally read it correctly... so |
702 | * determine it again, overwriting old values if necessary. */ | 700 | * determine it again, overwriting old values if necessary. */ |
703 | bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery); | 701 | bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback); |
702 | |||
703 | /* if the CIS changed, we need to check whether the number of | ||
704 | * functions changed. */ | ||
705 | if (s->fake_cis) { | ||
706 | int old_funcs, new_funcs; | ||
707 | cistpl_longlink_mfc_t mfc; | ||
708 | |||
709 | /* does this cis override add or remove functions? */ | ||
710 | old_funcs = s->functions; | ||
711 | |||
712 | if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, | ||
713 | &mfc)) | ||
714 | new_funcs = mfc.nfn; | ||
715 | else | ||
716 | new_funcs = 1; | ||
717 | if (old_funcs > new_funcs) { | ||
718 | pcmcia_card_remove(s, NULL); | ||
719 | pcmcia_card_add(s); | ||
720 | } else if (new_funcs > old_funcs) { | ||
721 | s->functions = new_funcs; | ||
722 | pcmcia_device_add(s, 1); | ||
723 | } | ||
724 | } | ||
704 | 725 | ||
705 | /* we re-scan all devices, not just the ones connected to this | 726 | /* we re-scan all devices, not just the ones connected to this |
706 | * socket. This does not matter, though. */ | 727 | * socket. This does not matter, though. */ |
707 | ret = bus_rescan_devices(&pcmcia_bus_type); | 728 | if (bus_rescan_devices(&pcmcia_bus_type)) |
708 | if (ret) | 729 | dev_warn(&s->dev, "rescanning the bus failed\n"); |
709 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed\n"); | ||
710 | } | 730 | } |
711 | 731 | ||
732 | |||
712 | #ifdef CONFIG_PCMCIA_LOAD_CIS | 733 | #ifdef CONFIG_PCMCIA_LOAD_CIS |
713 | 734 | ||
714 | /** | 735 | /** |
@@ -1085,7 +1106,6 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | |||
1085 | struct device_attribute *attr, const char *buf, size_t count) | 1106 | struct device_attribute *attr, const char *buf, size_t count) |
1086 | { | 1107 | { |
1087 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1108 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1088 | int ret; | ||
1089 | 1109 | ||
1090 | if (!count) | 1110 | if (!count) |
1091 | return -EINVAL; | 1111 | return -EINVAL; |
@@ -1093,11 +1113,7 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | |||
1093 | mutex_lock(&p_dev->socket->ops_mutex); | 1113 | mutex_lock(&p_dev->socket->ops_mutex); |
1094 | p_dev->allow_func_id_match = 1; | 1114 | p_dev->allow_func_id_match = 1; |
1095 | mutex_unlock(&p_dev->socket->ops_mutex); | 1115 | mutex_unlock(&p_dev->socket->ops_mutex); |
1096 | 1116 | pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY); | |
1097 | ret = bus_rescan_devices(&pcmcia_bus_type); | ||
1098 | if (ret) | ||
1099 | printk(KERN_INFO "pcmcia: bus_rescan_devices failed after " | ||
1100 | "allowing func_id matches\n"); | ||
1101 | 1117 | ||
1102 | return count; | 1118 | return count; |
1103 | } | 1119 | } |
@@ -1359,7 +1375,7 @@ EXPORT_SYMBOL(pcmcia_dev_present); | |||
1359 | static struct pcmcia_callback pcmcia_bus_callback = { | 1375 | static struct pcmcia_callback pcmcia_bus_callback = { |
1360 | .owner = THIS_MODULE, | 1376 | .owner = THIS_MODULE, |
1361 | .event = ds_event, | 1377 | .event = ds_event, |
1362 | .requery = pcmcia_bus_rescan, | 1378 | .requery = pcmcia_requery, |
1363 | .validate = pccard_validate_cis, | 1379 | .validate = pccard_validate_cis, |
1364 | .suspend = pcmcia_bus_suspend, | 1380 | .suspend = pcmcia_bus_suspend, |
1365 | .resume = pcmcia_bus_resume, | 1381 | .resume = pcmcia_bus_resume, |