linux/arch/x86/kernel/apic/htirq.c
<<
>>
Prefs
   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/*
  22 * Hypertransport interrupt support
  23 */
  24static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
  25{
  26        struct ht_irq_msg msg;
  27
  28        fetch_ht_irq_msg(irq, &msg);
  29
  30        msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
  31        msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
  32
  33        msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
  34        msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
  35
  36        write_ht_irq_msg(irq, &msg);
  37}
  38
  39static int
  40ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
  41{
  42        struct irq_cfg *cfg = irqd_cfg(data);
  43        unsigned int dest;
  44        int ret;
  45
  46        ret = apic_set_affinity(data, mask, &dest);
  47        if (ret)
  48                return ret;
  49
  50        target_ht_irq(data->irq, dest, cfg->vector);
  51        return IRQ_SET_MASK_OK_NOCOPY;
  52}
  53
  54static struct irq_chip ht_irq_chip = {
  55        .name                   = "PCI-HT",
  56        .irq_mask               = mask_ht_irq,
  57        .irq_unmask             = unmask_ht_irq,
  58        .irq_ack                = apic_ack_edge,
  59        .irq_set_affinity       = ht_set_affinity,
  60        .irq_retrigger          = apic_retrigger_irq,
  61        .flags                  = IRQCHIP_SKIP_SET_WAKE,
  62};
  63
  64int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
  65{
  66        struct irq_cfg *cfg;
  67        struct ht_irq_msg msg;
  68        unsigned dest;
  69        int err;
  70
  71        if (disable_apic)
  72                return -ENXIO;
  73
  74        cfg = irq_cfg(irq);
  75        err = assign_irq_vector(irq, cfg, apic->target_cpus());
  76        if (err)
  77                return err;
  78
  79        err = apic->cpu_mask_to_apicid_and(cfg->domain,
  80                                           apic->target_cpus(), &dest);
  81        if (err)
  82                return err;
  83
  84        msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
  85
  86        msg.address_lo =
  87                HT_IRQ_LOW_BASE |
  88                HT_IRQ_LOW_DEST_ID(dest) |
  89                HT_IRQ_LOW_VECTOR(cfg->vector) |
  90                ((apic->irq_dest_mode == 0) ?
  91                        HT_IRQ_LOW_DM_PHYSICAL :
  92                        HT_IRQ_LOW_DM_LOGICAL) |
  93                HT_IRQ_LOW_RQEOI_EDGE |
  94                ((apic->irq_delivery_mode != dest_LowestPrio) ?
  95                        HT_IRQ_LOW_MT_FIXED :
  96                        HT_IRQ_LOW_MT_ARBITRATED) |
  97                HT_IRQ_LOW_IRQ_MASKED;
  98
  99        write_ht_irq_msg(irq, &msg);
 100
 101        irq_set_chip_and_handler_name(irq, &ht_irq_chip,
 102                                      handle_edge_irq, "edge");
 103
 104        dev_dbg(&dev->dev, "irq %d for HT\n", irq);
 105
 106        return 0;
 107}
 108