mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 15:41:39 +00:00
iommu/vt-d: Generalise DMAR MSI setup to allow for page request events
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
907fea3491
commit
1208225cf4
@ -1086,6 +1086,11 @@ static void free_iommu(struct intel_iommu *iommu)
|
|||||||
iommu_device_destroy(iommu->iommu_dev);
|
iommu_device_destroy(iommu->iommu_dev);
|
||||||
|
|
||||||
if (iommu->irq) {
|
if (iommu->irq) {
|
||||||
|
if (iommu->pr_irq) {
|
||||||
|
free_irq(iommu->pr_irq, iommu);
|
||||||
|
dmar_free_hwirq(iommu->pr_irq);
|
||||||
|
iommu->pr_irq = 0;
|
||||||
|
}
|
||||||
free_irq(iommu->irq, iommu);
|
free_irq(iommu->irq, iommu);
|
||||||
dmar_free_hwirq(iommu->irq);
|
dmar_free_hwirq(iommu->irq);
|
||||||
iommu->irq = 0;
|
iommu->irq = 0;
|
||||||
@ -1493,53 +1498,68 @@ static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int dmar_msi_reg(struct intel_iommu *iommu, int irq)
|
||||||
|
{
|
||||||
|
if (iommu->irq == irq)
|
||||||
|
return DMAR_FECTL_REG;
|
||||||
|
else if (iommu->pr_irq == irq)
|
||||||
|
return DMAR_PECTL_REG;
|
||||||
|
else
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
void dmar_msi_unmask(struct irq_data *data)
|
void dmar_msi_unmask(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct intel_iommu *iommu = irq_data_get_irq_handler_data(data);
|
struct intel_iommu *iommu = irq_data_get_irq_handler_data(data);
|
||||||
|
int reg = dmar_msi_reg(iommu, data->irq);
|
||||||
unsigned long flag;
|
unsigned long flag;
|
||||||
|
|
||||||
/* unmask it */
|
/* unmask it */
|
||||||
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
||||||
writel(0, iommu->reg + DMAR_FECTL_REG);
|
writel(0, iommu->reg + reg);
|
||||||
/* Read a reg to force flush the post write */
|
/* Read a reg to force flush the post write */
|
||||||
readl(iommu->reg + DMAR_FECTL_REG);
|
readl(iommu->reg + reg);
|
||||||
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmar_msi_mask(struct irq_data *data)
|
void dmar_msi_mask(struct irq_data *data)
|
||||||
{
|
{
|
||||||
unsigned long flag;
|
|
||||||
struct intel_iommu *iommu = irq_data_get_irq_handler_data(data);
|
struct intel_iommu *iommu = irq_data_get_irq_handler_data(data);
|
||||||
|
int reg = dmar_msi_reg(iommu, data->irq);
|
||||||
|
unsigned long flag;
|
||||||
|
|
||||||
/* mask it */
|
/* mask it */
|
||||||
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
||||||
writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
|
writel(DMA_FECTL_IM, iommu->reg + reg);
|
||||||
/* Read a reg to force flush the post write */
|
/* Read a reg to force flush the post write */
|
||||||
readl(iommu->reg + DMAR_FECTL_REG);
|
readl(iommu->reg + reg);
|
||||||
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmar_msi_write(int irq, struct msi_msg *msg)
|
void dmar_msi_write(int irq, struct msi_msg *msg)
|
||||||
{
|
{
|
||||||
struct intel_iommu *iommu = irq_get_handler_data(irq);
|
struct intel_iommu *iommu = irq_get_handler_data(irq);
|
||||||
|
int reg = dmar_msi_reg(iommu, irq);
|
||||||
unsigned long flag;
|
unsigned long flag;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
||||||
writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
|
writel(msg->data, iommu->reg + reg + 4);
|
||||||
writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
|
writel(msg->address_lo, iommu->reg + reg + 8);
|
||||||
writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
|
writel(msg->address_hi, iommu->reg + reg + 12);
|
||||||
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dmar_msi_read(int irq, struct msi_msg *msg)
|
void dmar_msi_read(int irq, struct msi_msg *msg)
|
||||||
{
|
{
|
||||||
struct intel_iommu *iommu = irq_get_handler_data(irq);
|
struct intel_iommu *iommu = irq_get_handler_data(irq);
|
||||||
|
int reg = dmar_msi_reg(iommu, irq);
|
||||||
unsigned long flag;
|
unsigned long flag;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
raw_spin_lock_irqsave(&iommu->register_lock, flag);
|
||||||
msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
|
msg->data = readl(iommu->reg + reg + 4);
|
||||||
msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
|
msg->address_lo = readl(iommu->reg + reg + 8);
|
||||||
msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
|
msg->address_hi = readl(iommu->reg + reg + 12);
|
||||||
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,14 @@
|
|||||||
#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
|
#define DMAR_IQA_REG 0x90 /* Invalidation queue addr register */
|
||||||
#define DMAR_ICS_REG 0x9c /* Invalidation complete status register */
|
#define DMAR_ICS_REG 0x9c /* Invalidation complete status register */
|
||||||
#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */
|
#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr register */
|
||||||
|
#define DMAR_PQH_REG 0xc0 /* Page request queue head register */
|
||||||
|
#define DMAR_PQT_REG 0xc8 /* Page request queue tail register */
|
||||||
|
#define DMAR_PQA_REG 0xd0 /* Page request queue address register */
|
||||||
|
#define DMAR_PRS_REG 0xdc /* Page request status register */
|
||||||
|
#define DMAR_PECTL_REG 0xe0 /* Page request event control register */
|
||||||
|
#define DMAR_PEDATA_REG 0xe4 /* Page request event interrupt data register */
|
||||||
|
#define DMAR_PEADDR_REG 0xe8 /* Page request event interrupt addr register */
|
||||||
|
#define DMAR_PEUADDR_REG 0xec /* Page request event Upper address register */
|
||||||
|
|
||||||
#define OFFSET_STRIDE (9)
|
#define OFFSET_STRIDE (9)
|
||||||
|
|
||||||
@ -373,7 +381,7 @@ struct intel_iommu {
|
|||||||
int seq_id; /* sequence id of the iommu */
|
int seq_id; /* sequence id of the iommu */
|
||||||
int agaw; /* agaw of this iommu */
|
int agaw; /* agaw of this iommu */
|
||||||
int msagaw; /* max sagaw of this iommu */
|
int msagaw; /* max sagaw of this iommu */
|
||||||
unsigned int irq;
|
unsigned int irq, pr_irq;
|
||||||
u16 segment; /* PCI segment# */
|
u16 segment; /* PCI segment# */
|
||||||
unsigned char name[13]; /* Device Name */
|
unsigned char name[13]; /* Device Name */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user