ipa_rm_resource.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/slab.h>
  13. #include "ipa_i.h"
  14. #include "ipa_rm_resource.h"
  15. #include "ipa_rm_i.h"
  16. /**
  17. * ipa_rm_dep_prod_index() - producer name to producer index mapping
  18. * @resource_name: [in] resource name (should be of producer)
  19. *
  20. * Returns: resource index mapping, IPA_RM_INDEX_INVALID
  21. * in case provided resource name isn't contained
  22. * in enum ipa_rm_resource_name or is not of producers.
  23. *
  24. */
  25. int ipa_rm_prod_index(enum ipa_rm_resource_name resource_name)
  26. {
  27. int result = resource_name;
  28. switch (resource_name) {
  29. case IPA_RM_RESOURCE_BRIDGE_PROD:
  30. case IPA_RM_RESOURCE_A2_PROD:
  31. case IPA_RM_RESOURCE_USB_PROD:
  32. case IPA_RM_RESOURCE_HSIC_PROD:
  33. case IPA_RM_RESOURCE_STD_ECM_PROD:
  34. case IPA_RM_RESOURCE_WWAN_0_PROD:
  35. case IPA_RM_RESOURCE_WWAN_1_PROD:
  36. case IPA_RM_RESOURCE_WWAN_2_PROD:
  37. case IPA_RM_RESOURCE_WWAN_3_PROD:
  38. case IPA_RM_RESOURCE_WWAN_4_PROD:
  39. case IPA_RM_RESOURCE_WWAN_5_PROD:
  40. case IPA_RM_RESOURCE_WWAN_6_PROD:
  41. case IPA_RM_RESOURCE_WWAN_7_PROD:
  42. case IPA_RM_RESOURCE_WLAN_PROD:
  43. break;
  44. default:
  45. result = IPA_RM_INDEX_INVALID;
  46. break;
  47. }
  48. return result;
  49. }
  50. /**
  51. * ipa_rm_cons_index() - consumer name to consumer index mapping
  52. * @resource_name: [in] resource name (should be of consumer)
  53. *
  54. * Returns: resource index mapping, IPA_RM_INDEX_INVALID
  55. * in case provided resource name isn't contained
  56. * in enum ipa_rm_resource_name or is not of consumers.
  57. *
  58. */
  59. int ipa_rm_cons_index(enum ipa_rm_resource_name resource_name)
  60. {
  61. int result = resource_name;
  62. switch (resource_name) {
  63. case IPA_RM_RESOURCE_A2_CONS:
  64. case IPA_RM_RESOURCE_USB_CONS:
  65. case IPA_RM_RESOURCE_HSIC_CONS:
  66. break;
  67. default:
  68. result = IPA_RM_INDEX_INVALID;
  69. break;
  70. }
  71. return result;
  72. }
  73. static int ipa_rm_resource_consumer_request(
  74. struct ipa_rm_resource_cons *consumer)
  75. {
  76. int result = 0;
  77. int driver_result;
  78. unsigned long flags;
  79. IPADBG("IPA RM ::%s name %d ENTER\n",
  80. __func__, consumer->resource.name);
  81. spin_lock_irqsave(&consumer->resource.state_lock, flags);
  82. switch (consumer->resource.state) {
  83. case IPA_RM_RELEASED:
  84. case IPA_RM_RELEASE_IN_PROGRESS:
  85. {
  86. enum ipa_rm_resource_state prev_state =
  87. consumer->resource.state;
  88. consumer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
  89. spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
  90. driver_result = consumer->request_resource();
  91. spin_lock_irqsave(&consumer->resource.state_lock, flags);
  92. if (driver_result == 0)
  93. consumer->resource.state = IPA_RM_GRANTED;
  94. else if (driver_result != -EINPROGRESS) {
  95. consumer->resource.state = prev_state;
  96. result = driver_result;
  97. goto bail;
  98. }
  99. result = driver_result;
  100. break;
  101. }
  102. case IPA_RM_GRANTED:
  103. break;
  104. case IPA_RM_REQUEST_IN_PROGRESS:
  105. result = -EINPROGRESS;
  106. break;
  107. default:
  108. result = -EPERM;
  109. goto bail;
  110. }
  111. consumer->usage_count++;
  112. bail:
  113. spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
  114. IPADBG("IPA RM ::ipa_rm_resource_consumer_request EXIT [%d]\n", result);
  115. return result;
  116. }
  117. static int ipa_rm_resource_consumer_release(
  118. struct ipa_rm_resource_cons *consumer)
  119. {
  120. int result = 0;
  121. int driver_result;
  122. unsigned long flags;
  123. enum ipa_rm_resource_state save_state;
  124. IPADBG("IPA RM ::%s name %d ENTER\n",
  125. __func__, consumer->resource.name);
  126. spin_lock_irqsave(&consumer->resource.state_lock, flags);
  127. switch (consumer->resource.state) {
  128. case IPA_RM_RELEASED:
  129. break;
  130. case IPA_RM_GRANTED:
  131. case IPA_RM_REQUEST_IN_PROGRESS:
  132. if (consumer->usage_count > 0)
  133. consumer->usage_count--;
  134. if (consumer->usage_count == 0) {
  135. save_state = consumer->resource.state;
  136. consumer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
  137. spin_unlock_irqrestore(&consumer->resource.state_lock,
  138. flags);
  139. driver_result = consumer->release_resource();
  140. spin_lock_irqsave(&consumer->resource.state_lock,
  141. flags);
  142. if (driver_result == 0)
  143. consumer->resource.state = IPA_RM_RELEASED;
  144. else if (driver_result != -EINPROGRESS)
  145. consumer->resource.state = save_state;
  146. result = driver_result;
  147. }
  148. break;
  149. case IPA_RM_RELEASE_IN_PROGRESS:
  150. if (consumer->usage_count > 0)
  151. consumer->usage_count--;
  152. result = -EINPROGRESS;
  153. break;
  154. default:
  155. result = -EPERM;
  156. goto bail;
  157. }
  158. bail:
  159. spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
  160. IPADBG("IPA RM ::ipa_rm_resource_consumer_release EXIT [%d]\n", result);
  161. return result;
  162. }
  163. /**
  164. * ipa_rm_resource_producer_notify_clients() - notify
  165. * all registered clients of given producer
  166. * @producer: producer
  167. * @event: event to notify
  168. * @notify_registered_only: notify only clients registered by
  169. * ipa_rm_register()
  170. */
  171. void ipa_rm_resource_producer_notify_clients(
  172. struct ipa_rm_resource_prod *producer,
  173. enum ipa_rm_event event,
  174. bool notify_registered_only)
  175. {
  176. struct ipa_rm_notification_info *reg_info, *reg_info_cloned;
  177. struct list_head *pos, *q;
  178. LIST_HEAD(cloned_list);
  179. read_lock(&producer->event_listeners_lock);
  180. list_for_each(pos, &(producer->event_listeners)) {
  181. reg_info = list_entry(pos,
  182. struct ipa_rm_notification_info,
  183. link);
  184. if (notify_registered_only && !reg_info->explicit)
  185. continue;
  186. reg_info_cloned = kzalloc(sizeof(*reg_info_cloned), GFP_ATOMIC);
  187. if (!reg_info_cloned)
  188. goto clone_list_failed;
  189. reg_info_cloned->reg_params.notify_cb =
  190. reg_info->reg_params.notify_cb;
  191. reg_info_cloned->reg_params.user_data =
  192. reg_info->reg_params.user_data;
  193. list_add(&reg_info_cloned->link, &cloned_list);
  194. }
  195. read_unlock(&producer->event_listeners_lock);
  196. list_for_each_safe(pos, q, &cloned_list) {
  197. reg_info = list_entry(pos,
  198. struct ipa_rm_notification_info,
  199. link);
  200. reg_info->reg_params.notify_cb(
  201. reg_info->reg_params.user_data,
  202. event,
  203. 0);
  204. list_del(pos);
  205. kfree(reg_info);
  206. }
  207. return;
  208. clone_list_failed:
  209. read_unlock(&producer->event_listeners_lock);
  210. }
  211. static int ipa_rm_resource_producer_create(struct ipa_rm_resource **resource,
  212. struct ipa_rm_resource_prod **producer,
  213. struct ipa_rm_create_params *create_params,
  214. int *max_peers)
  215. {
  216. int result = 0;
  217. *producer = kzalloc(sizeof(**producer), GFP_KERNEL);
  218. if (*producer == NULL) {
  219. result = -ENOMEM;
  220. goto bail;
  221. }
  222. rwlock_init(&(*producer)->event_listeners_lock);
  223. INIT_LIST_HEAD(&((*producer)->event_listeners));
  224. result = ipa_rm_resource_producer_register(*producer,
  225. &(create_params->reg_params),
  226. false);
  227. if (result)
  228. goto register_fail;
  229. (*resource) = (struct ipa_rm_resource *) (*producer);
  230. (*resource)->type = IPA_RM_PRODUCER;
  231. *max_peers = IPA_RM_RESOURCE_CONS_MAX;
  232. goto bail;
  233. register_fail:
  234. kfree(*producer);
  235. bail:
  236. return result;
  237. }
  238. static void ipa_rm_resource_producer_delete(
  239. struct ipa_rm_resource_prod *producer)
  240. {
  241. struct ipa_rm_notification_info *reg_info;
  242. struct list_head *pos, *q;
  243. write_lock(&producer->event_listeners_lock);
  244. list_for_each_safe(pos, q, &(producer->event_listeners)) {
  245. reg_info = list_entry(pos,
  246. struct ipa_rm_notification_info,
  247. link);
  248. list_del(pos);
  249. kfree(reg_info);
  250. }
  251. write_unlock(&producer->event_listeners_lock);
  252. }
  253. static int ipa_rm_resource_consumer_create(struct ipa_rm_resource **resource,
  254. struct ipa_rm_resource_cons **consumer,
  255. struct ipa_rm_create_params *create_params,
  256. int *max_peers)
  257. {
  258. int result = 0;
  259. *consumer = kzalloc(sizeof(**consumer), GFP_KERNEL);
  260. if (*consumer == NULL) {
  261. result = -ENOMEM;
  262. goto bail;
  263. }
  264. (*consumer)->request_resource = create_params->request_resource;
  265. (*consumer)->release_resource = create_params->release_resource;
  266. (*resource) = (struct ipa_rm_resource *) (*consumer);
  267. (*resource)->type = IPA_RM_CONSUMER;
  268. *max_peers = IPA_RM_RESOURCE_PROD_MAX;
  269. bail:
  270. return result;
  271. }
  272. /**
  273. * ipa_rm_resource_create() - creates resource
  274. * @create_params: [in] parameters needed
  275. * for resource initialization with IPA RM
  276. * @resource: [out] created resource
  277. *
  278. * Returns: 0 on success, negative on failure
  279. */
  280. int ipa_rm_resource_create(
  281. struct ipa_rm_create_params *create_params,
  282. struct ipa_rm_resource **resource)
  283. {
  284. struct ipa_rm_resource_cons *consumer;
  285. struct ipa_rm_resource_prod *producer;
  286. int max_peers;
  287. int result = 0;
  288. if (!create_params) {
  289. result = -EINVAL;
  290. goto bail;
  291. }
  292. if (IPA_RM_RESORCE_IS_PROD(create_params->name)) {
  293. result = ipa_rm_resource_producer_create(resource,
  294. &producer,
  295. create_params,
  296. &max_peers);
  297. if (result)
  298. goto bail;
  299. } else if (IPA_RM_RESORCE_IS_CONS(create_params->name)) {
  300. result = ipa_rm_resource_consumer_create(resource,
  301. &consumer,
  302. create_params,
  303. &max_peers);
  304. if (result)
  305. goto bail;
  306. } else {
  307. result = -EPERM;
  308. goto bail;
  309. }
  310. result = ipa_rm_peers_list_create(max_peers,
  311. &((*resource)->peers_list));
  312. if (result)
  313. goto peers_alloc_fail;
  314. (*resource)->name = create_params->name;
  315. (*resource)->state = IPA_RM_RELEASED;
  316. spin_lock_init(&((*resource)->state_lock));
  317. goto bail;
  318. peers_alloc_fail:
  319. ipa_rm_resource_delete(*resource);
  320. bail:
  321. return result;
  322. }
  323. /**
  324. * ipa_rm_resource_delete() - deletes resource
  325. * @resource: [in] resource
  326. * for resource initialization with IPA RM
  327. *
  328. * Returns: 0 on success, negative on failure
  329. */
  330. int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
  331. {
  332. struct ipa_rm_resource *consumer, *producer;
  333. int peers_index, result = 0, list_size;
  334. IPADBG("ipa_rm_resource_delete ENTER with resource %d\n",
  335. resource->name);
  336. if (!resource) {
  337. IPADBG("ipa_rm_resource_delete ENTER with invalid param\n");
  338. return -EINVAL;
  339. }
  340. if (resource->type == IPA_RM_PRODUCER) {
  341. if (resource->peers_list) {
  342. list_size = ipa_rm_peers_list_get_size(
  343. resource->peers_list);
  344. for (peers_index = 0;
  345. peers_index < list_size;
  346. peers_index++) {
  347. consumer = ipa_rm_peers_list_get_resource(
  348. peers_index,
  349. resource->peers_list);
  350. if (consumer)
  351. ipa_rm_resource_delete_dependency(
  352. resource,
  353. consumer);
  354. }
  355. ipa_rm_peers_list_delete(resource->peers_list);
  356. }
  357. ipa_rm_resource_producer_delete(
  358. (struct ipa_rm_resource_prod *) resource);
  359. kfree((struct ipa_rm_resource_prod *) resource);
  360. } else if (resource->type == IPA_RM_CONSUMER) {
  361. if (resource->peers_list) {
  362. list_size = ipa_rm_peers_list_get_size(
  363. resource->peers_list);
  364. for (peers_index = 0;
  365. peers_index < list_size;
  366. peers_index++){
  367. producer = ipa_rm_peers_list_get_resource(
  368. peers_index,
  369. resource->peers_list);
  370. if (producer)
  371. ipa_rm_resource_delete_dependency(
  372. producer,
  373. resource);
  374. }
  375. ipa_rm_peers_list_delete(resource->peers_list);
  376. }
  377. kfree((struct ipa_rm_resource_cons *) resource);
  378. }
  379. IPADBG("ipa_rm_resource_delete SUCCESS\n");
  380. return result;
  381. }
  382. /**
  383. * ipa_rm_resource_register() - register resource
  384. * @resource: [in] resource
  385. * @reg_params: [in] registration parameters
  386. * @explicit: [in] registered explicitly by ipa_rm_register()
  387. *
  388. * Returns: 0 on success, negative on failure
  389. *
  390. * Producer resource is expected for this call.
  391. *
  392. */
  393. int ipa_rm_resource_producer_register(struct ipa_rm_resource_prod *producer,
  394. struct ipa_rm_register_params *reg_params,
  395. bool explicit)
  396. {
  397. int result = 0;
  398. struct ipa_rm_notification_info *reg_info;
  399. struct list_head *pos;
  400. if (!producer || !reg_params) {
  401. result = -EPERM;
  402. goto bail;
  403. }
  404. IPADBG("IPA RM: %s name %d ENTER\n",
  405. __func__, producer->resource.name);
  406. read_lock(&producer->event_listeners_lock);
  407. list_for_each(pos, &(producer->event_listeners)) {
  408. reg_info = list_entry(pos,
  409. struct ipa_rm_notification_info,
  410. link);
  411. if (reg_info->reg_params.notify_cb ==
  412. reg_params->notify_cb) {
  413. result = -EPERM;
  414. read_unlock(&producer->event_listeners_lock);
  415. goto bail;
  416. }
  417. }
  418. read_unlock(&producer->event_listeners_lock);
  419. reg_info = kzalloc(sizeof(*reg_info), GFP_KERNEL);
  420. if (reg_info == NULL) {
  421. result = -ENOMEM;
  422. goto bail;
  423. }
  424. reg_info->reg_params.user_data = reg_params->user_data;
  425. reg_info->reg_params.notify_cb = reg_params->notify_cb;
  426. reg_info->explicit = explicit;
  427. INIT_LIST_HEAD(&reg_info->link);
  428. write_lock(&producer->event_listeners_lock);
  429. list_add(&reg_info->link, &producer->event_listeners);
  430. write_unlock(&producer->event_listeners_lock);
  431. bail:
  432. return result;
  433. }
  434. /**
  435. * ipa_rm_resource_deregister() - register resource
  436. * @resource: [in] resource
  437. * @reg_params: [in] registration parameters
  438. *
  439. * Returns: 0 on success, negative on failure
  440. *
  441. * Producer resource is expected for this call.
  442. * This function deleted only single instance of
  443. * registration info.
  444. *
  445. */
  446. int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
  447. struct ipa_rm_register_params *reg_params)
  448. {
  449. int result = -EINVAL;
  450. struct ipa_rm_notification_info *reg_info;
  451. struct list_head *pos, *q;
  452. if (!producer || !reg_params)
  453. return -EINVAL;
  454. write_lock(&producer->event_listeners_lock);
  455. list_for_each_safe(pos, q, &(producer->event_listeners)) {
  456. reg_info = list_entry(pos,
  457. struct ipa_rm_notification_info,
  458. link);
  459. if (reg_info->reg_params.notify_cb ==
  460. reg_params->notify_cb) {
  461. list_del(pos);
  462. kfree(reg_info);
  463. result = 0;
  464. goto bail;
  465. }
  466. }
  467. bail:
  468. write_unlock(&producer->event_listeners_lock);
  469. return result;
  470. }
  471. /**
  472. * ipa_rm_resource_add_dependency() - add dependency between two
  473. * given resources
  474. * @resource: [in] resource resource
  475. * @depends_on: [in] depends_on resource
  476. *
  477. * Returns: 0 on success, negative on failure
  478. */
  479. int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
  480. struct ipa_rm_resource *depends_on)
  481. {
  482. int result = 0;
  483. unsigned long flags;
  484. int consumer_result;
  485. if (!resource || !depends_on)
  486. return -EINVAL;
  487. if (ipa_rm_peers_list_check_dependency(resource->peers_list,
  488. resource->name,
  489. depends_on->peers_list,
  490. depends_on->name))
  491. return -EEXIST;
  492. ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
  493. ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
  494. spin_lock_irqsave(&resource->state_lock, flags);
  495. switch (resource->state) {
  496. case IPA_RM_RELEASED:
  497. case IPA_RM_RELEASE_IN_PROGRESS:
  498. break;
  499. case IPA_RM_GRANTED:
  500. case IPA_RM_REQUEST_IN_PROGRESS:
  501. {
  502. enum ipa_rm_resource_state prev_state = resource->state;
  503. resource->state = IPA_RM_REQUEST_IN_PROGRESS;
  504. ((struct ipa_rm_resource_prod *)
  505. resource)->pending_request++;
  506. spin_unlock_irqrestore(&resource->state_lock, flags);
  507. consumer_result = ipa_rm_resource_consumer_request(
  508. (struct ipa_rm_resource_cons *)depends_on);
  509. spin_lock_irqsave(&resource->state_lock, flags);
  510. if (consumer_result != -EINPROGRESS) {
  511. resource->state = prev_state;
  512. ((struct ipa_rm_resource_prod *)
  513. resource)->pending_request--;
  514. }
  515. result = consumer_result;
  516. break;
  517. }
  518. default:
  519. result = -EPERM;
  520. goto bail;
  521. }
  522. bail:
  523. spin_unlock_irqrestore(&resource->state_lock, flags);
  524. IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
  525. resource->name, resource->peers_list->peers_count);
  526. IPADBG("IPA RM ipa_rm_resource_add_dependency name[%d]count[%d]EXIT\n",
  527. depends_on->name, depends_on->peers_list->peers_count);
  528. return result;
  529. }
  530. /**
  531. * ipa_rm_resource_delete_dependency() - add dependency between two
  532. * given resources
  533. * @resource: [in] resource resource
  534. * @depends_on: [in] depends_on resource
  535. *
  536. * Returns: 0 on success, negative on failure
  537. * EINPROGRESS is returned in case this is the last dependency
  538. * of given resource and IPA RM client should receive the RELEASED cb
  539. */
  540. int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
  541. struct ipa_rm_resource *depends_on)
  542. {
  543. int result = 0;
  544. unsigned long flags;
  545. unsigned long consumer_flags;
  546. bool state_changed = false;
  547. bool release_consumer = false;
  548. if (!resource || !depends_on)
  549. return -EINVAL;
  550. IPADBG("IPA RM: %s from %d to %d ENTER\n",
  551. __func__,
  552. resource->name,
  553. depends_on->name);
  554. if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
  555. resource->name,
  556. depends_on->peers_list,
  557. depends_on->name))
  558. return -EINVAL;
  559. spin_lock_irqsave(&resource->state_lock, flags);
  560. switch (resource->state) {
  561. case IPA_RM_RELEASED:
  562. break;
  563. case IPA_RM_GRANTED:
  564. release_consumer = true;
  565. break;
  566. case IPA_RM_RELEASE_IN_PROGRESS:
  567. if (((struct ipa_rm_resource_prod *)
  568. resource)->pending_release > 0)
  569. ((struct ipa_rm_resource_prod *)
  570. resource)->pending_release--;
  571. spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
  572. if (depends_on->state == IPA_RM_RELEASE_IN_PROGRESS &&
  573. ((struct ipa_rm_resource_prod *)
  574. resource)->pending_release == 0) {
  575. resource->state = IPA_RM_RELEASED;
  576. state_changed = true;
  577. }
  578. spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
  579. break;
  580. case IPA_RM_REQUEST_IN_PROGRESS:
  581. release_consumer = true;
  582. if (((struct ipa_rm_resource_prod *)
  583. resource)->pending_request > 0)
  584. ((struct ipa_rm_resource_prod *)
  585. resource)->pending_request--;
  586. spin_lock_irqsave(&depends_on->state_lock, consumer_flags);
  587. if (depends_on->state == IPA_RM_REQUEST_IN_PROGRESS &&
  588. ((struct ipa_rm_resource_prod *)
  589. resource)->pending_request == 0) {
  590. resource->state = IPA_RM_GRANTED;
  591. state_changed = true;
  592. }
  593. spin_unlock_irqrestore(&depends_on->state_lock, consumer_flags);
  594. break;
  595. default:
  596. result = -EINVAL;
  597. spin_unlock_irqrestore(&resource->state_lock, flags);
  598. goto bail;
  599. }
  600. if (state_changed &&
  601. ipa_rm_peers_list_has_last_peer(resource->peers_list)) {
  602. (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
  603. resource->name,
  604. resource->state,
  605. false);
  606. result = -EINPROGRESS;
  607. }
  608. spin_unlock_irqrestore(&resource->state_lock, flags);
  609. ipa_rm_peers_list_remove_peer(resource->peers_list,
  610. depends_on->name);
  611. ipa_rm_peers_list_remove_peer(depends_on->peers_list,
  612. resource->name);
  613. if (release_consumer)
  614. (void) ipa_rm_resource_consumer_release(
  615. (struct ipa_rm_resource_cons *)depends_on);
  616. IPADBG("IPA RM: %s from %d to %d SUCCESS\n",
  617. __func__,
  618. resource->name,
  619. depends_on->name);
  620. bail:
  621. return result;
  622. }
  623. /**
  624. * ipa_rm_resource_producer_request() - producer resource request
  625. * @producer: [in] producer
  626. *
  627. * Returns: 0 on success, negative on failure
  628. */
  629. int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer)
  630. {
  631. int peers_index;
  632. int result = 0;
  633. unsigned long flags;
  634. struct ipa_rm_resource *consumer;
  635. int consumer_result;
  636. IPADBG("IPA RM ::ipa_rm_resource_producer_request [%d] ENTER\n",
  637. producer->resource.name);
  638. if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
  639. spin_lock_irqsave(&producer->resource.state_lock, flags);
  640. producer->resource.state = IPA_RM_GRANTED;
  641. (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
  642. producer->resource.name,
  643. IPA_RM_RESOURCE_GRANTED,
  644. true);
  645. result = 0;
  646. goto unlock_and_bail;
  647. }
  648. spin_lock_irqsave(&producer->resource.state_lock, flags);
  649. IPADBG("IPA RM ::ipa_rm_resource_producer_request state [%d]\n",
  650. producer->resource.state);
  651. switch (producer->resource.state) {
  652. case IPA_RM_RELEASED:
  653. case IPA_RM_RELEASE_IN_PROGRESS:
  654. producer->resource.state = IPA_RM_REQUEST_IN_PROGRESS;
  655. break;
  656. case IPA_RM_GRANTED:
  657. goto unlock_and_bail;
  658. case IPA_RM_REQUEST_IN_PROGRESS:
  659. result = -EINPROGRESS;
  660. goto unlock_and_bail;
  661. default:
  662. result = -EINVAL;
  663. goto unlock_and_bail;
  664. }
  665. producer->pending_request = 0;
  666. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  667. for (peers_index = 0;
  668. peers_index < ipa_rm_peers_list_get_size(
  669. producer->resource.peers_list);
  670. peers_index++) {
  671. consumer = ipa_rm_peers_list_get_resource(peers_index,
  672. producer->resource.peers_list);
  673. if (consumer) {
  674. spin_lock_irqsave(
  675. &producer->resource.state_lock, flags);
  676. producer->pending_request++;
  677. spin_unlock_irqrestore(
  678. &producer->resource.state_lock, flags);
  679. consumer_result = ipa_rm_resource_consumer_request(
  680. (struct ipa_rm_resource_cons *)consumer);
  681. if (consumer_result == -EINPROGRESS) {
  682. result = -EINPROGRESS;
  683. } else {
  684. spin_lock_irqsave(
  685. &producer->resource.state_lock, flags);
  686. producer->pending_request--;
  687. spin_unlock_irqrestore(
  688. &producer->resource.state_lock, flags);
  689. if (consumer_result != 0) {
  690. result = consumer_result;
  691. goto bail;
  692. }
  693. }
  694. }
  695. }
  696. spin_lock_irqsave(&producer->resource.state_lock, flags);
  697. if (producer->pending_request == 0) {
  698. producer->resource.state = IPA_RM_GRANTED;
  699. (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
  700. producer->resource.name,
  701. IPA_RM_RESOURCE_GRANTED,
  702. true);
  703. result = 0;
  704. }
  705. unlock_and_bail:
  706. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  707. bail:
  708. IPADBG("IPA RM ::ipa_rm_resource_producer_request EXIT[%d]\n", result);
  709. return result;
  710. }
  711. /**
  712. * ipa_rm_resource_producer_release() - producer resource release
  713. * producer: [in] producer resource
  714. *
  715. * Returns: 0 on success, negative on failure
  716. *
  717. */
  718. int ipa_rm_resource_producer_release(struct ipa_rm_resource_prod *producer)
  719. {
  720. int peers_index;
  721. int result = 0;
  722. unsigned long flags;
  723. struct ipa_rm_resource *consumer;
  724. int consumer_result;
  725. IPADBG("IPA RM: %s name %d ENTER\n",
  726. __func__,
  727. producer->resource.name);
  728. if (ipa_rm_peers_list_is_empty(producer->resource.peers_list)) {
  729. spin_lock_irqsave(&producer->resource.state_lock, flags);
  730. producer->resource.state = IPA_RM_RELEASED;
  731. (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
  732. producer->resource.name,
  733. IPA_RM_RESOURCE_RELEASED,
  734. true);
  735. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  736. return 0;
  737. }
  738. spin_lock_irqsave(&producer->resource.state_lock, flags);
  739. switch (producer->resource.state) {
  740. case IPA_RM_RELEASED:
  741. goto bail;
  742. case IPA_RM_GRANTED:
  743. case IPA_RM_REQUEST_IN_PROGRESS:
  744. producer->resource.state = IPA_RM_RELEASE_IN_PROGRESS;
  745. break;
  746. case IPA_RM_RELEASE_IN_PROGRESS:
  747. result = -EINPROGRESS;
  748. goto bail;
  749. default:
  750. result = -EPERM;
  751. goto bail;
  752. }
  753. producer->pending_release = 0;
  754. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  755. for (peers_index = 0;
  756. peers_index < ipa_rm_peers_list_get_size(
  757. producer->resource.peers_list);
  758. peers_index++) {
  759. consumer = ipa_rm_peers_list_get_resource(peers_index,
  760. producer->resource.peers_list);
  761. if (consumer) {
  762. spin_lock_irqsave(
  763. &producer->resource.state_lock, flags);
  764. producer->pending_release++;
  765. spin_unlock_irqrestore(
  766. &producer->resource.state_lock, flags);
  767. consumer_result = ipa_rm_resource_consumer_release(
  768. (struct ipa_rm_resource_cons *)consumer);
  769. spin_lock_irqsave(
  770. &producer->resource.state_lock, flags);
  771. producer->pending_release--;
  772. spin_unlock_irqrestore(
  773. &producer->resource.state_lock, flags);
  774. }
  775. }
  776. spin_lock_irqsave(&producer->resource.state_lock, flags);
  777. if (producer->pending_release == 0) {
  778. producer->resource.state = IPA_RM_RELEASED;
  779. (void) ipa_rm_wq_send_cmd(IPA_RM_WQ_NOTIFY_PROD,
  780. producer->resource.name,
  781. IPA_RM_RESOURCE_RELEASED,
  782. true);
  783. }
  784. bail:
  785. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  786. IPADBG("IPA RM ::ipa_rm_resource_producer_release EXIT[%d]\n", result);
  787. return result;
  788. }
  789. static void ipa_rm_resource_producer_handle_cb(
  790. struct ipa_rm_resource_prod *producer,
  791. enum ipa_rm_event event)
  792. {
  793. unsigned long flags;
  794. spin_lock_irqsave(&producer->resource.state_lock, flags);
  795. switch (producer->resource.state) {
  796. case IPA_RM_REQUEST_IN_PROGRESS:
  797. if (event != IPA_RM_RESOURCE_GRANTED)
  798. goto unlock_and_bail;
  799. if (producer->pending_request > 0) {
  800. producer->pending_request--;
  801. if (producer->pending_request == 0) {
  802. producer->resource.state =
  803. IPA_RM_GRANTED;
  804. spin_unlock_irqrestore(
  805. &producer->resource.state_lock, flags);
  806. ipa_rm_resource_producer_notify_clients(
  807. producer,
  808. IPA_RM_RESOURCE_GRANTED,
  809. false);
  810. goto bail;
  811. }
  812. }
  813. break;
  814. case IPA_RM_RELEASE_IN_PROGRESS:
  815. if (event != IPA_RM_RESOURCE_RELEASED)
  816. goto unlock_and_bail;
  817. if (producer->pending_release > 0) {
  818. producer->pending_release--;
  819. if (producer->pending_release == 0) {
  820. producer->resource.state =
  821. IPA_RM_RELEASED;
  822. spin_unlock_irqrestore(
  823. &producer->resource.state_lock, flags);
  824. ipa_rm_resource_producer_notify_clients(
  825. producer,
  826. IPA_RM_RESOURCE_RELEASED,
  827. false);
  828. goto bail;
  829. }
  830. }
  831. break;
  832. case IPA_RM_GRANTED:
  833. case IPA_RM_RELEASED:
  834. default:
  835. goto unlock_and_bail;
  836. }
  837. unlock_and_bail:
  838. spin_unlock_irqrestore(&producer->resource.state_lock, flags);
  839. bail:
  840. return;
  841. }
  842. /**
  843. * ipa_rm_resource_consumer_handle_cb() - propagates resource
  844. * notification to all dependent producers
  845. * @consumer: [in] notifying resource
  846. *
  847. */
  848. void ipa_rm_resource_consumer_handle_cb(struct ipa_rm_resource_cons *consumer,
  849. enum ipa_rm_event event)
  850. {
  851. int peers_index;
  852. struct ipa_rm_resource *producer;
  853. unsigned long flags;
  854. if (!consumer)
  855. return;
  856. spin_lock_irqsave(&consumer->resource.state_lock, flags);
  857. switch (consumer->resource.state) {
  858. case IPA_RM_REQUEST_IN_PROGRESS:
  859. if (event == IPA_RM_RESOURCE_RELEASED)
  860. goto bail;
  861. consumer->resource.state = IPA_RM_GRANTED;
  862. break;
  863. case IPA_RM_RELEASE_IN_PROGRESS:
  864. if (event == IPA_RM_RESOURCE_GRANTED)
  865. goto bail;
  866. consumer->resource.state = IPA_RM_RELEASED;
  867. break;
  868. case IPA_RM_GRANTED:
  869. case IPA_RM_RELEASED:
  870. default:
  871. goto bail;
  872. }
  873. spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
  874. for (peers_index = 0;
  875. peers_index < ipa_rm_peers_list_get_size(
  876. consumer->resource.peers_list);
  877. peers_index++) {
  878. producer = ipa_rm_peers_list_get_resource(peers_index,
  879. consumer->resource.peers_list);
  880. if (producer)
  881. ipa_rm_resource_producer_handle_cb(
  882. (struct ipa_rm_resource_prod *)
  883. producer,
  884. event);
  885. }
  886. return;
  887. bail:
  888. spin_unlock_irqrestore(&consumer->resource.state_lock, flags);
  889. return;
  890. }
  891. /*
  892. * ipa_rm_resource_producer_print_stat() - print the
  893. * resource status and all his dependencies
  894. *
  895. * @resource: [in] Resource resource
  896. * @buff: [in] The buf used to print
  897. * @size: [in] Buf size
  898. *
  899. * Returns: number of bytes used on success, negative on failure
  900. */
  901. int ipa_rm_resource_producer_print_stat(
  902. struct ipa_rm_resource *resource,
  903. char *buf,
  904. int size){
  905. int i, nbytes, cnt = 0;
  906. unsigned long flags;
  907. struct ipa_rm_resource *consumer;
  908. if (!buf || size < 0)
  909. return -EINVAL;
  910. switch (resource->name) {
  911. case IPA_RM_RESOURCE_BRIDGE_PROD:
  912. nbytes = scnprintf(buf + cnt, size - cnt,
  913. "BRIDGE_PROD[");
  914. cnt += nbytes;
  915. break;
  916. case IPA_RM_RESOURCE_A2_PROD:
  917. nbytes = scnprintf(buf + cnt, size - cnt,
  918. "A2_PROD[");
  919. cnt += nbytes;
  920. break;
  921. case IPA_RM_RESOURCE_USB_PROD:
  922. nbytes = scnprintf(buf + cnt, size - cnt,
  923. "USB_PROD[");
  924. cnt += nbytes;
  925. break;
  926. case IPA_RM_RESOURCE_HSIC_PROD:
  927. nbytes = scnprintf(buf + cnt, size - cnt,
  928. "HSIC_PROD[");
  929. cnt += nbytes;
  930. break;
  931. case IPA_RM_RESOURCE_STD_ECM_PROD:
  932. nbytes = scnprintf(buf + cnt, size - cnt,
  933. "STD_ECM_PROD[");
  934. cnt += nbytes;
  935. break;
  936. case IPA_RM_RESOURCE_WWAN_0_PROD:
  937. nbytes = scnprintf(buf + cnt, size - cnt,
  938. "WWAN_0_PROD[");
  939. cnt += nbytes;
  940. break;
  941. case IPA_RM_RESOURCE_WWAN_1_PROD:
  942. nbytes = scnprintf(buf + cnt, size - cnt,
  943. "WWAN_1_PROD[");
  944. cnt += nbytes;
  945. break;
  946. case IPA_RM_RESOURCE_WWAN_2_PROD:
  947. nbytes = scnprintf(buf + cnt, size - cnt,
  948. "WWAN_2_PROD[");
  949. cnt += nbytes;
  950. break;
  951. case IPA_RM_RESOURCE_WWAN_3_PROD:
  952. nbytes = scnprintf(buf + cnt, size - cnt,
  953. "WWAN_3_PROD[");
  954. cnt += nbytes;
  955. break;
  956. case IPA_RM_RESOURCE_WWAN_4_PROD:
  957. nbytes = scnprintf(buf + cnt, size - cnt,
  958. "WWAN_4_PROD[");
  959. cnt += nbytes;
  960. break;
  961. case IPA_RM_RESOURCE_WWAN_5_PROD:
  962. nbytes = scnprintf(buf + cnt, size - cnt,
  963. "WWAN_5_PROD[");
  964. cnt += nbytes;
  965. break;
  966. case IPA_RM_RESOURCE_WWAN_6_PROD:
  967. nbytes = scnprintf(buf + cnt, size - cnt,
  968. "WWAN_6_PROD[");
  969. cnt += nbytes;
  970. break;
  971. case IPA_RM_RESOURCE_WWAN_7_PROD:
  972. nbytes = scnprintf(buf + cnt, size - cnt,
  973. "WWAN_7_PROD[");
  974. cnt += nbytes;
  975. break;
  976. case IPA_RM_RESOURCE_WLAN_PROD:
  977. nbytes = scnprintf(buf + cnt, size - cnt,
  978. "WLAN_PROD[");
  979. cnt += nbytes;
  980. break;
  981. default:
  982. return -EPERM;
  983. }
  984. spin_lock_irqsave(&resource->state_lock, flags);
  985. switch (resource->state) {
  986. case IPA_RM_RELEASED:
  987. nbytes = scnprintf(buf + cnt, size - cnt,
  988. "Released] -> ");
  989. cnt += nbytes;
  990. break;
  991. case IPA_RM_REQUEST_IN_PROGRESS:
  992. nbytes = scnprintf(buf + cnt, size - cnt,
  993. "Request In Progress] -> ");
  994. cnt += nbytes;
  995. break;
  996. case IPA_RM_GRANTED:
  997. nbytes = scnprintf(buf + cnt, size - cnt,
  998. "Granted] -> ");
  999. cnt += nbytes;
  1000. break;
  1001. case IPA_RM_RELEASE_IN_PROGRESS:
  1002. nbytes = scnprintf(buf + cnt, size - cnt,
  1003. "Release In Progress] -> ");
  1004. cnt += nbytes;
  1005. break;
  1006. default:
  1007. spin_unlock_irqrestore(
  1008. &resource->state_lock,
  1009. flags);
  1010. return -EPERM;
  1011. }
  1012. spin_unlock_irqrestore(
  1013. &resource->state_lock,
  1014. flags);
  1015. for (i = 0; i < resource->peers_list->max_peers; ++i) {
  1016. consumer =
  1017. ipa_rm_peers_list_get_resource(
  1018. i,
  1019. resource->peers_list);
  1020. if (consumer) {
  1021. switch (consumer->name) {
  1022. case IPA_RM_RESOURCE_A2_CONS:
  1023. nbytes = scnprintf(buf + cnt,
  1024. size - cnt,
  1025. " A2_CONS[");
  1026. cnt += nbytes;
  1027. break;
  1028. case IPA_RM_RESOURCE_USB_CONS:
  1029. nbytes = scnprintf(buf + cnt,
  1030. size - cnt,
  1031. " USB_CONS[");
  1032. cnt += nbytes;
  1033. break;
  1034. case IPA_RM_RESOURCE_HSIC_CONS:
  1035. nbytes = scnprintf(buf + cnt,
  1036. size - cnt,
  1037. " HSIC_CONS[");
  1038. cnt += nbytes;
  1039. break;
  1040. default:
  1041. return -EPERM;
  1042. }
  1043. spin_lock_irqsave(&consumer->state_lock, flags);
  1044. switch (consumer->state) {
  1045. case IPA_RM_RELEASED:
  1046. nbytes = scnprintf(buf + cnt, size - cnt,
  1047. "Released], ");
  1048. cnt += nbytes;
  1049. break;
  1050. case IPA_RM_REQUEST_IN_PROGRESS:
  1051. nbytes = scnprintf(buf + cnt, size - cnt,
  1052. "Request In Progress], ");
  1053. cnt += nbytes;
  1054. break;
  1055. case IPA_RM_GRANTED:
  1056. nbytes = scnprintf(buf + cnt, size - cnt,
  1057. "Granted], ");
  1058. cnt += nbytes;
  1059. break;
  1060. case IPA_RM_RELEASE_IN_PROGRESS:
  1061. nbytes = scnprintf(buf + cnt, size - cnt,
  1062. "Release In Progress], ");
  1063. cnt += nbytes;
  1064. break;
  1065. default:
  1066. spin_unlock_irqrestore(
  1067. &consumer->state_lock,
  1068. flags);
  1069. return -EPERM;
  1070. }
  1071. spin_unlock_irqrestore(
  1072. &consumer->state_lock,
  1073. flags);
  1074. }
  1075. }
  1076. nbytes = scnprintf(buf + cnt, size - cnt,
  1077. "\n");
  1078. cnt += nbytes;
  1079. return cnt;
  1080. }