dprc-driver.c 22 KB

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