diff options
| -rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 54 |
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 | ||
| 1132 | struct its_pci_alias { | ||
| 1133 | struct pci_dev *pdev; | ||
| 1134 | u32 dev_id; | ||
| 1135 | u32 count; | ||
| 1136 | }; | ||
| 1137 | |||
| 1138 | static 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 | |||
| 1148 | static 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 | |||
| 1132 | static int its_msi_prepare(struct irq_domain *domain, struct device *dev, | 1159 | static 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)); | |
| 1194 | out: | ||
| 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; |
