diff options
| author | Joerg Roedel <joerg.roedel@amd.com> | 2011-11-28 14:36:36 +0100 | 
|---|---|---|
| committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-12-14 12:09:39 +0100 | 
| commit | 175d6146738b3d04e1adcaa4a971a3b2b0dbd8af (patch) | |
| tree | 02fea4cc4c1205db6d922be017b5bd65359ed3d7 /drivers/iommu/amd_iommu_v2.c | |
| parent | 8736b2c331030733c5d619170dc6e9ef211a4039 (diff) | |
iommu/amd: Add invalid_ppr callback
This callback can be used to change the PRI response code
sent to a device when a PPR fault fails.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu/amd_iommu_v2.c')
| -rw-r--r-- | drivers/iommu/amd_iommu_v2.c | 57 | 
1 files changed, 55 insertions, 2 deletions
| diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index abdb8396f89a..fe812e2a0474 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -62,6 +62,7 @@ struct device_state {  	struct iommu_domain *domain;  	int pasid_levels;  	int max_pasids; +	amd_iommu_invalid_ppr_cb inv_ppr_cb;  	spinlock_t lock;  	wait_queue_head_t wq;  }; @@ -505,10 +506,31 @@ static void do_fault(struct work_struct *work)  	npages = get_user_pages(fault->state->task, fault->state->mm,  				fault->address, 1, write, 0, &page, NULL); -	if (npages == 1) +	if (npages == 1) {  		put_page(page); -	else +	} else if (fault->dev_state->inv_ppr_cb) { +		int status; + +		status = fault->dev_state->inv_ppr_cb(fault->dev_state->pdev, +						      fault->pasid, +						      fault->address, +						      fault->flags); +		switch (status) { +		case AMD_IOMMU_INV_PRI_RSP_SUCCESS: +			set_pri_tag_status(fault->state, fault->tag, PPR_SUCCESS); +			break; +		case AMD_IOMMU_INV_PRI_RSP_INVALID: +			set_pri_tag_status(fault->state, fault->tag, PPR_INVALID); +			break; +		case AMD_IOMMU_INV_PRI_RSP_FAIL: +			set_pri_tag_status(fault->state, fault->tag, PPR_FAILURE); +			break; +		default: +			BUG(); +		} +	} else {  		set_pri_tag_status(fault->state, fault->tag, PPR_INVALID); +	}  	finish_pri_tag(fault->dev_state, fault->state, fault->tag); @@ -828,6 +850,37 @@ void amd_iommu_free_device(struct pci_dev *pdev)  }  EXPORT_SYMBOL(amd_iommu_free_device); +int amd_iommu_set_invalid_ppr_cb(struct pci_dev *pdev, +				 amd_iommu_invalid_ppr_cb cb) +{ +	struct device_state *dev_state; +	unsigned long flags; +	u16 devid; +	int ret; + +	if (!amd_iommu_v2_supported()) +		return -ENODEV; + +	devid = device_id(pdev); + +	spin_lock_irqsave(&state_lock, flags); + +	ret = -EINVAL; +	dev_state = state_table[devid]; +	if (dev_state == NULL) +		goto out_unlock; + +	dev_state->inv_ppr_cb = cb; + +	ret = 0; + +out_unlock: +	spin_unlock_irqrestore(&state_lock, flags); + +	return ret; +} +EXPORT_SYMBOL(amd_iommu_set_invalid_ppr_cb); +  static int __init amd_iommu_v2_init(void)  {  	size_t state_table_size; | 
