Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
0004  *  Loongson PCH MSI support
0005  */
0006 
0007 #define pr_fmt(fmt) "pch-msi: " fmt
0008 
0009 #include <linux/irqchip.h>
0010 #include <linux/msi.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/of_irq.h>
0014 #include <linux/of_pci.h>
0015 #include <linux/pci.h>
0016 #include <linux/slab.h>
0017 
0018 static int nr_pics;
0019 
0020 struct pch_msi_data {
0021     struct mutex    msi_map_lock;
0022     phys_addr_t doorbell;
0023     u32     irq_first;  /* The vector number that MSIs starts */
0024     u32     num_irqs;   /* The number of vectors for MSIs */
0025     unsigned long   *msi_map;
0026 };
0027 
0028 static struct fwnode_handle *pch_msi_handle[MAX_IO_PICS];
0029 
0030 static void pch_msi_mask_msi_irq(struct irq_data *d)
0031 {
0032     pci_msi_mask_irq(d);
0033     irq_chip_mask_parent(d);
0034 }
0035 
0036 static void pch_msi_unmask_msi_irq(struct irq_data *d)
0037 {
0038     irq_chip_unmask_parent(d);
0039     pci_msi_unmask_irq(d);
0040 }
0041 
0042 static struct irq_chip pch_msi_irq_chip = {
0043     .name           = "PCH PCI MSI",
0044     .irq_mask       = pch_msi_mask_msi_irq,
0045     .irq_unmask     = pch_msi_unmask_msi_irq,
0046     .irq_ack        = irq_chip_ack_parent,
0047     .irq_set_affinity   = irq_chip_set_affinity_parent,
0048 };
0049 
0050 static int pch_msi_allocate_hwirq(struct pch_msi_data *priv, int num_req)
0051 {
0052     int first;
0053 
0054     mutex_lock(&priv->msi_map_lock);
0055 
0056     first = bitmap_find_free_region(priv->msi_map, priv->num_irqs,
0057                     get_count_order(num_req));
0058     if (first < 0) {
0059         mutex_unlock(&priv->msi_map_lock);
0060         return -ENOSPC;
0061     }
0062 
0063     mutex_unlock(&priv->msi_map_lock);
0064 
0065     return priv->irq_first + first;
0066 }
0067 
0068 static void pch_msi_free_hwirq(struct pch_msi_data *priv,
0069                 int hwirq, int num_req)
0070 {
0071     int first = hwirq - priv->irq_first;
0072 
0073     mutex_lock(&priv->msi_map_lock);
0074     bitmap_release_region(priv->msi_map, first, get_count_order(num_req));
0075     mutex_unlock(&priv->msi_map_lock);
0076 }
0077 
0078 static void pch_msi_compose_msi_msg(struct irq_data *data,
0079                     struct msi_msg *msg)
0080 {
0081     struct pch_msi_data *priv = irq_data_get_irq_chip_data(data);
0082 
0083     msg->address_hi = upper_32_bits(priv->doorbell);
0084     msg->address_lo = lower_32_bits(priv->doorbell);
0085     msg->data = data->hwirq;
0086 }
0087 
0088 static struct msi_domain_info pch_msi_domain_info = {
0089     .flags  = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
0090           MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
0091     .chip   = &pch_msi_irq_chip,
0092 };
0093 
0094 static struct irq_chip middle_irq_chip = {
0095     .name           = "PCH MSI",
0096     .irq_mask       = irq_chip_mask_parent,
0097     .irq_unmask     = irq_chip_unmask_parent,
0098     .irq_ack        = irq_chip_ack_parent,
0099     .irq_set_affinity   = irq_chip_set_affinity_parent,
0100     .irq_compose_msi_msg    = pch_msi_compose_msi_msg,
0101 };
0102 
0103 static int pch_msi_parent_domain_alloc(struct irq_domain *domain,
0104                     unsigned int virq, int hwirq)
0105 {
0106     struct irq_fwspec fwspec;
0107 
0108     fwspec.fwnode = domain->parent->fwnode;
0109     fwspec.param_count = 1;
0110     fwspec.param[0] = hwirq;
0111 
0112     return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
0113 }
0114 
0115 static int pch_msi_middle_domain_alloc(struct irq_domain *domain,
0116                        unsigned int virq,
0117                        unsigned int nr_irqs, void *args)
0118 {
0119     struct pch_msi_data *priv = domain->host_data;
0120     int hwirq, err, i;
0121 
0122     hwirq = pch_msi_allocate_hwirq(priv, nr_irqs);
0123     if (hwirq < 0)
0124         return hwirq;
0125 
0126     for (i = 0; i < nr_irqs; i++) {
0127         err = pch_msi_parent_domain_alloc(domain, virq + i, hwirq + i);
0128         if (err)
0129             goto err_hwirq;
0130 
0131         irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
0132                           &middle_irq_chip, priv);
0133     }
0134 
0135     return 0;
0136 
0137 err_hwirq:
0138     pch_msi_free_hwirq(priv, hwirq, nr_irqs);
0139     irq_domain_free_irqs_parent(domain, virq, i - 1);
0140 
0141     return err;
0142 }
0143 
0144 static void pch_msi_middle_domain_free(struct irq_domain *domain,
0145                        unsigned int virq,
0146                        unsigned int nr_irqs)
0147 {
0148     struct irq_data *d = irq_domain_get_irq_data(domain, virq);
0149     struct pch_msi_data *priv = irq_data_get_irq_chip_data(d);
0150 
0151     irq_domain_free_irqs_parent(domain, virq, nr_irqs);
0152     pch_msi_free_hwirq(priv, d->hwirq, nr_irqs);
0153 }
0154 
0155 static const struct irq_domain_ops pch_msi_middle_domain_ops = {
0156     .alloc  = pch_msi_middle_domain_alloc,
0157     .free   = pch_msi_middle_domain_free,
0158 };
0159 
0160 static int pch_msi_init_domains(struct pch_msi_data *priv,
0161                 struct irq_domain *parent,
0162                 struct fwnode_handle *domain_handle)
0163 {
0164     struct irq_domain *middle_domain, *msi_domain;
0165 
0166     middle_domain = irq_domain_create_linear(domain_handle,
0167                         priv->num_irqs,
0168                         &pch_msi_middle_domain_ops,
0169                         priv);
0170     if (!middle_domain) {
0171         pr_err("Failed to create the MSI middle domain\n");
0172         return -ENOMEM;
0173     }
0174 
0175     middle_domain->parent = parent;
0176     irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS);
0177 
0178     msi_domain = pci_msi_create_irq_domain(domain_handle,
0179                            &pch_msi_domain_info,
0180                            middle_domain);
0181     if (!msi_domain) {
0182         pr_err("Failed to create PCI MSI domain\n");
0183         irq_domain_remove(middle_domain);
0184         return -ENOMEM;
0185     }
0186 
0187     return 0;
0188 }
0189 
0190 static int pch_msi_init(phys_addr_t msg_address, int irq_base, int irq_count,
0191             struct irq_domain *parent_domain, struct fwnode_handle *domain_handle)
0192 {
0193     int ret;
0194     struct pch_msi_data *priv;
0195 
0196     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0197     if (!priv)
0198         return -ENOMEM;
0199 
0200     mutex_init(&priv->msi_map_lock);
0201 
0202     priv->doorbell = msg_address;
0203     priv->irq_first = irq_base;
0204     priv->num_irqs = irq_count;
0205 
0206     priv->msi_map = bitmap_zalloc(priv->num_irqs, GFP_KERNEL);
0207     if (!priv->msi_map)
0208         goto err_priv;
0209 
0210     pr_debug("Registering %d MSIs, starting at %d\n",
0211          priv->num_irqs, priv->irq_first);
0212 
0213     ret = pch_msi_init_domains(priv, parent_domain, domain_handle);
0214     if (ret)
0215         goto err_map;
0216 
0217     pch_msi_handle[nr_pics++] = domain_handle;
0218     return 0;
0219 
0220 err_map:
0221     bitmap_free(priv->msi_map);
0222 err_priv:
0223     kfree(priv);
0224 
0225     return -EINVAL;
0226 }
0227 
0228 #ifdef CONFIG_OF
0229 static int pch_msi_of_init(struct device_node *node, struct device_node *parent)
0230 {
0231     int err;
0232     int irq_base, irq_count;
0233     struct resource res;
0234     struct irq_domain *parent_domain;
0235 
0236     parent_domain = irq_find_host(parent);
0237     if (!parent_domain) {
0238         pr_err("Failed to find the parent domain\n");
0239         return -ENXIO;
0240     }
0241 
0242     if (of_address_to_resource(node, 0, &res)) {
0243         pr_err("Failed to allocate resource\n");
0244         return -EINVAL;
0245     }
0246 
0247     if (of_property_read_u32(node, "loongson,msi-base-vec", &irq_base)) {
0248         pr_err("Unable to parse MSI vec base\n");
0249         return -EINVAL;
0250     }
0251 
0252     if (of_property_read_u32(node, "loongson,msi-num-vecs", &irq_count)) {
0253         pr_err("Unable to parse MSI vec number\n");
0254         return -EINVAL;
0255     }
0256 
0257     err = pch_msi_init(res.start, irq_base, irq_count, parent_domain, of_node_to_fwnode(node));
0258     if (err < 0)
0259         return err;
0260 
0261     return 0;
0262 }
0263 
0264 IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init);
0265 #endif
0266 
0267 #ifdef CONFIG_ACPI
0268 struct fwnode_handle *get_pch_msi_handle(int pci_segment)
0269 {
0270     int i;
0271 
0272     for (i = 0; i < MAX_IO_PICS; i++) {
0273         if (msi_group[i].pci_segment == pci_segment)
0274             return pch_msi_handle[i];
0275     }
0276     return NULL;
0277 }
0278 
0279 int __init pch_msi_acpi_init(struct irq_domain *parent,
0280                     struct acpi_madt_msi_pic *acpi_pchmsi)
0281 {
0282     int ret;
0283     struct fwnode_handle *domain_handle;
0284 
0285     domain_handle = irq_domain_alloc_fwnode(&acpi_pchmsi->msg_address);
0286     ret = pch_msi_init(acpi_pchmsi->msg_address, acpi_pchmsi->start,
0287                 acpi_pchmsi->count, parent, domain_handle);
0288     if (ret < 0)
0289         irq_domain_free_fwnode(domain_handle);
0290 
0291     return ret;
0292 }
0293 #endif