aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-11-23 03:26:03 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2015-12-16 10:29:44 -0500
commit72f57f2f430f9d262fe3c8dd957f57cbdc1f5f97 (patch)
tree47a5db996facb075ef44d51974de96bc497a1c95
parentab6484ee84c17a948c4235c20928f6aee295ced7 (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.c94
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/** 192static struct platform_msi_priv_data *
193 * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev 193platform_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 */
201int 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; 232static 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 */
247int 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
248out_free_desc: 267out_free_desc:
249 platform_msi_free_descs(dev, 0, nvec); 268 platform_msi_free_descs(dev, 0, nvec);
250out_free_id: 269out_free_priv_data:
251 ida_simple_remove(&platform_msi_devid_ida, priv_data->devid); 270 platform_msi_free_priv_data(priv_data);
252out_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 */
262void platform_msi_domain_free_irqs(struct device *dev) 279void 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);