diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-11-23 03:26:03 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-12-16 10:29:44 -0500 |
commit | 72f57f2f430f9d262fe3c8dd957f57cbdc1f5f97 (patch) | |
tree | 47a5db996facb075ef44d51974de96bc497a1c95 | |
parent | ab6484ee84c17a948c4235c20928f6aee295ced7 (diff) |
platform-msi: Factor out allocation/free of private data
As we're going to have multiple paths to allocate/free the
platform-msi private data, factor this out into separate
utility functions.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | drivers/base/platform-msi.c | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index 6148c78f51a7..44b8c0d816fe 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c | |||
@@ -189,21 +189,11 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode, | |||
189 | return domain; | 189 | return domain; |
190 | } | 190 | } |
191 | 191 | ||
192 | /** | 192 | static struct platform_msi_priv_data * |
193 | * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev | 193 | platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec, |
194 | * @dev: The device for which to allocate interrupts | 194 | irq_write_msi_msg_t write_msi_msg) |
195 | * @nvec: The number of interrupts to allocate | ||
196 | * @write_msi_msg: Callback to write an interrupt message for @dev | ||
197 | * | ||
198 | * Returns: | ||
199 | * Zero for success, or an error code in case of failure | ||
200 | */ | ||
201 | int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, | ||
202 | irq_write_msi_msg_t write_msi_msg) | ||
203 | { | 195 | { |
204 | struct platform_msi_priv_data *priv_data; | 196 | struct platform_msi_priv_data *datap; |
205 | int err; | ||
206 | |||
207 | /* | 197 | /* |
208 | * Limit the number of interrupts to 256 per device. Should we | 198 | * Limit the number of interrupts to 256 per device. Should we |
209 | * need to bump this up, DEV_ID_SHIFT should be adjusted | 199 | * need to bump this up, DEV_ID_SHIFT should be adjusted |
@@ -211,33 +201,62 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, | |||
211 | * capable devices). | 201 | * capable devices). |
212 | */ | 202 | */ |
213 | if (!dev->msi_domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS) | 203 | if (!dev->msi_domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS) |
214 | return -EINVAL; | 204 | return ERR_PTR(-EINVAL); |
215 | 205 | ||
216 | if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) { | 206 | if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) { |
217 | dev_err(dev, "Incompatible msi_domain, giving up\n"); | 207 | dev_err(dev, "Incompatible msi_domain, giving up\n"); |
218 | return -EINVAL; | 208 | return ERR_PTR(-EINVAL); |
219 | } | 209 | } |
220 | 210 | ||
221 | /* Already had a helping of MSI? Greed... */ | 211 | /* Already had a helping of MSI? Greed... */ |
222 | if (!list_empty(dev_to_msi_list(dev))) | 212 | if (!list_empty(dev_to_msi_list(dev))) |
223 | return -EBUSY; | 213 | return ERR_PTR(-EBUSY); |
214 | |||
215 | datap = kzalloc(sizeof(*datap), GFP_KERNEL); | ||
216 | if (!datap) | ||
217 | return ERR_PTR(-ENOMEM); | ||
218 | |||
219 | datap->devid = ida_simple_get(&platform_msi_devid_ida, | ||
220 | 0, 1 << DEV_ID_SHIFT, GFP_KERNEL); | ||
221 | if (datap->devid < 0) { | ||
222 | int err = datap->devid; | ||
223 | kfree(datap); | ||
224 | return ERR_PTR(err); | ||
225 | } | ||
224 | 226 | ||
225 | priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL); | 227 | datap->write_msg = write_msi_msg; |
226 | if (!priv_data) | ||
227 | return -ENOMEM; | ||
228 | 228 | ||
229 | priv_data->devid = ida_simple_get(&platform_msi_devid_ida, | 229 | return datap; |
230 | 0, 1 << DEV_ID_SHIFT, GFP_KERNEL); | 230 | } |
231 | if (priv_data->devid < 0) { | 231 | |
232 | err = priv_data->devid; | 232 | static void platform_msi_free_priv_data(struct platform_msi_priv_data *data) |
233 | goto out_free_data; | 233 | { |
234 | } | 234 | ida_simple_remove(&platform_msi_devid_ida, data->devid); |
235 | kfree(data); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev | ||
240 | * @dev: The device for which to allocate interrupts | ||
241 | * @nvec: The number of interrupts to allocate | ||
242 | * @write_msi_msg: Callback to write an interrupt message for @dev | ||
243 | * | ||
244 | * Returns: | ||
245 | * Zero for success, or an error code in case of failure | ||
246 | */ | ||
247 | int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, | ||
248 | irq_write_msi_msg_t write_msi_msg) | ||
249 | { | ||
250 | struct platform_msi_priv_data *priv_data; | ||
251 | int err; | ||
235 | 252 | ||
236 | priv_data->write_msg = write_msi_msg; | 253 | priv_data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg); |
254 | if (IS_ERR(priv_data)) | ||
255 | return PTR_ERR(priv_data); | ||
237 | 256 | ||
238 | err = platform_msi_alloc_descs(dev, nvec, priv_data); | 257 | err = platform_msi_alloc_descs(dev, nvec, priv_data); |
239 | if (err) | 258 | if (err) |
240 | goto out_free_id; | 259 | goto out_free_priv_data; |
241 | 260 | ||
242 | err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec); | 261 | err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec); |
243 | if (err) | 262 | if (err) |
@@ -247,10 +266,8 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, | |||
247 | 266 | ||
248 | out_free_desc: | 267 | out_free_desc: |
249 | platform_msi_free_descs(dev, 0, nvec); | 268 | platform_msi_free_descs(dev, 0, nvec); |
250 | out_free_id: | 269 | out_free_priv_data: |
251 | ida_simple_remove(&platform_msi_devid_ida, priv_data->devid); | 270 | platform_msi_free_priv_data(priv_data); |
252 | out_free_data: | ||
253 | kfree(priv_data); | ||
254 | 271 | ||
255 | return err; | 272 | return err; |
256 | } | 273 | } |
@@ -261,16 +278,11 @@ out_free_data: | |||
261 | */ | 278 | */ |
262 | void platform_msi_domain_free_irqs(struct device *dev) | 279 | void platform_msi_domain_free_irqs(struct device *dev) |
263 | { | 280 | { |
264 | struct msi_desc *desc; | 281 | if (!list_empty(dev_to_msi_list(dev))) { |
265 | 282 | struct msi_desc *desc; | |
266 | desc = first_msi_entry(dev); | ||
267 | if (desc) { | ||
268 | struct platform_msi_priv_data *data; | ||
269 | |||
270 | data = desc->platform.msi_priv_data; | ||
271 | 283 | ||
272 | ida_simple_remove(&platform_msi_devid_ida, data->devid); | 284 | desc = first_msi_entry(dev); |
273 | kfree(data); | 285 | platform_msi_free_priv_data(desc->platform.msi_priv_data); |
274 | } | 286 | } |
275 | 287 | ||
276 | msi_domain_free_irqs(dev->msi_domain, dev); | 288 | msi_domain_free_irqs(dev->msi_domain, dev); |