diff options
| author | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-09 06:24:45 -0400 |
|---|---|---|
| committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-06-14 06:49:57 -0400 |
| commit | 8fa5f802abf3cd374b5f07418cea72c5d9d204cc (patch) | |
| tree | 40ab1352de8ac21c061e9bae524ecbe5249e1c9a | |
| parent | 39c555460cbc6d35656878c89d4664fbd6c81551 (diff) | |
x86/amd-iommu: Introduce global dev_data_list
This list keeps all allocated iommu_dev_data structs in a
list together. This is needed for instances that have no
associated device.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
| -rw-r--r-- | arch/x86/include/asm/amd_iommu_types.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/amd_iommu.c | 56 |
2 files changed, 48 insertions, 9 deletions
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h index 4c9982995414..35520e31c1b4 100644 --- a/arch/x86/include/asm/amd_iommu_types.h +++ b/arch/x86/include/asm/amd_iommu_types.h | |||
| @@ -310,6 +310,7 @@ struct protection_domain { | |||
| 310 | */ | 310 | */ |
| 311 | struct iommu_dev_data { | 311 | struct iommu_dev_data { |
| 312 | struct list_head list; /* For domain->dev_list */ | 312 | struct list_head list; /* For domain->dev_list */ |
| 313 | struct list_head dev_data_list; /* For global dev_data_list */ | ||
| 313 | struct device *dev; /* Device this data belong to */ | 314 | struct device *dev; /* Device this data belong to */ |
| 314 | struct device *alias; /* The Alias Device */ | 315 | struct device *alias; /* The Alias Device */ |
| 315 | struct protection_domain *domain; /* Domain the device is bound to */ | 316 | struct protection_domain *domain; /* Domain the device is bound to */ |
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index cc6f6da630e8..8b8489084649 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c | |||
| @@ -45,6 +45,10 @@ static DEFINE_RWLOCK(amd_iommu_devtable_lock); | |||
| 45 | static LIST_HEAD(iommu_pd_list); | 45 | static LIST_HEAD(iommu_pd_list); |
| 46 | static DEFINE_SPINLOCK(iommu_pd_list_lock); | 46 | static DEFINE_SPINLOCK(iommu_pd_list_lock); |
| 47 | 47 | ||
| 48 | /* List of all available dev_data structures */ | ||
| 49 | static LIST_HEAD(dev_data_list); | ||
| 50 | static DEFINE_SPINLOCK(dev_data_list_lock); | ||
| 51 | |||
| 48 | /* | 52 | /* |
| 49 | * Domain for untranslated devices - only allocated | 53 | * Domain for untranslated devices - only allocated |
| 50 | * if iommu=pt passed on kernel cmd line. | 54 | * if iommu=pt passed on kernel cmd line. |
| @@ -68,6 +72,35 @@ static void update_domain(struct protection_domain *domain); | |||
| 68 | * | 72 | * |
| 69 | ****************************************************************************/ | 73 | ****************************************************************************/ |
| 70 | 74 | ||
| 75 | static struct iommu_dev_data *alloc_dev_data(void) | ||
| 76 | { | ||
| 77 | struct iommu_dev_data *dev_data; | ||
| 78 | unsigned long flags; | ||
| 79 | |||
| 80 | dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); | ||
| 81 | if (!dev_data) | ||
| 82 | return NULL; | ||
| 83 | |||
| 84 | atomic_set(&dev_data->bind, 0); | ||
| 85 | |||
| 86 | spin_lock_irqsave(&dev_data_list_lock, flags); | ||
| 87 | list_add_tail(&dev_data->dev_data_list, &dev_data_list); | ||
| 88 | spin_unlock_irqrestore(&dev_data_list_lock, flags); | ||
| 89 | |||
| 90 | return dev_data; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void free_dev_data(struct iommu_dev_data *dev_data) | ||
| 94 | { | ||
| 95 | unsigned long flags; | ||
| 96 | |||
| 97 | spin_lock_irqsave(&dev_data_list_lock, flags); | ||
| 98 | list_del(&dev_data->dev_data_list); | ||
| 99 | spin_unlock_irqrestore(&dev_data_list_lock, flags); | ||
| 100 | |||
| 101 | kfree(dev_data); | ||
| 102 | } | ||
| 103 | |||
| 71 | static inline u16 get_device_id(struct device *dev) | 104 | static inline u16 get_device_id(struct device *dev) |
| 72 | { | 105 | { |
| 73 | struct pci_dev *pdev = to_pci_dev(dev); | 106 | struct pci_dev *pdev = to_pci_dev(dev); |
| @@ -139,32 +172,28 @@ static int iommu_init_device(struct device *dev) | |||
| 139 | { | 172 | { |
| 140 | struct iommu_dev_data *dev_data; | 173 | struct iommu_dev_data *dev_data; |
| 141 | struct pci_dev *pdev; | 174 | struct pci_dev *pdev; |
| 142 | u16 devid, alias; | 175 | u16 alias; |
| 143 | 176 | ||
| 144 | if (dev->archdata.iommu) | 177 | if (dev->archdata.iommu) |
| 145 | return 0; | 178 | return 0; |
| 146 | 179 | ||
| 147 | dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); | 180 | dev_data = alloc_dev_data(); |
| 148 | if (!dev_data) | 181 | if (!dev_data) |
| 149 | return -ENOMEM; | 182 | return -ENOMEM; |
| 150 | 183 | ||
| 151 | dev_data->dev = dev; | 184 | dev_data->dev = dev; |
| 152 | 185 | ||
| 153 | devid = get_device_id(dev); | 186 | alias = amd_iommu_alias_table[get_device_id(dev)]; |
| 154 | alias = amd_iommu_alias_table[devid]; | ||
| 155 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); | 187 | pdev = pci_get_bus_and_slot(PCI_BUS(alias), alias & 0xff); |
| 156 | if (pdev) | 188 | if (pdev) |
| 157 | dev_data->alias = &pdev->dev; | 189 | dev_data->alias = &pdev->dev; |
| 158 | else { | 190 | else { |
| 159 | kfree(dev_data); | 191 | free_dev_data(dev_data); |
| 160 | return -ENOTSUPP; | 192 | return -ENOTSUPP; |
| 161 | } | 193 | } |
| 162 | 194 | ||
| 163 | atomic_set(&dev_data->bind, 0); | ||
| 164 | |||
| 165 | dev->archdata.iommu = dev_data; | 195 | dev->archdata.iommu = dev_data; |
| 166 | 196 | ||
| 167 | |||
| 168 | return 0; | 197 | return 0; |
| 169 | } | 198 | } |
| 170 | 199 | ||
| @@ -184,11 +213,16 @@ static void iommu_ignore_device(struct device *dev) | |||
| 184 | 213 | ||
| 185 | static void iommu_uninit_device(struct device *dev) | 214 | static void iommu_uninit_device(struct device *dev) |
| 186 | { | 215 | { |
| 187 | kfree(dev->archdata.iommu); | 216 | /* |
| 217 | * Nothing to do here - we keep dev_data around for unplugged devices | ||
| 218 | * and reuse it when the device is re-plugged - not doing so would | ||
| 219 | * introduce a ton of races. | ||
| 220 | */ | ||
| 188 | } | 221 | } |
| 189 | 222 | ||
| 190 | void __init amd_iommu_uninit_devices(void) | 223 | void __init amd_iommu_uninit_devices(void) |
| 191 | { | 224 | { |
| 225 | struct iommu_dev_data *dev_data, *n; | ||
| 192 | struct pci_dev *pdev = NULL; | 226 | struct pci_dev *pdev = NULL; |
| 193 | 227 | ||
| 194 | for_each_pci_dev(pdev) { | 228 | for_each_pci_dev(pdev) { |
| @@ -198,6 +232,10 @@ void __init amd_iommu_uninit_devices(void) | |||
| 198 | 232 | ||
| 199 | iommu_uninit_device(&pdev->dev); | 233 | iommu_uninit_device(&pdev->dev); |
| 200 | } | 234 | } |
| 235 | |||
| 236 | /* Free all of our dev_data structures */ | ||
| 237 | list_for_each_entry_safe(dev_data, n, &dev_data_list, dev_data_list) | ||
| 238 | free_dev_data(dev_data); | ||
| 201 | } | 239 | } |
| 202 | 240 | ||
| 203 | int __init amd_iommu_init_devices(void) | 241 | int __init amd_iommu_init_devices(void) |
