aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2014-10-01 18:45:01 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-10-01 18:45:01 -0400
commitb9c9c2558ba366d59dc242872da883a879b8ffc6 (patch)
treeb2c15a99796161df92eb27ce80ec6b52cb7ca12f /drivers/pci
parent5d85142b9e5264a925e4d582c3b0d7297d9c2713 (diff)
parentc8df6ac9452e8f47a6f660993c526d13e858a6f3 (diff)
Merge branch 'pci/host-designware' into next
* pci/host-designware: PCI: designware: Remove open-coded bitmap operations PCI: designware: Setup and clear exactly one MSI at a time Conflicts: drivers/pci/host/pcie-designware.c
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/pcie-designware.c97
1 files changed, 14 insertions, 83 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index f72744599d12..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
199static 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
223static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) 199static 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
250static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) 227static 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
261static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) 238static 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);
@@ -313,53 +276,17 @@ no_valid_irq:
313 return -ENOSPC; 276 return -ENOSPC;
314} 277}
315 278
316static void clear_irq(unsigned int irq)
317{
318 unsigned int pos, nvec;
319 struct msi_desc *msi;
320 struct pcie_port *pp;
321 struct irq_data *data = irq_get_irq_data(irq);
322
323 /* get the port structure */
324 msi = irq_data_get_msi(data);
325 pp = sys_to_pcie(msi->dev->bus->sysdata);
326
327 /* undo what was done in assign_irq */
328 pos = data->hwirq;
329 nvec = 1 << msi->msi_attrib.multiple;
330
331 clear_irq_range(pp, irq, nvec, pos);
332
333 /* all irqs cleared; reset attributes */
334 msi->irq = 0;
335 msi->msi_attrib.multiple = 0;
336}
337
338static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, 279static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
339 struct msi_desc *desc) 280 struct msi_desc *desc)
340{ 281{
341 int irq, pos, msgvec; 282 int irq, pos;
342 u16 msg_ctr;
343 struct msi_msg msg; 283 struct msi_msg msg;
344 struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata); 284 struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
345 285
346 pci_read_config_word(pdev, pdev->msi_cap + PCI_MSI_FLAGS, &msg_ctr); 286 irq = assign_irq(1, desc, &pos);
347 msgvec = (msg_ctr & PCI_MSI_FLAGS_QSIZE) >> 4;
348 if (msgvec == 0)
349 msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
350 if (msgvec > 5)
351 msgvec = 0;
352
353 irq = assign_irq((1 << msgvec), desc, &pos);
354 if (irq < 0) 287 if (irq < 0)
355 return irq; 288 return irq;
356 289
357 /*
358 * write_msi_msg() will update PCI_MSI_FLAGS so there is
359 * no need to explicitly call pci_write_config_word().
360 */
361 desc->msi_attrib.multiple = msgvec;
362
363 if (pp->ops->get_msi_addr) 290 if (pp->ops->get_msi_addr)
364 msg.address_lo = pp->ops->get_msi_addr(pp); 291 msg.address_lo = pp->ops->get_msi_addr(pp);
365 else 292 else
@@ -378,7 +305,11 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
378 305
379static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) 306static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
380{ 307{
381 clear_irq(irq); 308 struct irq_data *data = irq_get_irq_data(irq);
309 struct msi_desc *msi = irq_data_get_msi(data);
310 struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata);
311
312 clear_irq_range(pp, irq, 1, data->hwirq);
382} 313}
383 314
384static struct msi_chip dw_pcie_msi_chip = { 315static struct msi_chip dw_pcie_msi_chip = {