| @@ -828,23 +828,74 @@ static int msi_handle_pci_fail(struct irq_domain *domain, struct msi_desc *desc, · 827 unmodified lines |
| 828 | 828 | return allocated ? allocated : -ENOSPC; |
| 829 | 829 | } |
| 830 | 830 | |
| 831 | +#define VIRQ_CAN_RESERVE 0x01 |
| 832 | +#define VIRQ_ACTIVATE 0x02 |
| 833 | +#define VIRQ_NOMASK_QUIRK 0x04 |
| 834 | + |
| 835 | +static int msi_init_virq(struct irq_domain *domain, int virq, unsigned int vflags) |
| 836 | +{ |
| 837 | + struct irq_data *irqd = irq_domain_get_irq_data(domain, virq); |
| 838 | + int ret; |
| 839 | + |
| 840 | + if (!(vflags & VIRQ_CAN_RESERVE)) { |
| 841 | + irqd_clr_can_reserve(irqd); |
| 842 | + if (vflags & VIRQ_NOMASK_QUIRK) |
| 843 | + irqd_set_msi_nomask_quirk(irqd); |
| 844 | + } |
| 845 | + |
| 846 | + if (!(vflags & VIRQ_ACTIVATE)) |
| 847 | + return 0; |
| 848 | + |
| 849 | + ret = irq_domain_activate_irq(irqd, vflags & VIRQ_CAN_RESERVE); |
| 850 | + if (ret) |
| 851 | + return ret; |
| 852 | + /* |
| 853 | + * If the interrupt uses reservation mode, clear the activated bit |
| 854 | + * so request_irq() will assign the final vector. |
| 855 | + */ |
| 856 | + if (vflags & VIRQ_CAN_RESERVE) |
| 857 | + irqd_clr_activated(irqd); |
| 858 | + return 0; |
| 859 | +} |
| 860 | + |
| 831 | 861 | int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, |
| 832 | 862 | int nvec) |
| 833 | 863 | { |
| 834 | 864 | struct msi_domain_info *info = domain->host_data; |
| 835 | 865 | struct msi_domain_ops *ops = info->ops; |
| 836 | | − struct irq_data *irq_data; |
| 837 | | − struct msi_desc *desc; |
| 838 | 866 | msi_alloc_info_t arg = { }; |
| 867 | + unsigned int vflags = 0; |
| 868 | + struct msi_desc *desc; |
| 839 | 869 | int allocated = 0; |
| 840 | 870 | int i, ret, virq; |
| 841 | | − bool can_reserve; |
| 842 | 871 | |
| 843 | 872 | ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg); |
| 844 | 873 | if (ret) |
| 845 | 874 | return ret; |
| 846 | 875 | |
| 847 | | − for_each_msi_entry(desc, dev) { |
| 876 | + /* |
| 877 | + * This flag is set by the PCI layer as we need to activate |
| 878 | + * the MSI entries before the PCI layer enables MSI in the |
| 879 | + * card. Otherwise the card latches a random msi message. |
| 880 | + */ |
| 881 | + if (info->flags & MSI_FLAG_ACTIVATE_EARLY) |
| 882 | + vflags |= VIRQ_ACTIVATE; |
| 883 | + |
| 884 | + /* |
| 885 | + * Interrupt can use a reserved vector and will not occupy |
| 886 | + * a real device vector until the interrupt is requested. |
| 887 | + */ |
| 888 | + if (msi_check_reservation_mode(domain, info, dev)) { |
| 889 | + vflags |= VIRQ_CAN_RESERVE; |
| 890 | + /* |
| 891 | + * MSI affinity setting requires a special quirk (X86) when |
| 892 | + * reservation mode is active. |
| 893 | + */ |
| 894 | + if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK) |
| 895 | + vflags |= VIRQ_NOMASK_QUIRK; |
| 896 | + } |
| 897 | + |
| 898 | + msi_for_each_desc(desc, dev, MSI_DESC_NOTASSOCIATED) { |
| 848 | 899 | ops->set_desc(&arg, desc); |
| 849 | 900 | |
| 850 | 901 | virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used, |
| @@ -856,49 +907,12 @@ int __msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, · 5 unmodified lines |
| 856 | 907 | for (i = 0; i < desc->nvec_used; i++) { |
| 857 | 908 | irq_set_msi_desc_off(virq, i, desc); |
| 858 | 909 | irq_debugfs_copy_devname(virq + i, dev); |
| 910 | + ret = msi_init_virq(domain, virq + i, vflags); |
| 911 | + if (ret) |
| 912 | + return ret; |
| 859 | 913 | } |
| 860 | 914 | allocated++; |
| 861 | 915 | } |
| 862 | | − |
| 863 | | − can_reserve = msi_check_reservation_mode(domain, info, dev); |
| 864 | | − |
| 865 | | − /* |
| 866 | | − * This flag is set by the PCI layer as we need to activate |
| 867 | | − * the MSI entries before the PCI layer enables MSI in the |
| 868 | | − * card. Otherwise the card latches a random msi message. |
| 869 | | − */ |
| 870 | | − if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY)) |
| 871 | | − goto skip_activate; |
| 872 | | − |
| 873 | | − for_each_msi_vector(desc, i, dev) { |
| 874 | | − if (desc->irq == i) { |
| 875 | | − virq = desc->irq; |
| 876 | | − dev_dbg(dev, "irq [%d-%d] for MSI\n", |
| 877 | | − virq, virq + desc->nvec_used - 1); |
| 878 | | − } |
| 879 | | − |
| 880 | | − irq_data = irq_domain_get_irq_data(domain, i); |
| 881 | | − if (!can_reserve) { |
| 882 | | − irqd_clr_can_reserve(irq_data); |
| 883 | | − if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK) |
| 884 | | − irqd_set_msi_nomask_quirk(irq_data); |
| 885 | | − } |
| 886 | | − ret = irq_domain_activate_irq(irq_data, can_reserve); |
| 887 | | − if (ret) |
| 888 | | − return ret; |
| 889 | | − } |
| 890 | | − |
| 891 | | −skip_activate: |
| 892 | | − /* |
| 893 | | − * If these interrupts use reservation mode, clear the activated bit |
| 894 | | − * so request_irq() will assign the final vector. |
| 895 | | − */ |
| 896 | | − if (can_reserve) { |
| 897 | | − for_each_msi_vector(desc, i, dev) { |
| 898 | | − irq_data = irq_domain_get_irq_data(domain, i); |
| 899 | | − irqd_clr_activated(irq_data); |
| 900 | | − } |
| 901 | | − } |
| 902 | 916 | return 0; |
| 903 | 917 | } |
| 904 | 918 | |
| @@ -976,26 +990,21 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, int nve · 71 unmodified lines |
| 976 | 990 | |
| 977 | 991 | void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev) |
| 978 | 992 | { |
| 979 | | − struct irq_data *irq_data; |
| 993 | + struct irq_data *irqd; |
| 980 | 994 | struct msi_desc *desc; |
| 981 | 995 | int i; |
| 982 | 996 | |
| 983 | | − for_each_msi_vector(desc, i, dev) { |
| 984 | | − irq_data = irq_domain_get_irq_data(domain, i); |
| 985 | | − if (irqd_is_activated(irq_data)) |
| 986 | | − irq_domain_deactivate_irq(irq_data); |
| 987 | | − } |
| 988 | | − |
| 989 | | − for_each_msi_entry(desc, dev) { |
| 990 | | − /* |
| 991 | | − * We might have failed to allocate an MSI early |
| 992 | | − * enough that there is no IRQ associated to this |
| 993 | | − * entry. If that's the case, don't do anything. |
| 994 | | − */ |
| 995 | | − if (desc->irq) { |
| 996 | | − irq_domain_free_irqs(desc->irq, desc->nvec_used); |
| 997 | | − desc->irq = 0; |
| 997 | + /* Only handle MSI entries which have an interrupt associated */ |
| 998 | + msi_for_each_desc(desc, dev, MSI_DESC_ASSOCIATED) { |
| 999 | + /* Make sure all interrupts are deactivated */ |
| 1000 | + for (i = 0; i < desc->nvec_used; i++) { |
| 1001 | + irqd = irq_domain_get_irq_data(domain, desc->irq + i); |
| 1002 | + if (irqd && irqd_is_activated(irqd)) |
| 1003 | + irq_domain_deactivate_irq(irqd); |
| 998 | 1004 | } |
| 1005 | + |
| 1006 | + irq_domain_free_irqs(desc->irq, desc->nvec_used); |
| 1007 | + desc->irq = 0; |
| 999 | 1008 | } |
| 1000 | 1009 | } |
| 1001 | 1010 | |