diff options
Diffstat (limited to 'drivers/pci')
| -rw-r--r-- | drivers/pci/host/pcie-designware.c | 51 |
1 files changed, 7 insertions, 44 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 339296cbc823..dfed00aa3ac0 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c | |||
| @@ -196,30 +196,6 @@ void dw_pcie_msi_init(struct pcie_port *pp) | |||
| 196 | dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0); | 196 | dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0) | ||
| 200 | { | ||
| 201 | int flag = 1; | ||
| 202 | |||
| 203 | do { | ||
| 204 | pos = find_next_zero_bit(pp->msi_irq_in_use, | ||
| 205 | MAX_MSI_IRQS, pos); | ||
| 206 | /*if you have reached to the end then get out from here.*/ | ||
| 207 | if (pos == MAX_MSI_IRQS) | ||
| 208 | return -ENOSPC; | ||
| 209 | /* | ||
| 210 | * Check if this position is at correct offset.nvec is always a | ||
| 211 | * power of two. pos0 must be nvec bit aligned. | ||
| 212 | */ | ||
| 213 | if (pos % msgvec) | ||
| 214 | pos += msgvec - (pos % msgvec); | ||
| 215 | else | ||
| 216 | flag = 0; | ||
| 217 | } while (flag); | ||
| 218 | |||
| 219 | *pos0 = pos; | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) | 199 | static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) |
| 224 | { | 200 | { |
| 225 | unsigned int res, bit, val; | 201 | unsigned int res, bit, val; |
| @@ -238,13 +214,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, | |||
| 238 | 214 | ||
| 239 | for (i = 0; i < nvec; i++) { | 215 | for (i = 0; i < nvec; i++) { |
| 240 | irq_set_msi_desc_off(irq_base, i, NULL); | 216 | irq_set_msi_desc_off(irq_base, i, NULL); |
| 241 | clear_bit(pos + i, pp->msi_irq_in_use); | ||
| 242 | /* Disable corresponding interrupt on MSI controller */ | 217 | /* Disable corresponding interrupt on MSI controller */ |
| 243 | if (pp->ops->msi_clear_irq) | 218 | if (pp->ops->msi_clear_irq) |
| 244 | pp->ops->msi_clear_irq(pp, pos + i); | 219 | pp->ops->msi_clear_irq(pp, pos + i); |
| 245 | else | 220 | else |
| 246 | dw_pcie_msi_clear_irq(pp, pos + i); | 221 | dw_pcie_msi_clear_irq(pp, pos + i); |
| 247 | } | 222 | } |
| 223 | |||
| 224 | bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec)); | ||
| 248 | } | 225 | } |
| 249 | 226 | ||
| 250 | static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) | 227 | static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) |
| @@ -260,26 +237,13 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) | |||
| 260 | 237 | ||
| 261 | static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) | 238 | static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) |
| 262 | { | 239 | { |
| 263 | int irq, pos0, pos1, i; | 240 | int irq, pos0, i; |
| 264 | struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); | 241 | struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); |
| 265 | 242 | ||
| 266 | pos0 = find_first_zero_bit(pp->msi_irq_in_use, | 243 | pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS, |
| 267 | MAX_MSI_IRQS); | 244 | order_base_2(no_irqs)); |
| 268 | if (pos0 % no_irqs) { | 245 | if (pos0 < 0) |
| 269 | if (find_valid_pos0(pp, no_irqs, pos0, &pos0)) | 246 | goto no_valid_irq; |
| 270 | goto no_valid_irq; | ||
| 271 | } | ||
| 272 | if (no_irqs > 1) { | ||
| 273 | pos1 = find_next_bit(pp->msi_irq_in_use, | ||
| 274 | MAX_MSI_IRQS, pos0); | ||
| 275 | /* there must be nvec number of consecutive free bits */ | ||
| 276 | while ((pos1 - pos0) < no_irqs) { | ||
| 277 | if (find_valid_pos0(pp, no_irqs, pos1, &pos0)) | ||
| 278 | goto no_valid_irq; | ||
| 279 | pos1 = find_next_bit(pp->msi_irq_in_use, | ||
| 280 | MAX_MSI_IRQS, pos0); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | 247 | ||
| 284 | irq = irq_find_mapping(pp->irq_domain, pos0); | 248 | irq = irq_find_mapping(pp->irq_domain, pos0); |
| 285 | if (!irq) | 249 | if (!irq) |
| @@ -297,7 +261,6 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) | |||
| 297 | clear_irq_range(pp, irq, i, pos0); | 261 | clear_irq_range(pp, irq, i, pos0); |
| 298 | goto no_valid_irq; | 262 | goto no_valid_irq; |
| 299 | } | 263 | } |
| 300 | set_bit(pos0 + i, pp->msi_irq_in_use); | ||
| 301 | /*Enable corresponding interrupt in MSI interrupt controller */ | 264 | /*Enable corresponding interrupt in MSI interrupt controller */ |
| 302 | if (pp->ops->msi_set_irq) | 265 | if (pp->ops->msi_set_irq) |
| 303 | pp->ops->msi_set_irq(pp, pos0 + i); | 266 | pp->ops->msi_set_irq(pp, pos0 + i); |
