platform-msi.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * MSI framework for platform devices
  3. *
  4. * Copyright (C) 2015 ARM Limited, All Rights Reserved.
  5. * Author: Marc Zyngier <marc.zyngier@arm.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <linux/device.h>
  20. #include <linux/idr.h>
  21. #include <linux/irq.h>
  22. #include <linux/irqdomain.h>
  23. #include <linux/msi.h>
  24. #include <linux/slab.h>
  25. #define DEV_ID_SHIFT 21
  26. #define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))
  27. /*
  28. * Internal data structure containing a (made up, but unique) devid
  29. * and the callback to write the MSI message.
  30. */
  31. struct platform_msi_priv_data {
  32. struct device *dev;
  33. void *host_data;
  34. msi_alloc_info_t arg;
  35. irq_write_msi_msg_t write_msg;
  36. int devid;
  37. };
  38. /* The devid allocator */
  39. static DEFINE_IDA(platform_msi_devid_ida);
  40. #ifdef GENERIC_MSI_DOMAIN_OPS
  41. /*
  42. * Convert an msi_desc to a globaly unique identifier (per-device
  43. * devid + msi_desc position in the msi_list).
  44. */
  45. static irq_hw_number_t platform_msi_calc_hwirq(struct msi_desc *desc)
  46. {
  47. u32 devid;
  48. devid = desc->platform.msi_priv_data->devid;
  49. return (devid << (32 - DEV_ID_SHIFT)) | desc->platform.msi_index;
  50. }
  51. static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
  52. {
  53. arg->desc = desc;
  54. arg->hwirq = platform_msi_calc_hwirq(desc);
  55. }
  56. static int platform_msi_init(struct irq_domain *domain,
  57. struct msi_domain_info *info,
  58. unsigned int virq, irq_hw_number_t hwirq,
  59. msi_alloc_info_t *arg)
  60. {
  61. return irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
  62. info->chip, info->chip_data);
  63. }
  64. #else
  65. #define platform_msi_set_desc NULL
  66. #define platform_msi_init NULL
  67. #endif
  68. static void platform_msi_update_dom_ops(struct msi_domain_info *info)
  69. {
  70. struct msi_domain_ops *ops = info->ops;
  71. BUG_ON(!ops);
  72. if (ops->msi_init == NULL)
  73. ops->msi_init = platform_msi_init;
  74. if (ops->set_desc == NULL)
  75. ops->set_desc = platform_msi_set_desc;
  76. }
  77. static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
  78. {
  79. struct msi_desc *desc = irq_data_get_msi_desc(data);
  80. struct platform_msi_priv_data *priv_data;
  81. priv_data = desc->platform.msi_priv_data;
  82. priv_data->write_msg(desc, msg);
  83. }
  84. static void platform_msi_update_chip_ops(struct msi_domain_info *info)
  85. {
  86. struct irq_chip *chip = info->chip;
  87. BUG_ON(!chip);
  88. if (!chip->irq_mask)
  89. chip->irq_mask = irq_chip_mask_parent;
  90. if (!chip->irq_unmask)
  91. chip->irq_unmask = irq_chip_unmask_parent;
  92. if (!chip->irq_eoi)
  93. chip->irq_eoi = irq_chip_eoi_parent;
  94. if (!chip->irq_set_affinity)
  95. chip->irq_set_affinity = msi_domain_set_affinity;
  96. if (!chip->irq_write_msi_msg)
  97. chip->irq_write_msi_msg = platform_msi_write_msg;
  98. }
  99. static void platform_msi_free_descs(struct device *dev, int base, int nvec)
  100. {
  101. struct msi_desc *desc, *tmp;
  102. list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
  103. if (desc->platform.msi_index >= base &&
  104. desc->platform.msi_index < (base + nvec)) {
  105. list_del(&desc->list);
  106. free_msi_entry(desc);
  107. }
  108. }
  109. }
  110. static int platform_msi_alloc_descs_with_irq(struct device *dev, int virq,
  111. int nvec,
  112. struct platform_msi_priv_data *data)
  113. {
  114. struct msi_desc *desc;
  115. int i, base = 0;
  116. if (!list_empty(dev_to_msi_list(dev))) {
  117. desc = list_last_entry(dev_to_msi_list(dev),
  118. struct msi_desc, list);
  119. base = desc->platform.msi_index + 1;
  120. }
  121. for (i = 0; i < nvec; i++) {
  122. desc = alloc_msi_entry(dev, 1, NULL);
  123. if (!desc)
  124. break;
  125. desc->platform.msi_priv_data = data;
  126. desc->platform.msi_index = base + i;
  127. desc->irq = virq ? virq + i : 0;
  128. list_add_tail(&desc->list, dev_to_msi_list(dev));
  129. }
  130. if (i != nvec) {
  131. /* Clean up the mess */
  132. platform_msi_free_descs(dev, base, nvec);
  133. return -ENOMEM;
  134. }
  135. return 0;
  136. }
  137. static int platform_msi_alloc_descs(struct device *dev, int nvec,
  138. struct platform_msi_priv_data *data)
  139. {
  140. return platform_msi_alloc_descs_with_irq(dev, 0, nvec, data);
  141. }
  142. /**
  143. * platform_msi_create_irq_domain - Create a platform MSI interrupt domain
  144. * @fwnode: Optional fwnode of the interrupt controller
  145. * @info: MSI domain info
  146. * @parent: Parent irq domain
  147. *
  148. * Updates the domain and chip ops and creates a platform MSI
  149. * interrupt domain.
  150. *
  151. * Returns:
  152. * A domain pointer or NULL in case of failure.
  153. */
  154. struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
  155. struct msi_domain_info *info,
  156. struct irq_domain *parent)
  157. {
  158. struct irq_domain *domain;
  159. if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
  160. platform_msi_update_dom_ops(info);
  161. if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
  162. platform_msi_update_chip_ops(info);
  163. domain = msi_create_irq_domain(fwnode, info, parent);
  164. if (domain)
  165. domain->bus_token = DOMAIN_BUS_PLATFORM_MSI;
  166. return domain;
  167. }
  168. static struct platform_msi_priv_data *
  169. platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
  170. irq_write_msi_msg_t write_msi_msg)
  171. {
  172. struct platform_msi_priv_data *datap;
  173. /*
  174. * Limit the number of interrupts to 256 per device. Should we
  175. * need to bump this up, DEV_ID_SHIFT should be adjusted
  176. * accordingly (which would impact the max number of MSI
  177. * capable devices).
  178. */
  179. if (!dev->msi_domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS)
  180. return ERR_PTR(-EINVAL);
  181. if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) {
  182. dev_err(dev, "Incompatible msi_domain, giving up\n");
  183. return ERR_PTR(-EINVAL);
  184. }
  185. /* Already had a helping of MSI? Greed... */
  186. if (!list_empty(dev_to_msi_list(dev)))
  187. return ERR_PTR(-EBUSY);
  188. datap = kzalloc(sizeof(*datap), GFP_KERNEL);
  189. if (!datap)
  190. return ERR_PTR(-ENOMEM);
  191. datap->devid = ida_simple_get(&platform_msi_devid_ida,
  192. 0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
  193. if (datap->devid < 0) {
  194. int err = datap->devid;
  195. kfree(datap);
  196. return ERR_PTR(err);
  197. }
  198. datap->write_msg = write_msi_msg;
  199. datap->dev = dev;
  200. return datap;
  201. }
  202. static void platform_msi_free_priv_data(struct platform_msi_priv_data *data)
  203. {
  204. ida_simple_remove(&platform_msi_devid_ida, data->devid);
  205. kfree(data);
  206. }
  207. /**
  208. * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
  209. * @dev: The device for which to allocate interrupts
  210. * @nvec: The number of interrupts to allocate
  211. * @write_msi_msg: Callback to write an interrupt message for @dev
  212. *
  213. * Returns:
  214. * Zero for success, or an error code in case of failure
  215. */
  216. int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
  217. irq_write_msi_msg_t write_msi_msg)
  218. {
  219. struct platform_msi_priv_data *priv_data;
  220. int err;
  221. priv_data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
  222. if (IS_ERR(priv_data))
  223. return PTR_ERR(priv_data);
  224. err = platform_msi_alloc_descs(dev, nvec, priv_data);
  225. if (err)
  226. goto out_free_priv_data;
  227. err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec);
  228. if (err)
  229. goto out_free_desc;
  230. return 0;
  231. out_free_desc:
  232. platform_msi_free_descs(dev, 0, nvec);
  233. out_free_priv_data:
  234. platform_msi_free_priv_data(priv_data);
  235. return err;
  236. }
  237. EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);
  238. /**
  239. * platform_msi_domain_free_irqs - Free MSI interrupts for @dev
  240. * @dev: The device for which to free interrupts
  241. */
  242. void platform_msi_domain_free_irqs(struct device *dev)
  243. {
  244. if (!list_empty(dev_to_msi_list(dev))) {
  245. struct msi_desc *desc;
  246. desc = first_msi_entry(dev);
  247. platform_msi_free_priv_data(desc->platform.msi_priv_data);
  248. }
  249. msi_domain_free_irqs(dev->msi_domain, dev);
  250. platform_msi_free_descs(dev, 0, MAX_DEV_MSIS);
  251. }
  252. EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);
  253. /**
  254. * platform_msi_get_host_data - Query the private data associated with
  255. * a platform-msi domain
  256. * @domain: The platform-msi domain
  257. *
  258. * Returns the private data provided when calling
  259. * platform_msi_create_device_domain.
  260. */
  261. void *platform_msi_get_host_data(struct irq_domain *domain)
  262. {
  263. struct platform_msi_priv_data *data = domain->host_data;
  264. return data->host_data;
  265. }
  266. /**
  267. * platform_msi_create_device_domain - Create a platform-msi domain
  268. *
  269. * @dev: The device generating the MSIs
  270. * @nvec: The number of MSIs that need to be allocated
  271. * @write_msi_msg: Callback to write an interrupt message for @dev
  272. * @ops: The hierarchy domain operations to use
  273. * @host_data: Private data associated to this domain
  274. *
  275. * Returns an irqdomain for @nvec interrupts
  276. */
  277. struct irq_domain *
  278. platform_msi_create_device_domain(struct device *dev,
  279. unsigned int nvec,
  280. irq_write_msi_msg_t write_msi_msg,
  281. const struct irq_domain_ops *ops,
  282. void *host_data)
  283. {
  284. struct platform_msi_priv_data *data;
  285. struct irq_domain *domain;
  286. int err;
  287. data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
  288. if (IS_ERR(data))
  289. return NULL;
  290. data->host_data = host_data;
  291. domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
  292. of_node_to_fwnode(dev->of_node),
  293. ops, data);
  294. if (!domain)
  295. goto free_priv;
  296. err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg);
  297. if (err)
  298. goto free_domain;
  299. return domain;
  300. free_domain:
  301. irq_domain_remove(domain);
  302. free_priv:
  303. platform_msi_free_priv_data(data);
  304. return NULL;
  305. }
  306. /**
  307. * platform_msi_domain_free - Free interrupts associated with a platform-msi
  308. * domain
  309. *
  310. * @domain: The platform-msi domain
  311. * @virq: The base irq from which to perform the free operation
  312. * @nvec: How many interrupts to free from @virq
  313. */
  314. void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
  315. unsigned int nvec)
  316. {
  317. struct platform_msi_priv_data *data = domain->host_data;
  318. struct msi_desc *desc;
  319. for_each_msi_entry(desc, data->dev) {
  320. if (WARN_ON(!desc->irq || desc->nvec_used != 1))
  321. return;
  322. if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
  323. continue;
  324. irq_domain_free_irqs_common(domain, desc->irq, 1);
  325. }
  326. }
  327. /**
  328. * platform_msi_domain_alloc - Allocate interrupts associated with
  329. * a platform-msi domain
  330. *
  331. * @domain: The platform-msi domain
  332. * @virq: The base irq from which to perform the allocate operation
  333. * @nvec: How many interrupts to free from @virq
  334. *
  335. * Return 0 on success, or an error code on failure. Must be called
  336. * with irq_domain_mutex held (which can only be done as part of a
  337. * top-level interrupt allocation).
  338. */
  339. int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
  340. unsigned int nr_irqs)
  341. {
  342. struct platform_msi_priv_data *data = domain->host_data;
  343. int err;
  344. err = platform_msi_alloc_descs_with_irq(data->dev, virq, nr_irqs, data);
  345. if (err)
  346. return err;
  347. err = msi_domain_populate_irqs(domain->parent, data->dev,
  348. virq, nr_irqs, &data->arg);
  349. if (err)
  350. platform_msi_domain_free(domain, virq, nr_irqs);
  351. return err;
  352. }