Skip to content

Commit

Permalink
iommu/amd: Add IOAPIC remapping routines
Browse files Browse the repository at this point in the history
Add the routine to setup interrupt remapping for ioapic
interrupts. Also add a routine to change the affinity of an
irq and to free an irq allocation for interrupt remapping.
The last two functions will also be used for MSI interrupts.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
  • Loading branch information
Joerg Roedel committed Sep 28, 2012
1 parent 2b32450 commit 5527de7
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4000,4 +4000,130 @@ static void free_irte(u16 devid, int index)
iommu_completion_wait(iommu);
}

static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
unsigned int destination, int vector,
struct io_apic_irq_attr *attr)
{
struct irq_remap_table *table;
struct irq_2_iommu *irte_info;
struct irq_cfg *cfg;
union irte irte;
int ioapic_id;
int index;
int devid;
int ret;

cfg = irq_get_chip_data(irq);
if (!cfg)
return -EINVAL;

irte_info = &cfg->irq_2_iommu;
ioapic_id = mpc_ioapic_id(attr->ioapic);
devid = get_ioapic_devid(ioapic_id);

if (devid < 0)
return devid;

table = get_irq_table(devid, true);
if (table == NULL)
return -ENOMEM;

index = attr->ioapic_pin;

/* Setup IRQ remapping info */
irte_info->sub_handle = devid;
irte_info->irte_index = index;
irte_info->iommu = (void *)cfg;

/* Setup IRTE for IOMMU */
irte.val = 0;
irte.fields.vector = vector;
irte.fields.int_type = apic->irq_delivery_mode;
irte.fields.destination = destination;
irte.fields.dm = apic->irq_dest_mode;
irte.fields.valid = 1;

ret = modify_irte(devid, index, irte);
if (ret)
return ret;

/* Setup IOAPIC entry */
memset(entry, 0, sizeof(*entry));

entry->vector = index;
entry->mask = 0;
entry->trigger = attr->trigger;
entry->polarity = attr->polarity;

/*
* Mask level triggered irqs.
* Use IRQ_DELAYED_DISABLE for edge triggered irqs.
*/
if (attr->trigger)
entry->mask = 1;

return 0;
}

static int set_affinity(struct irq_data *data, const struct cpumask *mask,
bool force)
{
struct irq_2_iommu *irte_info;
unsigned int dest, irq;
struct irq_cfg *cfg;
union irte irte;
int err;

if (!config_enabled(CONFIG_SMP))
return -1;

cfg = data->chip_data;
irq = data->irq;
irte_info = &cfg->irq_2_iommu;

if (!cpumask_intersects(mask, cpu_online_mask))
return -EINVAL;

if (get_irte(irte_info->sub_handle, irte_info->irte_index, &irte))
return -EBUSY;

if (assign_irq_vector(irq, cfg, mask))
return -EBUSY;

err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
if (err) {
if (assign_irq_vector(irq, cfg, data->affinity))
pr_err("AMD-Vi: Failed to recover vector for irq %d\n", irq);
return err;
}

irte.fields.vector = cfg->vector;
irte.fields.destination = dest;

modify_irte(irte_info->sub_handle, irte_info->irte_index, irte);

if (cfg->move_in_progress)
send_cleanup_vector(cfg);

cpumask_copy(data->affinity, mask);

return 0;
}

static int free_irq(int irq)
{
struct irq_2_iommu *irte_info;
struct irq_cfg *cfg;

cfg = irq_get_chip_data(irq);
if (!cfg)
return -EINVAL;

irte_info = &cfg->irq_2_iommu;

free_irte(irte_info->sub_handle, irte_info->irte_index);

return 0;
}

#endif

0 comments on commit 5527de7

Please sign in to comment.