aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/host/pcie-designware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/host/pcie-designware.c')
-rw-r--r--drivers/pci/host/pcie-designware.c91
1 files changed, 59 insertions, 32 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index e33b68be0391..17ce88f79d2b 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -74,7 +74,7 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
74 return sys->private_data; 74 return sys->private_data;
75} 75}
76 76
77int cfg_read(void __iomem *addr, int where, int size, u32 *val) 77int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
78{ 78{
79 *val = readl(addr); 79 *val = readl(addr);
80 80
@@ -88,7 +88,7 @@ int cfg_read(void __iomem *addr, int where, int size, u32 *val)
88 return PCIBIOS_SUCCESSFUL; 88 return PCIBIOS_SUCCESSFUL;
89} 89}
90 90
91int cfg_write(void __iomem *addr, int where, int size, u32 val) 91int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
92{ 92{
93 if (size == 4) 93 if (size == 4)
94 writel(val, addr); 94 writel(val, addr);
@@ -126,7 +126,8 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
126 if (pp->ops->rd_own_conf) 126 if (pp->ops->rd_own_conf)
127 ret = pp->ops->rd_own_conf(pp, where, size, val); 127 ret = pp->ops->rd_own_conf(pp, where, size, val);
128 else 128 else
129 ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); 129 ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
130 size, val);
130 131
131 return ret; 132 return ret;
132} 133}
@@ -139,8 +140,8 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
139 if (pp->ops->wr_own_conf) 140 if (pp->ops->wr_own_conf)
140 ret = pp->ops->wr_own_conf(pp, where, size, val); 141 ret = pp->ops->wr_own_conf(pp, where, size, val);
141 else 142 else
142 ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, 143 ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
143 val); 144 size, val);
144 145
145 return ret; 146 return ret;
146} 147}
@@ -167,11 +168,13 @@ void dw_handle_msi_irq(struct pcie_port *pp)
167 while ((pos = find_next_bit(&val, 32, pos)) != 32) { 168 while ((pos = find_next_bit(&val, 32, pos)) != 32) {
168 irq = irq_find_mapping(pp->irq_domain, 169 irq = irq_find_mapping(pp->irq_domain,
169 i * 32 + pos); 170 i * 32 + pos);
171 dw_pcie_wr_own_conf(pp,
172 PCIE_MSI_INTR0_STATUS + i * 12,
173 4, 1 << pos);
170 generic_handle_irq(irq); 174 generic_handle_irq(irq);
171 pos++; 175 pos++;
172 } 176 }
173 } 177 }
174 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
175 } 178 }
176} 179}
177 180
@@ -209,6 +212,23 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
209 return 0; 212 return 0;
210} 213}
211 214
215static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
216 unsigned int nvec, unsigned int pos)
217{
218 unsigned int i, res, bit, val;
219
220 for (i = 0; i < nvec; i++) {
221 irq_set_msi_desc_off(irq_base, i, NULL);
222 clear_bit(pos + i, pp->msi_irq_in_use);
223 /* Disable corresponding interrupt on MSI controller */
224 res = ((pos + i) / 32) * 12;
225 bit = (pos + i) % 32;
226 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
227 val &= ~(1 << bit);
228 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
229 }
230}
231
212static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) 232static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
213{ 233{
214 int res, bit, irq, pos0, pos1, i; 234 int res, bit, irq, pos0, pos1, i;
@@ -242,18 +262,25 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
242 if (!irq) 262 if (!irq)
243 goto no_valid_irq; 263 goto no_valid_irq;
244 264
245 i = 0; 265 /*
246 while (i < no_irqs) { 266 * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
267 * descs so there is no need to allocate descs here. We can therefore
268 * assume that if irq_find_mapping above returns non-zero, then the
269 * descs are also successfully allocated.
270 */
271
272 for (i = 0; i < no_irqs; i++) {
273 if (irq_set_msi_desc_off(irq, i, desc) != 0) {
274 clear_irq_range(pp, irq, i, pos0);
275 goto no_valid_irq;
276 }
247 set_bit(pos0 + i, pp->msi_irq_in_use); 277 set_bit(pos0 + i, pp->msi_irq_in_use);
248 irq_alloc_descs((irq + i), (irq + i), 1, 0);
249 irq_set_msi_desc(irq + i, desc);
250 /*Enable corresponding interrupt in MSI interrupt controller */ 278 /*Enable corresponding interrupt in MSI interrupt controller */
251 res = ((pos0 + i) / 32) * 12; 279 res = ((pos0 + i) / 32) * 12;
252 bit = (pos0 + i) % 32; 280 bit = (pos0 + i) % 32;
253 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); 281 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
254 val |= 1 << bit; 282 val |= 1 << bit;
255 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); 283 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
256 i++;
257 } 284 }
258 285
259 *pos = pos0; 286 *pos = pos0;
@@ -266,7 +293,7 @@ no_valid_irq:
266 293
267static void clear_irq(unsigned int irq) 294static void clear_irq(unsigned int irq)
268{ 295{
269 int res, bit, val, pos; 296 unsigned int pos, nvec;
270 struct irq_desc *desc; 297 struct irq_desc *desc;
271 struct msi_desc *msi; 298 struct msi_desc *msi;
272 struct pcie_port *pp; 299 struct pcie_port *pp;
@@ -281,18 +308,15 @@ static void clear_irq(unsigned int irq)
281 return; 308 return;
282 } 309 }
283 310
311 /* undo what was done in assign_irq */
284 pos = data->hwirq; 312 pos = data->hwirq;
313 nvec = 1 << msi->msi_attrib.multiple;
285 314
286 irq_free_desc(irq); 315 clear_irq_range(pp, irq, nvec, pos);
287
288 clear_bit(pos, pp->msi_irq_in_use);
289 316
290 /* Disable corresponding interrupt on MSI interrupt controller */ 317 /* all irqs cleared; reset attributes */
291 res = (pos / 32) * 12; 318 msi->irq = 0;
292 bit = pos % 32; 319 msi->msi_attrib.multiple = 0;
293 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
294 val &= ~(1 << bit);
295 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
296} 320}
297 321
298static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, 322static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
@@ -320,10 +344,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
320 if (irq < 0) 344 if (irq < 0)
321 return irq; 345 return irq;
322 346
323 msg_ctr &= ~PCI_MSI_FLAGS_QSIZE; 347 /*
324 msg_ctr |= msgvec << 4; 348 * write_msi_msg() will update PCI_MSI_FLAGS so there is
325 pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, 349 * no need to explicitly call pci_write_config_word().
326 msg_ctr); 350 */
327 desc->msi_attrib.multiple = msgvec; 351 desc->msi_attrib.multiple = msgvec;
328 352
329 msg.address_lo = virt_to_phys((void *)pp->msi_data); 353 msg.address_lo = virt_to_phys((void *)pp->msi_data);
@@ -394,6 +418,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
394 + global_io_offset); 418 + global_io_offset);
395 pp->config.io_size = resource_size(&pp->io); 419 pp->config.io_size = resource_size(&pp->io);
396 pp->config.io_bus_addr = range.pci_addr; 420 pp->config.io_bus_addr = range.pci_addr;
421 pp->io_base = range.cpu_addr;
397 } 422 }
398 if (restype == IORESOURCE_MEM) { 423 if (restype == IORESOURCE_MEM) {
399 of_pci_range_to_resource(&range, np, &pp->mem); 424 of_pci_range_to_resource(&range, np, &pp->mem);
@@ -419,7 +444,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
419 444
420 pp->cfg0_base = pp->cfg.start; 445 pp->cfg0_base = pp->cfg.start;
421 pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; 446 pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
422 pp->io_base = pp->io.start;
423 pp->mem_base = pp->mem.start; 447 pp->mem_base = pp->mem.start;
424 448
425 pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, 449 pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
@@ -551,11 +575,13 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
551 575
552 if (bus->parent->number == pp->root_bus_nr) { 576 if (bus->parent->number == pp->root_bus_nr) {
553 dw_pcie_prog_viewport_cfg0(pp, busdev); 577 dw_pcie_prog_viewport_cfg0(pp, busdev);
554 ret = cfg_read(pp->va_cfg0_base + address, where, size, val); 578 ret = dw_pcie_cfg_read(pp->va_cfg0_base + address, where, size,
579 val);
555 dw_pcie_prog_viewport_mem_outbound(pp); 580 dw_pcie_prog_viewport_mem_outbound(pp);
556 } else { 581 } else {
557 dw_pcie_prog_viewport_cfg1(pp, busdev); 582 dw_pcie_prog_viewport_cfg1(pp, busdev);
558 ret = cfg_read(pp->va_cfg1_base + address, where, size, val); 583 ret = dw_pcie_cfg_read(pp->va_cfg1_base + address, where, size,
584 val);
559 dw_pcie_prog_viewport_io_outbound(pp); 585 dw_pcie_prog_viewport_io_outbound(pp);
560 } 586 }
561 587
@@ -574,18 +600,19 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
574 600
575 if (bus->parent->number == pp->root_bus_nr) { 601 if (bus->parent->number == pp->root_bus_nr) {
576 dw_pcie_prog_viewport_cfg0(pp, busdev); 602 dw_pcie_prog_viewport_cfg0(pp, busdev);
577 ret = cfg_write(pp->va_cfg0_base + address, where, size, val); 603 ret = dw_pcie_cfg_write(pp->va_cfg0_base + address, where, size,
604 val);
578 dw_pcie_prog_viewport_mem_outbound(pp); 605 dw_pcie_prog_viewport_mem_outbound(pp);
579 } else { 606 } else {
580 dw_pcie_prog_viewport_cfg1(pp, busdev); 607 dw_pcie_prog_viewport_cfg1(pp, busdev);
581 ret = cfg_write(pp->va_cfg1_base + address, where, size, val); 608 ret = dw_pcie_cfg_write(pp->va_cfg1_base + address, where, size,
609 val);
582 dw_pcie_prog_viewport_io_outbound(pp); 610 dw_pcie_prog_viewport_io_outbound(pp);
583 } 611 }
584 612
585 return ret; 613 return ret;
586} 614}
587 615
588
589static int dw_pcie_valid_config(struct pcie_port *pp, 616static int dw_pcie_valid_config(struct pcie_port *pp,
590 struct pci_bus *bus, int dev) 617 struct pci_bus *bus, int dev)
591{ 618{
@@ -679,7 +706,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
679 706
680 if (global_io_offset < SZ_1M && pp->config.io_size > 0) { 707 if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
681 sys->io_offset = global_io_offset - pp->config.io_bus_addr; 708 sys->io_offset = global_io_offset - pp->config.io_bus_addr;
682 pci_ioremap_io(sys->io_offset, pp->io.start); 709 pci_ioremap_io(global_io_offset, pp->io_base);
683 global_io_offset += SZ_64K; 710 global_io_offset += SZ_64K;
684 pci_add_resource_offset(&sys->resources, &pp->io, 711 pci_add_resource_offset(&sys->resources, &pp->io,
685 sys->io_offset); 712 sys->io_offset);