htirq.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Support Hypertransport IRQ
  3. *
  4. * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
  5. * Moved from arch/x86/kernel/apic/io_apic.c.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/mm.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/init.h>
  14. #include <linux/device.h>
  15. #include <linux/pci.h>
  16. #include <linux/htirq.h>
  17. #include <asm/hw_irq.h>
  18. #include <asm/apic.h>
  19. #include <asm/hypertransport.h>
  20. /*
  21. * Hypertransport interrupt support
  22. */
  23. static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
  24. {
  25. struct ht_irq_msg msg;
  26. fetch_ht_irq_msg(irq, &msg);
  27. msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
  28. msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
  29. msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
  30. msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
  31. write_ht_irq_msg(irq, &msg);
  32. }
  33. static int
  34. ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
  35. {
  36. struct irq_cfg *cfg = irqd_cfg(data);
  37. unsigned int dest;
  38. int ret;
  39. ret = apic_set_affinity(data, mask, &dest);
  40. if (ret)
  41. return ret;
  42. target_ht_irq(data->irq, dest, cfg->vector);
  43. return IRQ_SET_MASK_OK_NOCOPY;
  44. }
  45. static struct irq_chip ht_irq_chip = {
  46. .name = "PCI-HT",
  47. .irq_mask = mask_ht_irq,
  48. .irq_unmask = unmask_ht_irq,
  49. .irq_ack = apic_ack_edge,
  50. .irq_set_affinity = ht_set_affinity,
  51. .irq_retrigger = apic_retrigger_irq,
  52. .flags = IRQCHIP_SKIP_SET_WAKE,
  53. };
  54. int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
  55. {
  56. struct irq_cfg *cfg;
  57. struct ht_irq_msg msg;
  58. unsigned dest;
  59. int err;
  60. if (disable_apic)
  61. return -ENXIO;
  62. cfg = irq_cfg(irq);
  63. err = assign_irq_vector(irq, cfg, apic->target_cpus());
  64. if (err)
  65. return err;
  66. err = apic->cpu_mask_to_apicid_and(cfg->domain,
  67. apic->target_cpus(), &dest);
  68. if (err)
  69. return err;
  70. msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
  71. msg.address_lo =
  72. HT_IRQ_LOW_BASE |
  73. HT_IRQ_LOW_DEST_ID(dest) |
  74. HT_IRQ_LOW_VECTOR(cfg->vector) |
  75. ((apic->irq_dest_mode == 0) ?
  76. HT_IRQ_LOW_DM_PHYSICAL :
  77. HT_IRQ_LOW_DM_LOGICAL) |
  78. HT_IRQ_LOW_RQEOI_EDGE |
  79. ((apic->irq_delivery_mode != dest_LowestPrio) ?
  80. HT_IRQ_LOW_MT_FIXED :
  81. HT_IRQ_LOW_MT_ARBITRATED) |
  82. HT_IRQ_LOW_IRQ_MASKED;
  83. write_ht_irq_msg(irq, &msg);
  84. irq_set_chip_and_handler_name(irq, &ht_irq_chip,
  85. handle_edge_irq, "edge");
  86. dev_dbg(&dev->dev, "irq %d for HT\n", irq);
  87. return 0;
  88. }