ipa_rm_resource.c 30 KB

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