Create struct msi_device_data and add a pointer of that type to struct dev_msi_info, which is part of struct device. Provide an allocator function which can be invoked from the MSI interrupt allocation code pathes. Add a properties field to the data structure as a first member so the allocation size is not zero bytes. The field will be uses later on.
Unified · Split
| @@ -45,6 +45,7 @@ struct iommu_ops; · 44 unmodified lines | |||
| 45 | struct iommu_group; | 45 | struct iommu_group; |
| 46 | struct dev_pin_info; | 46 | struct dev_pin_info; |
| 47 | struct dev_iommu; | 47 | struct dev_iommu; |
| 48 | struct msi_device_data; | ||
| 48 | 49 | ||
| 49 | /** | 50 | /** |
| 50 | * struct subsys_interface - interfaces to device functions | 51 | * struct subsys_interface - interfaces to device functions |
| @@ -374,11 +375,15 @@ struct dev_links_info { · 323 unmodified lines | |||
| 374 | /** | 375 | /** |
| 375 | * struct dev_msi_info - Device data related to MSI | 376 | * struct dev_msi_info - Device data related to MSI |
| 376 | * @domain: The MSI interrupt domain associated to the device | 377 | * @domain: The MSI interrupt domain associated to the device |
| 378 | * @data: Pointer to MSI device data | ||
| 377 | */ | 379 | */ |
| 378 | struct dev_msi_info { | 380 | struct dev_msi_info { |
| 379 | #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN | 381 | #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN |
| 380 | struct irq_domain *domain; | 382 | struct irq_domain *domain; |
| 381 | #endif | 383 | #endif |
| 384 | #ifdef CONFIG_GENERIC_MSI_IRQ | ||
| 385 | struct msi_device_data *data; | ||
| 386 | #endif | ||
| 382 | }; | 387 | }; |
| 383 | 388 | ||
| 384 | /** | 389 | /** |
| @@ -171,6 +171,16 @@ struct msi_desc { · 170 unmodified lines | |||
| 171 | }; | 171 | }; |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | /** | ||
| 175 | * msi_device_data - MSI per device data | ||
| 176 | * @properties: MSI properties which are interesting to drivers | ||
| 177 | */ | ||
| 178 | struct msi_device_data { | ||
| 179 | unsigned long properties; | ||
| 180 | }; | ||
| 181 | |||
| 182 | int msi_setup_device_data(struct device *dev); | ||
| 183 | |||
| 174 | /* Helpers to hide struct msi_desc implementation details */ | 184 | /* Helpers to hide struct msi_desc implementation details */ |
| 175 | #define msi_desc_to_dev(desc) ((desc)->dev) | 185 | #define msi_desc_to_dev(desc) ((desc)->dev) |
| 176 | #define dev_to_msi_list(dev) (&(dev)->msi_list) | 186 | #define dev_to_msi_list(dev) (&(dev)->msi_list) |
| @@ -233,10 +243,16 @@ void pci_msi_mask_irq(struct irq_data *data); · 56 unmodified lines | |||
| 233 | void pci_msi_unmask_irq(struct irq_data *data); | 243 | void pci_msi_unmask_irq(struct irq_data *data); |
| 234 | 244 | ||
| 235 | #ifdef CONFIG_SYSFS | 245 | #ifdef CONFIG_SYSFS |
| 246 | int msi_device_populate_sysfs(struct device *dev); | ||
| 247 | void msi_device_destroy_sysfs(struct device *dev); | ||
| 248 | |||
| 236 | const struct attribute_group **msi_populate_sysfs(struct device *dev); | 249 | const struct attribute_group **msi_populate_sysfs(struct device *dev); |
| 237 | void msi_destroy_sysfs(struct device *dev, | 250 | void msi_destroy_sysfs(struct device *dev, |
| 238 | const struct attribute_group **msi_irq_groups); | 251 | const struct attribute_group **msi_irq_groups); |
| 239 | #else | 252 | #else |
| 253 | static inline int msi_device_populate_sysfs(struct device *dev) { return 0; } | ||
| 254 | static inline void msi_device_destroy_sysfs(struct device *dev) { } | ||
| 255 | |||
| 240 | static inline const struct attribute_group **msi_populate_sysfs(struct device *dev) | 256 | static inline const struct attribute_group **msi_populate_sysfs(struct device *dev) |
| 241 | { | 257 | { |
| 242 | return NULL; | 258 | return NULL; |
| @@ -384,6 +400,8 @@ enum { · 141 unmodified lines | |||
| 384 | MSI_FLAG_MUST_REACTIVATE = (1 << 5), | 400 | MSI_FLAG_MUST_REACTIVATE = (1 << 5), |
| 385 | /* Is level-triggered capable, using two messages */ | 401 | /* Is level-triggered capable, using two messages */ |
| 386 | MSI_FLAG_LEVEL_CAPABLE = (1 << 6), | 402 | MSI_FLAG_LEVEL_CAPABLE = (1 << 6), |
| 403 | /* Populate sysfs on alloc() and destroy it on free() */ | ||
| 404 | MSI_FLAG_DEV_SYSFS = (1 << 7), | ||
| 387 | }; | 405 | }; |
| 388 | 406 | ||
| 389 | int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, | 407 | int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, |
| @@ -73,6 +73,38 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) · 72 unmodified lines | |||
| 73 | } | 73 | } |
| 74 | EXPORT_SYMBOL_GPL(get_cached_msi_msg); | 74 | EXPORT_SYMBOL_GPL(get_cached_msi_msg); |
| 75 | 75 | ||
| 76 | static void msi_device_data_release(struct device *dev, void *res) | ||
| 77 | { | ||
| 78 | WARN_ON_ONCE(!list_empty(&dev->msi_list)); | ||
| 79 | dev->msi.data = NULL; | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * msi_setup_device_data - Setup MSI device data | ||
| 84 | * @dev: Device for which MSI device data should be set up | ||
| 85 | * | ||
| 86 | * Return: 0 on success, appropriate error code otherwise | ||
| 87 | * | ||
| 88 | * This can be called more than once for @dev. If the MSI device data is | ||
| 89 | * already allocated the call succeeds. The allocated memory is | ||
| 90 | * automatically released when the device is destroyed. | ||
| 91 | */ | ||
| 92 | int msi_setup_device_data(struct device *dev) | ||
| 93 | { | ||
| 94 | struct msi_device_data *md; | ||
| 95 | |||
| 96 | if (dev->msi.data) | ||
| 97 | return 0; | ||
| 98 | |||
| 99 | md = devres_alloc(msi_device_data_release, sizeof(*md), GFP_KERNEL); | ||
| 100 | if (!md) | ||
| 101 | return -ENOMEM; | ||
| 102 | |||
| 103 | dev->msi.data = md; | ||
| 104 | devres_add(dev, md); | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 76 | #ifdef CONFIG_SYSFS | 108 | #ifdef CONFIG_SYSFS |
| 77 | static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, | 109 | static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, |
| 78 | char *buf) | 110 | char *buf) |