aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-12-18 16:03:57 -0500
committerBjorn Helgaas <bhelgaas@google.com>2013-12-18 16:03:57 -0500
commitc354e811a911e680f5c53baa5cdb5d36e660237b (patch)
treecd6de22440149b4ec805bb71c41c8ae4d8cf04fc
parent330ebfe36e3dc21f656dfa59d69895e21bf6e9da (diff)
parent0b8cfb6aa3aabc96177b1e68ef13d2eb5c686606 (diff)
Merge branch 'pci/host-designware' into next
* pci/host-designware: PCI: designware: Use typical "for" loop idiom PCI: designware: Remove redundant call to pci_write_config_word() PCI: designware: Fix crash in dw_msi_teardown_irq()
-rw-r--r--drivers/pci/host/pcie-designware.c59
1 files changed, 40 insertions, 19 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index e33b68be0391..1c92833a4ed3 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -209,6 +209,23 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
209 return 0; 209 return 0;
210} 210}
211 211
212static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
213 unsigned int nvec, unsigned int pos)
214{
215 unsigned int i, res, bit, val;
216
217 for (i = 0; i < nvec; i++) {
218 irq_set_msi_desc_off(irq_base, i, NULL);
219 clear_bit(pos + i, pp->msi_irq_in_use);
220 /* Disable corresponding interrupt on MSI interrupt controller */
221 res = ((pos + i) / 32) * 12;
222 bit = (pos + i) % 32;
223 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
224 val &= ~(1 << bit);
225 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
226 }
227}
228
212static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) 229static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
213{ 230{
214 int res, bit, irq, pos0, pos1, i; 231 int res, bit, irq, pos0, pos1, i;
@@ -242,18 +259,25 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
242 if (!irq) 259 if (!irq)
243 goto no_valid_irq; 260 goto no_valid_irq;
244 261
245 i = 0; 262 /*
246 while (i < no_irqs) { 263 * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
264 * descs so there is no need to allocate descs here. We can therefore
265 * assume that if irq_find_mapping above returns non-zero, then the
266 * descs are also successfully allocated.
267 */
268
269 for (i = 0; i < no_irqs; i++) {
270 if (irq_set_msi_desc_off(irq, i, desc) != 0) {
271 clear_irq_range(pp, irq, i, pos0);
272 goto no_valid_irq;
273 }
247 set_bit(pos0 + i, pp->msi_irq_in_use); 274 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 */ 275 /*Enable corresponding interrupt in MSI interrupt controller */
251 res = ((pos0 + i) / 32) * 12; 276 res = ((pos0 + i) / 32) * 12;
252 bit = (pos0 + i) % 32; 277 bit = (pos0 + i) % 32;
253 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); 278 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
254 val |= 1 << bit; 279 val |= 1 << bit;
255 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); 280 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
256 i++;
257 } 281 }
258 282
259 *pos = pos0; 283 *pos = pos0;
@@ -266,7 +290,7 @@ no_valid_irq:
266 290
267static void clear_irq(unsigned int irq) 291static void clear_irq(unsigned int irq)
268{ 292{
269 int res, bit, val, pos; 293 unsigned int pos, nvec;
270 struct irq_desc *desc; 294 struct irq_desc *desc;
271 struct msi_desc *msi; 295 struct msi_desc *msi;
272 struct pcie_port *pp; 296 struct pcie_port *pp;
@@ -281,18 +305,15 @@ static void clear_irq(unsigned int irq)
281 return; 305 return;
282 } 306 }
283 307
308 /* undo what was done in assign_irq */
284 pos = data->hwirq; 309 pos = data->hwirq;
310 nvec = 1 << msi->msi_attrib.multiple;
285 311
286 irq_free_desc(irq); 312 clear_irq_range(pp, irq, nvec, pos);
287 313
288 clear_bit(pos, pp->msi_irq_in_use); 314 /* all irqs cleared; reset attributes */
289 315 msi->irq = 0;
290 /* Disable corresponding interrupt on MSI interrupt controller */ 316 msi->msi_attrib.multiple = 0;
291 res = (pos / 32) * 12;
292 bit = pos % 32;
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} 317}
297 318
298static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, 319static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
@@ -320,10 +341,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
320 if (irq < 0) 341 if (irq < 0)
321 return irq; 342 return irq;
322 343
323 msg_ctr &= ~PCI_MSI_FLAGS_QSIZE; 344 /*
324 msg_ctr |= msgvec << 4; 345 * write_msi_msg() will update PCI_MSI_FLAGS so there is
325 pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, 346 * no need to explicitly call pci_write_config_word().
326 msg_ctr); 347 */
327 desc->msi_attrib.multiple = msgvec; 348 desc->msi_attrib.multiple = msgvec;
328 349
329 msg.address_lo = virt_to_phys((void *)pp->msi_data); 350 msg.address_lo = virt_to_phys((void *)pp->msi_data);