aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 733b32fda390..46b9441b36bd 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1129,31 +1129,69 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
1129 return 0; 1129 return 0;
1130} 1130}
1131 1131
1132struct its_pci_alias {
1133 struct pci_dev *pdev;
1134 u32 dev_id;
1135 u32 count;
1136};
1137
1138static int its_pci_msi_vec_count(struct pci_dev *pdev)
1139{
1140 int msi, msix;
1141
1142 msi = max(pci_msi_vec_count(pdev), 0);
1143 msix = max(pci_msix_vec_count(pdev), 0);
1144
1145 return max(msi, msix);
1146}
1147
1148static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
1149{
1150 struct its_pci_alias *dev_alias = data;
1151
1152 dev_alias->dev_id = alias;
1153 if (pdev != dev_alias->pdev)
1154 dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
1155
1156 return 0;
1157}
1158
1132static int its_msi_prepare(struct irq_domain *domain, struct device *dev, 1159static int its_msi_prepare(struct irq_domain *domain, struct device *dev,
1133 int nvec, msi_alloc_info_t *info) 1160 int nvec, msi_alloc_info_t *info)
1134{ 1161{
1135 struct pci_dev *pdev; 1162 struct pci_dev *pdev;
1136 struct its_node *its; 1163 struct its_node *its;
1137 u32 dev_id;
1138 struct its_device *its_dev; 1164 struct its_device *its_dev;
1165 struct its_pci_alias dev_alias;
1139 1166
1140 if (!dev_is_pci(dev)) 1167 if (!dev_is_pci(dev))
1141 return -EINVAL; 1168 return -EINVAL;
1142 1169
1143 pdev = to_pci_dev(dev); 1170 pdev = to_pci_dev(dev);
1144 dev_id = PCI_DEVID(pdev->bus->number, pdev->devfn); 1171 dev_alias.pdev = pdev;
1172 dev_alias.count = nvec;
1173
1174 pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
1145 its = domain->parent->host_data; 1175 its = domain->parent->host_data;
1146 1176
1147 its_dev = its_find_device(its, dev_id); 1177 its_dev = its_find_device(its, dev_alias.dev_id);
1148 if (WARN_ON(its_dev)) 1178 if (its_dev) {
1149 return -EINVAL; 1179 /*
1180 * We already have seen this ID, probably through
1181 * another alias (PCI bridge of some sort). No need to
1182 * create the device.
1183 */
1184 dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id);
1185 goto out;
1186 }
1150 1187
1151 its_dev = its_create_device(its, dev_id, nvec); 1188 its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count);
1152 if (!its_dev) 1189 if (!its_dev)
1153 return -ENOMEM; 1190 return -ENOMEM;
1154 1191
1155 dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", nvec, ilog2(nvec)); 1192 dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n",
1156 1193 dev_alias.count, ilog2(dev_alias.count));
1194out:
1157 info->scratchpad[0].ptr = its_dev; 1195 info->scratchpad[0].ptr = its_dev;
1158 info->scratchpad[1].ptr = dev; 1196 info->scratchpad[1].ptr = dev;
1159 return 0; 1197 return 0;