Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pcmcia: setup IRQ to be used by PCMCIA drivers at card insert

Setup the IRQ to be used by PCMCIA drivers already during the device
registration stage, making use of a new function pcmcia_setup_irq().
This will allow us to get rid of quite a lot of indirection in the
future.

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>

+141 -95
+2
drivers/pcmcia/cs_internal.h
··· 149 149 int low, 150 150 struct pcmcia_socket *s); 151 151 152 + void pcmcia_cleanup_irq(struct pcmcia_socket *s); 153 + int pcmcia_setup_irq(struct pcmcia_device *p_dev); 152 154 153 155 /* cistpl.c */ 154 156 extern struct bin_attribute pccard_cis_attr;
+11 -4
drivers/pcmcia/ds.c
··· 546 546 p_dev->function_config = tmp_dev->function_config; 547 547 p_dev->io = tmp_dev->io; 548 548 p_dev->irq = tmp_dev->irq; 549 + p_dev->irq_v = tmp_dev->irq_v; 549 550 kref_get(&p_dev->function_config->ref); 550 551 } 551 552 552 553 /* Add to the list in pcmcia_bus_socket */ 553 554 list_add(&p_dev->socket_device_list, &s->devices_list); 554 555 555 - mutex_unlock(&s->ops_mutex); 556 + if (pcmcia_setup_irq(p_dev)) 557 + dev_warn(&p_dev->dev, 558 + "IRQ setup failed -- device might not work\n"); 556 559 557 560 if (!p_dev->function_config) { 558 561 dev_dbg(&p_dev->dev, "creating config_t\n"); 559 562 p_dev->function_config = kzalloc(sizeof(struct config_t), 560 563 GFP_KERNEL); 561 - if (!p_dev->function_config) 564 + if (!p_dev->function_config) { 565 + mutex_unlock(&s->ops_mutex); 562 566 goto err_unreg; 567 + } 563 568 kref_init(&p_dev->function_config->ref); 564 569 } 570 + mutex_unlock(&s->ops_mutex); 565 571 566 572 dev_printk(KERN_NOTICE, &p_dev->dev, 567 - "pcmcia: registering new device %s\n", 568 - p_dev->devname); 573 + "pcmcia: registering new device %s (IRQ: %d)\n", 574 + p_dev->devname, p_dev->irq_v); 569 575 570 576 pcmcia_device_query(p_dev); 571 577 ··· 1264 1258 handle_event(skt, event); 1265 1259 mutex_lock(&s->ops_mutex); 1266 1260 destroy_cis_cache(s); 1261 + pcmcia_cleanup_irq(s); 1267 1262 mutex_unlock(&s->ops_mutex); 1268 1263 break; 1269 1264
+125 -91
drivers/pcmcia/pcmcia_resource.c
··· 23 23 #include <linux/netdevice.h> 24 24 #include <linux/slab.h> 25 25 26 + #include <asm/irq.h> 27 + 26 28 #include <pcmcia/cs_types.h> 27 29 #include <pcmcia/ss.h> 28 30 #include <pcmcia/cs.h> ··· 39 37 static int io_speed; 40 38 module_param(io_speed, int, 0444); 41 39 42 - 43 - #ifdef CONFIG_PCMCIA_PROBE 44 - #include <asm/irq.h> 45 - /* mask of IRQs already reserved by other cards, we should avoid using them */ 46 - static u8 pcmcia_used_irq[NR_IRQS]; 47 - #endif 48 40 49 41 static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, 50 42 unsigned long end, struct pcmcia_socket *s) ··· 436 440 } 437 441 if (--s->irq.Config == 0) { 438 442 c->state &= ~CONFIG_IRQ_REQ; 439 - s->irq.AssignedIRQ = 0; 440 443 } 441 444 442 445 if (req->Handler) 443 446 free_irq(req->AssignedIRQ, p_dev->priv); 444 447 445 - #ifdef CONFIG_PCMCIA_PROBE 446 - pcmcia_used_irq[req->AssignedIRQ]--; 447 - #endif 448 448 ret = 0; 449 449 450 450 out: ··· 691 699 /** pcmcia_request_irq 692 700 * 693 701 * Request_irq() reserves an irq for this client. 694 - * 695 - * Also, since Linux only reserves irq's when they are actually 696 - * hooked, we don't guarantee that an irq will still be available 697 - * when the configuration is locked. Now that I think about it, 698 - * there might be a way to fix this using a dummy handler. 699 702 */ 700 - 701 - #ifdef CONFIG_PCMCIA_PROBE 702 - static irqreturn_t test_action(int cpl, void *dev_id) 703 - { 704 - return IRQ_NONE; 705 - } 706 - #endif 707 703 708 704 int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) 709 705 { 710 706 struct pcmcia_socket *s = p_dev->socket; 711 707 config_t *c; 712 - int ret = -EINVAL, irq = 0; 713 - int type; 708 + int ret = -EINVAL, irq = p_dev->irq_v; 709 + int type = IRQF_SHARED; 714 710 715 711 mutex_lock(&s->ops_mutex); 716 712 ··· 716 736 goto out; 717 737 } 718 738 719 - /* Decide what type of interrupt we are registering */ 720 - type = 0; 721 - if (s->functions > 1) /* All of this ought to be handled higher up */ 722 - type = IRQF_SHARED; 723 - else if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) 724 - type = IRQF_SHARED; 725 - else 726 - printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n"); 727 - 728 - /* If the interrupt is already assigned, it must be the same */ 729 - if (s->irq.AssignedIRQ != 0) 730 - irq = s->irq.AssignedIRQ; 731 - 732 - #ifdef CONFIG_PCMCIA_PROBE 733 739 if (!irq) { 734 - int try; 735 - u32 mask = s->irq_mask; 736 - void *data = p_dev; /* something unique to this device */ 737 - 738 - for (try = 0; try < 64; try++) { 739 - irq = try % 32; 740 - 741 - /* marked as available by driver, and not blocked by userspace? */ 742 - if (!((mask >> irq) & 1)) 743 - continue; 744 - 745 - /* avoid an IRQ which is already used by a PCMCIA card */ 746 - if ((try < 32) && pcmcia_used_irq[irq]) 747 - continue; 748 - 749 - /* register the correct driver, if possible, of check whether 750 - * registering a dummy handle works, i.e. if the IRQ isn't 751 - * marked as used by the kernel resource management core */ 752 - ret = request_irq(irq, 753 - (req->Handler) ? req->Handler : test_action, 754 - type, 755 - p_dev->devname, 756 - (req->Handler) ? p_dev->priv : data); 757 - if (!ret) { 758 - if (!req->Handler) 759 - free_irq(irq, data); 760 - break; 761 - } 762 - } 763 - } 764 - #endif 765 - /* only assign PCI irq if no IRQ already assigned */ 766 - if (ret && !s->irq.AssignedIRQ) { 767 - if (!s->pci_irq) { 768 - dev_printk(KERN_INFO, &s->dev, "no IRQ found\n"); 769 - goto out; 770 - } 771 - type = IRQF_SHARED; 772 - irq = s->pci_irq; 740 + dev_dbg(&s->dev, "no IRQ available\n"); 741 + goto out; 773 742 } 774 743 775 - if (ret && req->Handler) { 744 + if (!(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) { 745 + req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING; 746 + dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: " 747 + "request for exclusive IRQ could not be fulfilled.\n"); 748 + dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver " 749 + "needs updating to supported shared IRQ lines.\n"); 750 + } 751 + 752 + if (req->Handler) { 776 753 ret = request_irq(irq, req->Handler, type, 777 754 p_dev->devname, p_dev->priv); 778 755 if (ret) { ··· 739 802 } 740 803 } 741 804 742 - /* Make sure the fact the request type was overridden is passed back */ 743 - if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) { 744 - req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING; 745 - dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: " 746 - "request for exclusive IRQ could not be fulfilled.\n"); 747 - dev_printk(KERN_WARNING, &p_dev->dev, "pcmcia: the driver " 748 - "needs updating to supported shared IRQ lines.\n"); 749 - } 750 805 c->irq.Attributes = req->Attributes; 751 - s->irq.AssignedIRQ = req->AssignedIRQ = irq; 806 + req->AssignedIRQ = irq; 752 807 s->irq.Config++; 753 808 754 809 c->state |= CONFIG_IRQ_REQ; 755 810 p_dev->_irq = 1; 756 - 757 - #ifdef CONFIG_PCMCIA_PROBE 758 - pcmcia_used_irq[irq]++; 759 - #endif 760 811 761 812 ret = 0; 762 813 out: ··· 752 827 return ret; 753 828 } /* pcmcia_request_irq */ 754 829 EXPORT_SYMBOL(pcmcia_request_irq); 830 + 831 + 832 + #ifdef CONFIG_PCMCIA_PROBE 833 + 834 + /* mask of IRQs already reserved by other cards, we should avoid using them */ 835 + static u8 pcmcia_used_irq[NR_IRQS]; 836 + 837 + static irqreturn_t test_action(int cpl, void *dev_id) 838 + { 839 + return IRQ_NONE; 840 + } 841 + 842 + /** 843 + * pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used 844 + * @p_dev - the associated PCMCIA device 845 + * 846 + * locking note: must be called with ops_mutex locked. 847 + */ 848 + static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) 849 + { 850 + struct pcmcia_socket *s = p_dev->socket; 851 + unsigned int try, irq; 852 + u32 mask = s->irq_mask; 853 + int ret = -ENODEV; 854 + 855 + for (try = 0; try < 64; try++) { 856 + irq = try % 32; 857 + 858 + /* marked as available by driver, not blocked by userspace? */ 859 + if (!((mask >> irq) & 1)) 860 + continue; 861 + 862 + /* avoid an IRQ which is already used by another PCMCIA card */ 863 + if ((try < 32) && pcmcia_used_irq[irq]) 864 + continue; 865 + 866 + /* register the correct driver, if possible, to check whether 867 + * registering a dummy handle works, i.e. if the IRQ isn't 868 + * marked as used by the kernel resource management core */ 869 + ret = request_irq(irq, test_action, type, p_dev->devname, 870 + p_dev); 871 + if (!ret) { 872 + free_irq(irq, p_dev); 873 + p_dev->irq_v = s->irq.AssignedIRQ = irq; 874 + pcmcia_used_irq[irq]++; 875 + break; 876 + } 877 + } 878 + 879 + return ret; 880 + } 881 + 882 + void pcmcia_cleanup_irq(struct pcmcia_socket *s) 883 + { 884 + pcmcia_used_irq[s->irq.AssignedIRQ]--; 885 + s->irq.AssignedIRQ = 0; 886 + } 887 + 888 + #else /* CONFIG_PCMCIA_PROBE */ 889 + 890 + static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type) 891 + { 892 + return -EINVAL; 893 + } 894 + 895 + void pcmcia_cleanup_irq(struct pcmcia_socket *s) 896 + { 897 + s->irq.AssignedIRQ = 0; 898 + return; 899 + } 900 + 901 + #endif /* CONFIG_PCMCIA_PROBE */ 902 + 903 + 904 + /** 905 + * pcmcia_setup_irq() - determine IRQ to be used for device 906 + * @p_dev - the associated PCMCIA device 907 + * 908 + * locking note: must be called with ops_mutex locked. 909 + */ 910 + int pcmcia_setup_irq(struct pcmcia_device *p_dev) 911 + { 912 + struct pcmcia_socket *s = p_dev->socket; 913 + 914 + if (p_dev->irq_v) 915 + return 0; 916 + 917 + /* already assigned? */ 918 + if (s->irq.AssignedIRQ) { 919 + p_dev->irq_v = s->irq.AssignedIRQ; 920 + return 0; 921 + } 922 + 923 + /* prefer an exclusive ISA irq */ 924 + if (!pcmcia_setup_isa_irq(p_dev, 0)) 925 + return 0; 926 + 927 + /* but accept a shared ISA irq */ 928 + if (!pcmcia_setup_isa_irq(p_dev, IRQF_SHARED)) 929 + return 0; 930 + 931 + /* but use the PCI irq otherwise */ 932 + if (s->pci_irq) { 933 + p_dev->irq_v = s->irq.AssignedIRQ = s->pci_irq; 934 + return 0; 935 + } 936 + 937 + return -EINVAL; 938 + } 755 939 756 940 757 941 /** pcmcia_request_window
+3
include/pcmcia/ds.h
··· 95 95 config_req_t conf; 96 96 window_handle_t win; 97 97 98 + /* device setup */ 99 + unsigned int irq_v; /* do not use directly yet */ 100 + 98 101 /* Is the device suspended? */ 99 102 u16 suspended:1; 100 103