iommu/s390: Add support for iommu_device handling

Add support for the iommu_device_register interface to make
the s390 hardware iommus visible to the iommu core and in
sysfs.

Acked-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Joerg Roedel 2017-04-27 14:44:06 +02:00
parent ef954844c7
commit f42c223514
3 changed files with 50 additions and 1 deletions

View File

@ -8,6 +8,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/iommu.h>
#include <asm-generic/pci.h> #include <asm-generic/pci.h>
#include <asm/pci_clp.h> #include <asm/pci_clp.h>
#include <asm/pci_debug.h> #include <asm/pci_debug.h>
@ -122,6 +123,8 @@ struct zpci_dev {
unsigned long iommu_pages; unsigned long iommu_pages;
unsigned int next_bit; unsigned int next_bit;
struct iommu_device iommu_dev; /* IOMMU core handle */
char res_name[16]; char res_name[16];
struct zpci_bar_struct bars[PCI_BAR_COUNT]; struct zpci_bar_struct bars[PCI_BAR_COUNT];
@ -174,6 +177,10 @@ int clp_enable_fh(struct zpci_dev *, u8);
int clp_disable_fh(struct zpci_dev *); int clp_disable_fh(struct zpci_dev *);
int clp_get_state(u32 fid, enum zpci_state *state); int clp_get_state(u32 fid, enum zpci_state *state);
/* IOMMU Interface */
int zpci_init_iommu(struct zpci_dev *zdev);
void zpci_destroy_iommu(struct zpci_dev *zdev);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* Error handling and recovery */ /* Error handling and recovery */
void zpci_event_error(void *); void zpci_event_error(void *);

View File

@ -776,6 +776,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
zpci_exit_slot(zdev); zpci_exit_slot(zdev);
zpci_cleanup_bus_resources(zdev); zpci_cleanup_bus_resources(zdev);
zpci_destroy_iommu(zdev);
zpci_free_domain(zdev); zpci_free_domain(zdev);
spin_lock(&zpci_list_lock); spin_lock(&zpci_list_lock);
@ -848,11 +849,15 @@ int zpci_create_device(struct zpci_dev *zdev)
if (rc) if (rc)
goto out; goto out;
rc = zpci_init_iommu(zdev);
if (rc)
goto out_free;
mutex_init(&zdev->lock); mutex_init(&zdev->lock);
if (zdev->state == ZPCI_FN_STATE_CONFIGURED) { if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
rc = zpci_enable_device(zdev); rc = zpci_enable_device(zdev);
if (rc) if (rc)
goto out_free; goto out_destroy_iommu;
} }
rc = zpci_scan_bus(zdev); rc = zpci_scan_bus(zdev);
if (rc) if (rc)
@ -869,6 +874,8 @@ int zpci_create_device(struct zpci_dev *zdev)
out_disable: out_disable:
if (zdev->state == ZPCI_FN_STATE_ONLINE) if (zdev->state == ZPCI_FN_STATE_ONLINE)
zpci_disable_device(zdev); zpci_disable_device(zdev);
out_destroy_iommu:
zpci_destroy_iommu(zdev);
out_free: out_free:
zpci_free_domain(zdev); zpci_free_domain(zdev);
out: out:

View File

@ -18,6 +18,8 @@
*/ */
#define S390_IOMMU_PGSIZES (~0xFFFUL) #define S390_IOMMU_PGSIZES (~0xFFFUL)
static struct iommu_ops s390_iommu_ops;
struct s390_domain { struct s390_domain {
struct iommu_domain domain; struct iommu_domain domain;
struct list_head devices; struct list_head devices;
@ -166,11 +168,13 @@ static void s390_iommu_detach_device(struct iommu_domain *domain,
static int s390_iommu_add_device(struct device *dev) static int s390_iommu_add_device(struct device *dev)
{ {
struct iommu_group *group = iommu_group_get_for_dev(dev); struct iommu_group *group = iommu_group_get_for_dev(dev);
struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
if (IS_ERR(group)) if (IS_ERR(group))
return PTR_ERR(group); return PTR_ERR(group);
iommu_group_put(group); iommu_group_put(group);
iommu_device_link(&zdev->iommu_dev, dev);
return 0; return 0;
} }
@ -197,6 +201,7 @@ static void s390_iommu_remove_device(struct device *dev)
s390_iommu_detach_device(domain, dev); s390_iommu_detach_device(domain, dev);
} }
iommu_device_unlink(&zdev->iommu_dev, dev);
iommu_group_remove_device(dev); iommu_group_remove_device(dev);
} }
@ -327,6 +332,36 @@ static size_t s390_iommu_unmap(struct iommu_domain *domain,
return size; return size;
} }
int zpci_init_iommu(struct zpci_dev *zdev)
{
int rc = 0;
rc = iommu_device_sysfs_add(&zdev->iommu_dev, NULL, NULL,
"s390-iommu.%08x", zdev->fid);
if (rc)
goto out_err;
iommu_device_set_ops(&zdev->iommu_dev, &s390_iommu_ops);
rc = iommu_device_register(&zdev->iommu_dev);
if (rc)
goto out_sysfs;
return 0;
out_sysfs:
iommu_device_sysfs_remove(&zdev->iommu_dev);
out_err:
return rc;
}
void zpci_destroy_iommu(struct zpci_dev *zdev)
{
iommu_device_unregister(&zdev->iommu_dev);
iommu_device_sysfs_remove(&zdev->iommu_dev);
}
static struct iommu_ops s390_iommu_ops = { static struct iommu_ops s390_iommu_ops = {
.capable = s390_iommu_capable, .capable = s390_iommu_capable,
.domain_alloc = s390_domain_alloc, .domain_alloc = s390_domain_alloc,