dprc-driver.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Freescale data path resource container (DPRC) driver
  4. *
  5. * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
  6. * Copyright 2019-2020 NXP
  7. * Author: German Rivera <German.Rivera@freescale.com>
  8. *
  9. */
  10. #include <linux/module.h>
  11. #include <linux/slab.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/msi.h>
  14. #include <linux/fsl/mc.h>
  15. #include "fsl-mc-private.h"
  16. #define FSL_MC_DPRC_DRIVER_NAME "fsl_mc_dprc"
  17. struct fsl_mc_child_objs {
  18. int child_count;
  19. struct fsl_mc_obj_desc *child_array;
  20. };
  21. static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev,
  22. struct fsl_mc_obj_desc *obj_desc)
  23. {
  24. return mc_dev->obj_desc.id == obj_desc->id &&
  25. strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0;
  26. }
  27. static bool fsl_mc_obj_desc_is_allocatable(struct fsl_mc_obj_desc *obj)
  28. {
  29. if (strcmp(obj->type, "dpmcp") == 0 ||
  30. strcmp(obj->type, "dpcon") == 0 ||
  31. strcmp(obj->type, "dpbp") == 0)
  32. return true;
  33. else
  34. return false;
  35. }
  36. static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
  37. {
  38. int i;
  39. struct fsl_mc_child_objs *objs;
  40. struct fsl_mc_device *mc_dev;
  41. mc_dev = to_fsl_mc_device(dev);
  42. objs = data;
  43. for (i = 0; i < objs->child_count; i++) {
  44. struct fsl_mc_obj_desc *obj_desc = &objs->child_array[i];
  45. if (strlen(obj_desc->type) != 0 &&
  46. fsl_mc_device_match(mc_dev, obj_desc))
  47. break;
  48. }
  49. if (i == objs->child_count)
  50. fsl_mc_device_remove(mc_dev);
  51. return 0;
  52. }
  53. static int __fsl_mc_device_remove(struct device *dev, void *data)
  54. {
  55. fsl_mc_device_remove(to_fsl_mc_device(dev));
  56. return 0;
  57. }
  58. /**
  59. * dprc_remove_devices - Removes devices for objects removed from a DPRC
  60. *
  61. * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
  62. * @obj_desc_array: array of object descriptors for child objects currently
  63. * present in the DPRC in the MC.
  64. * @num_child_objects_in_mc: number of entries in obj_desc_array
  65. *
  66. * Synchronizes the state of the Linux bus driver with the actual state of
  67. * the MC by removing devices that represent MC objects that have
  68. * been dynamically removed in the physical DPRC.
  69. */
  70. void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev,
  71. struct fsl_mc_obj_desc *obj_desc_array,
  72. int num_child_objects_in_mc)
  73. {
  74. if (num_child_objects_in_mc != 0) {
  75. /*
  76. * Remove child objects that are in the DPRC in Linux,
  77. * but not in the MC:
  78. */
  79. struct fsl_mc_child_objs objs;
  80. objs.child_count = num_child_objects_in_mc;
  81. objs.child_array = obj_desc_array;
  82. device_for_each_child(&mc_bus_dev->dev, &objs,
  83. __fsl_mc_device_remove_if_not_in_mc);
  84. } else {
  85. /*
  86. * There are no child objects for this DPRC in the MC.
  87. * So, remove all the child devices from Linux:
  88. */
  89. device_for_each_child(&mc_bus_dev->dev, NULL,
  90. __fsl_mc_device_remove);
  91. }
  92. }
  93. EXPORT_SYMBOL_GPL(dprc_remove_devices);
  94. static int __fsl_mc_device_match(struct device *dev, void *data)
  95. {
  96. struct fsl_mc_obj_desc *obj_desc = data;
  97. struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
  98. return fsl_mc_device_match(mc_dev, obj_desc);
  99. }
  100. struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
  101. struct fsl_mc_device *mc_bus_dev)
  102. {
  103. struct device *dev;
  104. dev = device_find_child(&mc_bus_dev->dev, obj_desc,
  105. __fsl_mc_device_match);
  106. return dev ? to_fsl_mc_device(dev) : NULL;
  107. }
  108. /**
  109. * check_plugged_state_change - Check change in an MC object's plugged state
  110. *
  111. * @mc_dev: pointer to the fsl-mc device for a given MC object
  112. * @obj_desc: pointer to the MC object's descriptor in the MC
  113. *
  114. * If the plugged state has changed from unplugged to plugged, the fsl-mc
  115. * device is bound to the corresponding device driver.
  116. * If the plugged state has changed from plugged to unplugged, the fsl-mc
  117. * device is unbound from the corresponding device driver.
  118. */
  119. static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
  120. struct fsl_mc_obj_desc *obj_desc)
  121. {
  122. int error;
  123. u32 plugged_flag_at_mc =
  124. obj_desc->state & FSL_MC_OBJ_STATE_PLUGGED;
  125. if (plugged_flag_at_mc !=
  126. (mc_dev->obj_desc.state & FSL_MC_OBJ_STATE_PLUGGED)) {
  127. if (plugged_flag_at_mc) {
  128. mc_dev->obj_desc.state |= FSL_MC_OBJ_STATE_PLUGGED;
  129. error = device_attach(&mc_dev->dev);
  130. if (error < 0) {
  131. dev_err(&mc_dev->dev,
  132. "device_attach() failed: %d\n",
  133. error);
  134. }
  135. } else {
  136. mc_dev->obj_desc.state &= ~FSL_MC_OBJ_STATE_PLUGGED;
  137. device_release_driver(&mc_dev->dev);
  138. }
  139. }
  140. }
  141. static void fsl_mc_obj_device_add(struct fsl_mc_device *mc_bus_dev,
  142. struct fsl_mc_obj_desc *obj_desc)
  143. {
  144. int error;
  145. struct fsl_mc_device *child_dev;
  146. /*
  147. * Check if device is already known to Linux:
  148. */
  149. child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
  150. if (child_dev) {
  151. check_plugged_state_change(child_dev, obj_desc);
  152. put_device(&child_dev->dev);
  153. } else {
  154. error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
  155. &child_dev);
  156. if (error < 0)
  157. return;
  158. }
  159. }
  160. /**
  161. * dprc_add_new_devices - Adds devices to the logical bus for a DPRC
  162. *
  163. * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
  164. * @obj_desc_array: array of device descriptors for child devices currently
  165. * present in the physical DPRC.
  166. * @num_child_objects_in_mc: number of entries in obj_desc_array
  167. *
  168. * Synchronizes the state of the Linux bus driver with the actual
  169. * state of the MC by adding objects that have been newly discovered
  170. * in the physical DPRC.
  171. */
  172. static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
  173. struct fsl_mc_obj_desc *obj_desc_array,
  174. int num_child_objects_in_mc)
  175. {
  176. int i;
  177. /* probe the allocable objects first */
  178. for (i = 0; i < num_child_objects_in_mc; i++) {
  179. struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
  180. if (strlen(obj_desc->type) > 0 &&
  181. fsl_mc_obj_desc_is_allocatable(obj_desc))
  182. fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
  183. }
  184. for (i = 0; i < num_child_objects_in_mc; i++) {
  185. struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
  186. if (strlen(obj_desc->type) > 0 &&
  187. !fsl_mc_obj_desc_is_allocatable(obj_desc))
  188. fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
  189. }
  190. }
  191. /**
  192. * dprc_scan_objects - Discover objects in a DPRC
  193. *
  194. * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
  195. * @alloc_interrupts: if true the function allocates the interrupt pool,
  196. * otherwise the interrupt allocation is delayed
  197. *
  198. * Detects objects added and removed from a DPRC and synchronizes the
  199. * state of the Linux bus driver, MC by adding and removing
  200. * devices accordingly.
  201. * Two types of devices can be found in a DPRC: allocatable objects (e.g.,
  202. * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni).
  203. * All allocatable devices needed to be probed before all non-allocatable
  204. * devices, to ensure that device drivers for non-allocatable
  205. * devices can allocate any type of allocatable devices.
  206. * That is, we need to ensure that the corresponding resource pools are
  207. * populated before they can get allocation requests from probe callbacks
  208. * of the device drivers for the non-allocatable devices.
  209. */
  210. static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
  211. bool alloc_interrupts)
  212. {
  213. int num_child_objects;
  214. int dprc_get_obj_failures;
  215. int error;
  216. unsigned int irq_count = mc_bus_dev->obj_desc.irq_count;
  217. struct fsl_mc_obj_desc *child_obj_desc_array = NULL;
  218. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
  219. error = dprc_get_obj_count(mc_bus_dev->mc_io,
  220. 0,
  221. mc_bus_dev->mc_handle,
  222. &num_child_objects);
  223. if (error < 0) {
  224. dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n",
  225. error);
  226. return error;
  227. }
  228. if (num_child_objects != 0) {
  229. int i;
  230. child_obj_desc_array =
  231. devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects,
  232. sizeof(*child_obj_desc_array),
  233. GFP_KERNEL);
  234. if (!child_obj_desc_array)
  235. return -ENOMEM;
  236. /*
  237. * Discover objects currently present in the physical DPRC:
  238. */
  239. dprc_get_obj_failures = 0;
  240. for (i = 0; i < num_child_objects; i++) {
  241. struct fsl_mc_obj_desc *obj_desc =
  242. &child_obj_desc_array[i];
  243. error = dprc_get_obj(mc_bus_dev->mc_io,
  244. 0,
  245. mc_bus_dev->mc_handle,
  246. i, obj_desc);
  247. if (error < 0) {
  248. dev_err(&mc_bus_dev->dev,
  249. "dprc_get_obj(i=%d) failed: %d\n",
  250. i, error);
  251. /*
  252. * Mark the obj entry as "invalid", by using the
  253. * empty string as obj type:
  254. */
  255. obj_desc->type[0] = '\0';
  256. obj_desc->id = error;
  257. dprc_get_obj_failures++;
  258. continue;
  259. }
  260. /*
  261. * add a quirk for all versions of dpsec < 4.0...none
  262. * are coherent regardless of what the MC reports.
  263. */
  264. if ((strcmp(obj_desc->type, "dpseci") == 0) &&
  265. (obj_desc->ver_major < 4))
  266. obj_desc->flags |=
  267. FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY;
  268. irq_count += obj_desc->irq_count;
  269. dev_dbg(&mc_bus_dev->dev,
  270. "Discovered object: type %s, id %d\n",
  271. obj_desc->type, obj_desc->id);
  272. }
  273. if (dprc_get_obj_failures != 0) {
  274. dev_err(&mc_bus_dev->dev,
  275. "%d out of %d devices could not be retrieved\n",
  276. dprc_get_obj_failures, num_child_objects);
  277. }
  278. }
  279. /*
  280. * Allocate IRQ's before binding the scanned devices with their
  281. * respective drivers.
  282. */
  283. if (dev_get_msi_domain(&mc_bus_dev->dev)) {
  284. if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
  285. dev_warn(&mc_bus_dev->dev,
  286. "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
  287. irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
  288. }
  289. if (alloc_interrupts && !mc_bus->irq_resources) {
  290. error = fsl_mc_populate_irq_pool(mc_bus_dev,
  291. FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
  292. if (error < 0)
  293. return error;
  294. }
  295. }
  296. dprc_remove_devices(mc_bus_dev, child_obj_desc_array,
  297. num_child_objects);
  298. dprc_add_new_devices(mc_bus_dev, child_obj_desc_array,
  299. num_child_objects);
  300. if (child_obj_desc_array)
  301. devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
  302. return 0;
  303. }
  304. /**
  305. * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state
  306. *
  307. * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object
  308. *
  309. * Scans the physical DPRC and synchronizes the state of the Linux
  310. * bus driver with the actual state of the MC by adding and removing
  311. * devices as appropriate.
  312. */
  313. int dprc_scan_container(struct fsl_mc_device *mc_bus_dev,
  314. bool alloc_interrupts)
  315. {
  316. int error = 0;
  317. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
  318. fsl_mc_init_all_resource_pools(mc_bus_dev);
  319. /*
  320. * Discover objects in the DPRC:
  321. */
  322. mutex_lock(&mc_bus->scan_mutex);
  323. error = dprc_scan_objects(mc_bus_dev, alloc_interrupts);
  324. mutex_unlock(&mc_bus->scan_mutex);
  325. return error;
  326. }
  327. EXPORT_SYMBOL_GPL(dprc_scan_container);
  328. /**
  329. * dprc_irq0_handler - Regular ISR for DPRC interrupt 0
  330. *
  331. * @irq: IRQ number of the interrupt being handled
  332. * @arg: Pointer to device structure
  333. */
  334. static irqreturn_t dprc_irq0_handler(int irq_num, void *arg)
  335. {
  336. return IRQ_WAKE_THREAD;
  337. }
  338. /**
  339. * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0
  340. *
  341. * @irq: IRQ number of the interrupt being handled
  342. * @arg: Pointer to device structure
  343. */
  344. static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg)
  345. {
  346. int error;
  347. u32 status;
  348. struct device *dev = arg;
  349. struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
  350. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
  351. struct fsl_mc_io *mc_io = mc_dev->mc_io;
  352. struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc;
  353. dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n",
  354. irq_num, smp_processor_id());
  355. if (!(mc_dev->flags & FSL_MC_IS_DPRC))
  356. return IRQ_HANDLED;
  357. mutex_lock(&mc_bus->scan_mutex);
  358. if (!msi_desc || msi_desc->irq != (u32)irq_num)
  359. goto out;
  360. status = 0;
  361. error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
  362. &status);
  363. if (error < 0) {
  364. dev_err(dev,
  365. "dprc_get_irq_status() failed: %d\n", error);
  366. goto out;
  367. }
  368. error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0,
  369. status);
  370. if (error < 0) {
  371. dev_err(dev,
  372. "dprc_clear_irq_status() failed: %d\n", error);
  373. goto out;
  374. }
  375. if (status & (DPRC_IRQ_EVENT_OBJ_ADDED |
  376. DPRC_IRQ_EVENT_OBJ_REMOVED |
  377. DPRC_IRQ_EVENT_CONTAINER_DESTROYED |
  378. DPRC_IRQ_EVENT_OBJ_DESTROYED |
  379. DPRC_IRQ_EVENT_OBJ_CREATED)) {
  380. error = dprc_scan_objects(mc_dev, true);
  381. if (error < 0) {
  382. /*
  383. * If the error is -ENXIO, we ignore it, as it indicates
  384. * that the object scan was aborted, as we detected that
  385. * an object was removed from the DPRC in the MC, while
  386. * we were scanning the DPRC.
  387. */
  388. if (error != -ENXIO) {
  389. dev_err(dev, "dprc_scan_objects() failed: %d\n",
  390. error);
  391. }
  392. goto out;
  393. }
  394. }
  395. out:
  396. mutex_unlock(&mc_bus->scan_mutex);
  397. return IRQ_HANDLED;
  398. }
  399. /*
  400. * Disable and clear interrupt for a given DPRC object
  401. */
  402. static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
  403. {
  404. int error;
  405. struct fsl_mc_io *mc_io = mc_dev->mc_io;
  406. /*
  407. * Disable generation of interrupt, while we configure it:
  408. */
  409. error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0);
  410. if (error < 0) {
  411. dev_err(&mc_dev->dev,
  412. "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
  413. error);
  414. return error;
  415. }
  416. /*
  417. * Disable all interrupt causes for the interrupt:
  418. */
  419. error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0);
  420. if (error < 0) {
  421. dev_err(&mc_dev->dev,
  422. "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
  423. error);
  424. return error;
  425. }
  426. /*
  427. * Clear any leftover interrupts:
  428. */
  429. error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U);
  430. if (error < 0) {
  431. dev_err(&mc_dev->dev,
  432. "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n",
  433. error);
  434. return error;
  435. }
  436. return 0;
  437. }
  438. static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
  439. {
  440. int error;
  441. struct fsl_mc_device_irq *irq = mc_dev->irqs[0];
  442. /*
  443. * NOTE: devm_request_threaded_irq() invokes the device-specific
  444. * function that programs the MSI physically in the device
  445. */
  446. error = devm_request_threaded_irq(&mc_dev->dev,
  447. irq->msi_desc->irq,
  448. dprc_irq0_handler,
  449. dprc_irq0_handler_thread,
  450. IRQF_NO_SUSPEND | IRQF_ONESHOT,
  451. dev_name(&mc_dev->dev),
  452. &mc_dev->dev);
  453. if (error < 0) {
  454. dev_err(&mc_dev->dev,
  455. "devm_request_threaded_irq() failed: %d\n",
  456. error);
  457. return error;
  458. }
  459. return 0;
  460. }
  461. static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
  462. {
  463. int error;
  464. /*
  465. * Enable all interrupt causes for the interrupt:
  466. */
  467. error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0,
  468. ~0x0u);
  469. if (error < 0) {
  470. dev_err(&mc_dev->dev,
  471. "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
  472. error);
  473. return error;
  474. }
  475. /*
  476. * Enable generation of the interrupt:
  477. */
  478. error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1);
  479. if (error < 0) {
  480. dev_err(&mc_dev->dev,
  481. "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
  482. error);
  483. return error;
  484. }
  485. return 0;
  486. }
  487. /*
  488. * Setup interrupt for a given DPRC device
  489. */
  490. static int dprc_setup_irq(struct fsl_mc_device *mc_dev)
  491. {
  492. int error;
  493. error = fsl_mc_allocate_irqs(mc_dev);
  494. if (error < 0)
  495. return error;
  496. error = disable_dprc_irq(mc_dev);
  497. if (error < 0)
  498. goto error_free_irqs;
  499. error = register_dprc_irq_handler(mc_dev);
  500. if (error < 0)
  501. goto error_free_irqs;
  502. error = enable_dprc_irq(mc_dev);
  503. if (error < 0)
  504. goto error_free_irqs;
  505. return 0;
  506. error_free_irqs:
  507. fsl_mc_free_irqs(mc_dev);
  508. return error;
  509. }
  510. /**
  511. * dprc_setup - opens and creates a mc_io for DPRC
  512. *
  513. * @mc_dev: Pointer to fsl-mc device representing a DPRC
  514. *
  515. * It opens the physical DPRC in the MC.
  516. * It configures the DPRC portal used to communicate with MC
  517. */
  518. int dprc_setup(struct fsl_mc_device *mc_dev)
  519. {
  520. struct device *parent_dev = mc_dev->dev.parent;
  521. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
  522. struct irq_domain *mc_msi_domain;
  523. bool mc_io_created = false;
  524. bool msi_domain_set = false;
  525. u16 major_ver, minor_ver;
  526. size_t region_size;
  527. int error;
  528. if (!is_fsl_mc_bus_dprc(mc_dev))
  529. return -EINVAL;
  530. if (dev_get_msi_domain(&mc_dev->dev))
  531. return -EINVAL;
  532. if (!mc_dev->mc_io) {
  533. /*
  534. * This is a child DPRC:
  535. */
  536. if (!dev_is_fsl_mc(parent_dev))
  537. return -EINVAL;
  538. if (mc_dev->obj_desc.region_count == 0)
  539. return -EINVAL;
  540. region_size = resource_size(mc_dev->regions);
  541. error = fsl_create_mc_io(&mc_dev->dev,
  542. mc_dev->regions[0].start,
  543. region_size,
  544. NULL,
  545. FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
  546. &mc_dev->mc_io);
  547. if (error < 0)
  548. return error;
  549. mc_io_created = true;
  550. }
  551. mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev);
  552. if (!mc_msi_domain) {
  553. dev_warn(&mc_dev->dev,
  554. "WARNING: MC bus without interrupt support\n");
  555. } else {
  556. dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
  557. msi_domain_set = true;
  558. }
  559. error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
  560. &mc_dev->mc_handle);
  561. if (error < 0) {
  562. dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
  563. goto error_cleanup_msi_domain;
  564. }
  565. error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle,
  566. &mc_bus->dprc_attr);
  567. if (error < 0) {
  568. dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n",
  569. error);
  570. goto error_cleanup_open;
  571. }
  572. error = dprc_get_api_version(mc_dev->mc_io, 0,
  573. &major_ver,
  574. &minor_ver);
  575. if (error < 0) {
  576. dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n",
  577. error);
  578. goto error_cleanup_open;
  579. }
  580. if (major_ver < DPRC_MIN_VER_MAJOR ||
  581. (major_ver == DPRC_MIN_VER_MAJOR &&
  582. minor_ver < DPRC_MIN_VER_MINOR)) {
  583. dev_err(&mc_dev->dev,
  584. "ERROR: DPRC version %d.%d not supported\n",
  585. major_ver, minor_ver);
  586. error = -ENOTSUPP;
  587. goto error_cleanup_open;
  588. }
  589. return 0;
  590. error_cleanup_open:
  591. (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
  592. error_cleanup_msi_domain:
  593. if (msi_domain_set)
  594. dev_set_msi_domain(&mc_dev->dev, NULL);
  595. if (mc_io_created) {
  596. fsl_destroy_mc_io(mc_dev->mc_io);
  597. mc_dev->mc_io = NULL;
  598. }
  599. return error;
  600. }
  601. EXPORT_SYMBOL_GPL(dprc_setup);
  602. /**
  603. * dprc_probe - callback invoked when a DPRC is being bound to this driver
  604. *
  605. * @mc_dev: Pointer to fsl-mc device representing a DPRC
  606. *
  607. * It opens the physical DPRC in the MC.
  608. * It scans the DPRC to discover the MC objects contained in it.
  609. * It creates the interrupt pool for the MC bus associated with the DPRC.
  610. * It configures the interrupts for the DPRC device itself.
  611. */
  612. static int dprc_probe(struct fsl_mc_device *mc_dev)
  613. {
  614. int error;
  615. error = dprc_setup(mc_dev);
  616. if (error < 0)
  617. return error;
  618. /*
  619. * Discover MC objects in DPRC object:
  620. */
  621. error = dprc_scan_container(mc_dev, true);
  622. if (error < 0)
  623. goto dprc_cleanup;
  624. /*
  625. * Configure interrupt for the DPRC object associated with this MC bus:
  626. */
  627. error = dprc_setup_irq(mc_dev);
  628. if (error < 0)
  629. goto scan_cleanup;
  630. dev_info(&mc_dev->dev, "DPRC device bound to driver");
  631. return 0;
  632. scan_cleanup:
  633. device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
  634. dprc_cleanup:
  635. dprc_cleanup(mc_dev);
  636. return error;
  637. }
  638. /*
  639. * Tear down interrupt for a given DPRC object
  640. */
  641. static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
  642. {
  643. struct fsl_mc_device_irq *irq = mc_dev->irqs[0];
  644. (void)disable_dprc_irq(mc_dev);
  645. devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev);
  646. fsl_mc_free_irqs(mc_dev);
  647. }
  648. /**
  649. * dprc_cleanup - function that cleanups a DPRC
  650. *
  651. * @mc_dev: Pointer to fsl-mc device representing the DPRC
  652. *
  653. * It closes the DPRC device in the MC.
  654. * It destroys the interrupt pool associated with this MC bus.
  655. */
  656. int dprc_cleanup(struct fsl_mc_device *mc_dev)
  657. {
  658. int error;
  659. /* this function should be called only for DPRCs, it
  660. * is an error to call it for regular objects
  661. */
  662. if (!is_fsl_mc_bus_dprc(mc_dev))
  663. return -EINVAL;
  664. if (dev_get_msi_domain(&mc_dev->dev)) {
  665. fsl_mc_cleanup_irq_pool(mc_dev);
  666. dev_set_msi_domain(&mc_dev->dev, NULL);
  667. }
  668. fsl_mc_cleanup_all_resource_pools(mc_dev);
  669. /* if this step fails we cannot go further with cleanup as there is no way of
  670. * communicating with the firmware
  671. */
  672. if (!mc_dev->mc_io) {
  673. dev_err(&mc_dev->dev, "mc_io is NULL, tear down cannot be performed in firmware\n");
  674. return -EINVAL;
  675. }
  676. error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
  677. if (error < 0)
  678. dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error);
  679. if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
  680. fsl_destroy_mc_io(mc_dev->mc_io);
  681. mc_dev->mc_io = NULL;
  682. }
  683. return 0;
  684. }
  685. EXPORT_SYMBOL_GPL(dprc_cleanup);
  686. /**
  687. * dprc_remove - callback invoked when a DPRC is being unbound from this driver
  688. *
  689. * @mc_dev: Pointer to fsl-mc device representing the DPRC
  690. *
  691. * It removes the DPRC's child objects from Linux (not from the MC) and
  692. * closes the DPRC device in the MC.
  693. * It tears down the interrupts that were configured for the DPRC device.
  694. * It destroys the interrupt pool associated with this MC bus.
  695. */
  696. static int dprc_remove(struct fsl_mc_device *mc_dev)
  697. {
  698. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
  699. if (!is_fsl_mc_bus_dprc(mc_dev))
  700. return -EINVAL;
  701. if (!mc_bus->irq_resources)
  702. return -EINVAL;
  703. if (dev_get_msi_domain(&mc_dev->dev))
  704. dprc_teardown_irq(mc_dev);
  705. device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove);
  706. dprc_cleanup(mc_dev);
  707. dev_info(&mc_dev->dev, "DPRC device unbound from driver");
  708. return 0;
  709. }
  710. static const struct fsl_mc_device_id match_id_table[] = {
  711. {
  712. .vendor = FSL_MC_VENDOR_FREESCALE,
  713. .obj_type = "dprc"},
  714. {.vendor = 0x0},
  715. };
  716. static struct fsl_mc_driver dprc_driver = {
  717. .driver = {
  718. .name = FSL_MC_DPRC_DRIVER_NAME,
  719. .owner = THIS_MODULE,
  720. .pm = NULL,
  721. },
  722. .match_id_table = match_id_table,
  723. .probe = dprc_probe,
  724. .remove = dprc_remove,
  725. };
  726. int __init dprc_driver_init(void)
  727. {
  728. return fsl_mc_driver_register(&dprc_driver);
  729. }
  730. void dprc_driver_exit(void)
  731. {
  732. fsl_mc_driver_unregister(&dprc_driver);
  733. }