msm_prop.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include "msm_prop.h"
  6. void msm_property_init(struct msm_property_info *info,
  7. struct drm_mode_object *base,
  8. struct drm_device *dev,
  9. struct drm_property **property_array,
  10. struct msm_property_data *property_data,
  11. uint32_t property_count,
  12. uint32_t blob_count,
  13. uint32_t state_size)
  14. {
  15. /* prevent access if any of these are NULL */
  16. if (!base || !dev || !property_array || !property_data) {
  17. property_count = 0;
  18. blob_count = 0;
  19. DRM_ERROR("invalid arguments, forcing zero properties\n");
  20. return;
  21. }
  22. /* can't have more blob properties than total properties */
  23. if (blob_count > property_count) {
  24. blob_count = property_count;
  25. DBG("Capping number of blob properties to %d", blob_count);
  26. }
  27. if (!info) {
  28. DRM_ERROR("info pointer is NULL\n");
  29. } else {
  30. info->base = base;
  31. info->dev = dev;
  32. info->property_array = property_array;
  33. info->property_data = property_data;
  34. info->property_count = property_count;
  35. info->blob_count = blob_count;
  36. info->install_request = 0;
  37. info->install_count = 0;
  38. info->recent_idx = 0;
  39. info->is_active = false;
  40. info->state_size = state_size;
  41. info->state_cache_size = 0;
  42. mutex_init(&info->property_lock);
  43. memset(property_data,
  44. 0,
  45. sizeof(struct msm_property_data) *
  46. property_count);
  47. }
  48. }
  49. void msm_property_destroy(struct msm_property_info *info)
  50. {
  51. if (!info)
  52. return;
  53. /* free state cache */
  54. while (info->state_cache_size > 0)
  55. kfree(info->state_cache[--(info->state_cache_size)]);
  56. mutex_destroy(&info->property_lock);
  57. }
  58. int msm_property_pop_dirty(struct msm_property_info *info,
  59. struct msm_property_state *property_state)
  60. {
  61. struct list_head *item;
  62. int rc = 0;
  63. if (!info || !property_state || !property_state->values) {
  64. DRM_ERROR("invalid argument(s)\n");
  65. return -EINVAL;
  66. }
  67. WARN_ON(!mutex_is_locked(&info->property_lock));
  68. if (list_empty(&property_state->dirty_list)) {
  69. rc = -EAGAIN;
  70. } else {
  71. item = property_state->dirty_list.next;
  72. list_del_init(item);
  73. rc = container_of(item, struct msm_property_value, dirty_node)
  74. - property_state->values;
  75. DRM_DEBUG_KMS("property %d dirty\n", rc);
  76. }
  77. return rc;
  78. }
  79. /**
  80. * _msm_property_set_dirty_no_lock - flag given property as being dirty
  81. * This function doesn't mutex protect the
  82. * dirty linked list.
  83. * @info: Pointer to property info container struct
  84. * @property_state: Pointer to property state container struct
  85. * @property_idx: Property index
  86. */
  87. static void _msm_property_set_dirty_no_lock(
  88. struct msm_property_info *info,
  89. struct msm_property_state *property_state,
  90. uint32_t property_idx)
  91. {
  92. if (!info || !property_state || !property_state->values ||
  93. property_idx >= info->property_count) {
  94. DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
  95. return;
  96. }
  97. /* avoid re-inserting if already dirty */
  98. if (!list_empty(&property_state->values[property_idx].dirty_node)) {
  99. DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
  100. return;
  101. }
  102. list_add_tail(&property_state->values[property_idx].dirty_node,
  103. &property_state->dirty_list);
  104. }
  105. bool msm_property_is_dirty(
  106. struct msm_property_info *info,
  107. struct msm_property_state *property_state,
  108. uint32_t property_idx)
  109. {
  110. if (!info || !property_state || !property_state->values ||
  111. property_idx >= info->property_count) {
  112. DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
  113. return false;
  114. }
  115. return !list_empty(&property_state->values[property_idx].dirty_node);
  116. }
  117. /**
  118. * _msm_property_install_integer - install standard drm range property
  119. * @info: Pointer to property info container struct
  120. * @name: Property name
  121. * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE
  122. * @min: Min property value
  123. * @max: Max property value
  124. * @init: Default Property value
  125. * @property_idx: Property index
  126. * @force_dirty: Whether or not to filter 'dirty' status on unchanged values
  127. */
  128. static void _msm_property_install_integer(struct msm_property_info *info,
  129. const char *name, int flags, uint64_t min, uint64_t max,
  130. uint64_t init, uint32_t property_idx, bool force_dirty)
  131. {
  132. struct drm_property **prop;
  133. if (!info)
  134. return;
  135. ++info->install_request;
  136. if (!name || (property_idx >= info->property_count)) {
  137. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  138. } else {
  139. prop = &info->property_array[property_idx];
  140. /*
  141. * Properties need to be attached to each drm object that
  142. * uses them, but only need to be created once
  143. */
  144. if (!*prop) {
  145. *prop = drm_property_create_range(info->dev,
  146. flags, name, min, max);
  147. if (!*prop)
  148. DRM_ERROR("create %s property failed\n", name);
  149. }
  150. /* save init value for later */
  151. info->property_data[property_idx].default_value = init;
  152. info->property_data[property_idx].force_dirty = force_dirty;
  153. /* always attach property, if created */
  154. if (*prop) {
  155. drm_object_attach_property(info->base, *prop, init);
  156. ++info->install_count;
  157. }
  158. }
  159. }
  160. void msm_property_install_range(struct msm_property_info *info,
  161. const char *name, int flags, uint64_t min, uint64_t max,
  162. uint64_t init, uint32_t property_idx)
  163. {
  164. _msm_property_install_integer(info, name, flags,
  165. min, max, init, property_idx, false);
  166. }
  167. void msm_property_install_volatile_range(struct msm_property_info *info,
  168. const char *name, int flags, uint64_t min, uint64_t max,
  169. uint64_t init, uint32_t property_idx)
  170. {
  171. _msm_property_install_integer(info, name, flags,
  172. min, max, init, property_idx, true);
  173. }
  174. void msm_property_install_enum(struct msm_property_info *info,
  175. const char *name, int flags, int is_bitmask,
  176. const struct drm_prop_enum_list *values, int num_values,
  177. u32 init_idx, uint32_t property_idx)
  178. {
  179. struct drm_property **prop;
  180. if (!info)
  181. return;
  182. ++info->install_request;
  183. if (!name || !values || !num_values ||
  184. (property_idx >= info->property_count)) {
  185. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  186. } else {
  187. prop = &info->property_array[property_idx];
  188. /*
  189. * Properties need to be attached to each drm object that
  190. * uses them, but only need to be created once
  191. */
  192. if (!*prop) {
  193. /* 'bitmask' is a special type of 'enum' */
  194. if (is_bitmask)
  195. *prop = drm_property_create_bitmask(info->dev,
  196. DRM_MODE_PROP_BITMASK | flags,
  197. name, values, num_values, -1);
  198. else
  199. *prop = drm_property_create_enum(info->dev,
  200. DRM_MODE_PROP_ENUM | flags,
  201. name, values, num_values);
  202. if (!*prop)
  203. DRM_ERROR("create %s property failed\n", name);
  204. }
  205. /* save init value for later */
  206. info->property_data[property_idx].default_value = 0;
  207. info->property_data[property_idx].force_dirty = false;
  208. /* initialize with the given idx if valid */
  209. if (!is_bitmask && init_idx && (init_idx < num_values))
  210. info->property_data[property_idx].default_value =
  211. values[init_idx].type;
  212. /* always attach property, if created */
  213. if (*prop) {
  214. drm_object_attach_property(info->base, *prop,
  215. info->property_data
  216. [property_idx].default_value);
  217. ++info->install_count;
  218. }
  219. }
  220. }
  221. void msm_property_install_blob(struct msm_property_info *info,
  222. const char *name, int flags, uint32_t property_idx)
  223. {
  224. struct drm_property **prop;
  225. if (!info)
  226. return;
  227. ++info->install_request;
  228. if (!name || (property_idx >= info->blob_count)) {
  229. DRM_ERROR("invalid argument(s), %s\n", name ? name : "null");
  230. } else {
  231. prop = &info->property_array[property_idx];
  232. /*
  233. * Properties need to be attached to each drm object that
  234. * uses them, but only need to be created once
  235. */
  236. if (!*prop) {
  237. /* use 'create' for blob property place holder */
  238. *prop = drm_property_create(info->dev,
  239. DRM_MODE_PROP_BLOB | flags, name, 0);
  240. if (!*prop)
  241. DRM_ERROR("create %s property failed\n", name);
  242. }
  243. /* save init value for later */
  244. info->property_data[property_idx].default_value = 0;
  245. info->property_data[property_idx].force_dirty = true;
  246. /* always attach property, if created */
  247. if (*prop) {
  248. drm_object_attach_property(info->base, *prop, -1);
  249. ++info->install_count;
  250. }
  251. }
  252. }
  253. int msm_property_install_get_status(struct msm_property_info *info)
  254. {
  255. int rc = -ENOMEM;
  256. if (info && (info->install_request == info->install_count))
  257. rc = 0;
  258. return rc;
  259. }
  260. int msm_property_index(struct msm_property_info *info,
  261. struct drm_property *property)
  262. {
  263. uint32_t count;
  264. int32_t idx;
  265. int rc = -EINVAL;
  266. if (!info || !property) {
  267. DRM_ERROR("invalid argument(s)\n");
  268. } else {
  269. /*
  270. * Linear search, but start from last found index. This will
  271. * help if any single property is accessed multiple times in a
  272. * row. Ideally, we could keep a list of properties sorted in
  273. * the order of most recent access, but that may be overkill
  274. * for now.
  275. */
  276. mutex_lock(&info->property_lock);
  277. idx = info->recent_idx;
  278. count = info->property_count;
  279. while (count) {
  280. --count;
  281. /* stop searching on match */
  282. if (info->property_array[idx] == property) {
  283. info->recent_idx = idx;
  284. rc = idx;
  285. break;
  286. }
  287. /* move to next valid index */
  288. if (--idx < 0)
  289. idx = info->property_count - 1;
  290. }
  291. mutex_unlock(&info->property_lock);
  292. }
  293. return rc;
  294. }
  295. int msm_property_set_dirty(struct msm_property_info *info,
  296. struct msm_property_state *property_state,
  297. int property_idx)
  298. {
  299. if (!info || !property_state || !property_state->values) {
  300. DRM_ERROR("invalid argument(s)\n");
  301. return -EINVAL;
  302. }
  303. mutex_lock(&info->property_lock);
  304. _msm_property_set_dirty_no_lock(info, property_state, property_idx);
  305. mutex_unlock(&info->property_lock);
  306. return 0;
  307. }
  308. int msm_property_atomic_set(struct msm_property_info *info,
  309. struct msm_property_state *property_state,
  310. struct drm_property *property, uint64_t val)
  311. {
  312. struct drm_property_blob *blob;
  313. int property_idx, rc = -EINVAL;
  314. if (!info || !property_state) {
  315. DRM_ERROR("invalid argument(s)\n");
  316. return -EINVAL;
  317. }
  318. property_idx = msm_property_index(info, property);
  319. if ((property_idx == -EINVAL) || !property_state->values) {
  320. DRM_ERROR("invalid argument(s)\n");
  321. } else {
  322. /* extra handling for incoming properties */
  323. mutex_lock(&info->property_lock);
  324. if ((property->flags & DRM_MODE_PROP_BLOB) &&
  325. (property_idx < info->blob_count)) {
  326. /* need to clear previous ref */
  327. if (property_state->values[property_idx].blob)
  328. drm_property_blob_put(
  329. property_state->values[
  330. property_idx].blob);
  331. /* DRM lookup also takes a reference */
  332. blob = drm_property_lookup_blob(info->dev,
  333. (uint32_t)val);
  334. if (val && !blob) {
  335. DRM_ERROR("prop %d blob id 0x%llx not found\n",
  336. property_idx, val);
  337. val = 0;
  338. } else {
  339. if (blob) {
  340. DBG("Blob %u saved", blob->base.id);
  341. val = blob->base.id;
  342. }
  343. /* save the new blob */
  344. property_state->values[property_idx].blob =
  345. blob;
  346. }
  347. }
  348. /* update value and flag as dirty */
  349. if (property_state->values[property_idx].value != val ||
  350. info->property_data[property_idx].force_dirty) {
  351. property_state->values[property_idx].value = val;
  352. _msm_property_set_dirty_no_lock(info, property_state,
  353. property_idx);
  354. DBG("%s - %lld", property->name, val);
  355. }
  356. mutex_unlock(&info->property_lock);
  357. rc = 0;
  358. }
  359. return rc;
  360. }
  361. int msm_property_atomic_get(struct msm_property_info *info,
  362. struct msm_property_state *property_state,
  363. struct drm_property *property, uint64_t *val)
  364. {
  365. int property_idx, rc = -EINVAL;
  366. property_idx = msm_property_index(info, property);
  367. if (!info || (property_idx == -EINVAL) ||
  368. !property_state->values || !val) {
  369. DRM_DEBUG("Invalid argument(s)\n");
  370. } else {
  371. mutex_lock(&info->property_lock);
  372. *val = property_state->values[property_idx].value;
  373. mutex_unlock(&info->property_lock);
  374. rc = 0;
  375. }
  376. return rc;
  377. }
  378. void *msm_property_alloc_state(struct msm_property_info *info)
  379. {
  380. void *state = NULL;
  381. if (!info) {
  382. DRM_ERROR("invalid property info\n");
  383. return NULL;
  384. }
  385. mutex_lock(&info->property_lock);
  386. if (info->state_cache_size)
  387. state = info->state_cache[--(info->state_cache_size)];
  388. mutex_unlock(&info->property_lock);
  389. if (!state && info->state_size)
  390. state = kzalloc(info->state_size, GFP_KERNEL);
  391. if (!state)
  392. DRM_ERROR("failed to allocate state\n");
  393. return state;
  394. }
  395. /**
  396. * _msm_property_free_state - helper function for freeing local state objects
  397. * @info: Pointer to property info container struct
  398. * @st: Pointer to state object
  399. */
  400. static void _msm_property_free_state(struct msm_property_info *info, void *st)
  401. {
  402. if (!info || !st)
  403. return;
  404. mutex_lock(&info->property_lock);
  405. if (info->state_cache_size < MSM_PROP_STATE_CACHE_SIZE)
  406. info->state_cache[(info->state_cache_size)++] = st;
  407. else
  408. kfree(st);
  409. mutex_unlock(&info->property_lock);
  410. }
  411. void msm_property_reset_state(struct msm_property_info *info, void *state,
  412. struct msm_property_state *property_state,
  413. struct msm_property_value *property_values)
  414. {
  415. uint32_t i;
  416. if (!info) {
  417. DRM_ERROR("invalid property info\n");
  418. return;
  419. }
  420. if (state)
  421. memset(state, 0, info->state_size);
  422. if (property_state) {
  423. property_state->property_count = info->property_count;
  424. property_state->values = property_values;
  425. INIT_LIST_HEAD(&property_state->dirty_list);
  426. }
  427. /*
  428. * Assign default property values. This helper is mostly used
  429. * to initialize newly created state objects.
  430. */
  431. if (property_values)
  432. for (i = 0; i < info->property_count; ++i) {
  433. property_values[i].value =
  434. info->property_data[i].default_value;
  435. property_values[i].blob = NULL;
  436. INIT_LIST_HEAD(&property_values[i].dirty_node);
  437. }
  438. }
  439. void msm_property_duplicate_state(struct msm_property_info *info,
  440. void *old_state, void *state,
  441. struct msm_property_state *property_state,
  442. struct msm_property_value *property_values)
  443. {
  444. uint32_t i;
  445. if (!info || !old_state || !state) {
  446. DRM_ERROR("invalid argument(s)\n");
  447. return;
  448. }
  449. memcpy(state, old_state, info->state_size);
  450. if (!property_state)
  451. return;
  452. INIT_LIST_HEAD(&property_state->dirty_list);
  453. property_state->values = property_values;
  454. if (property_state->values)
  455. /* add ref count for blobs and initialize dirty nodes */
  456. for (i = 0; i < info->property_count; ++i) {
  457. if (property_state->values[i].blob)
  458. drm_property_blob_get(
  459. property_state->values[i].blob);
  460. INIT_LIST_HEAD(&property_state->values[i].dirty_node);
  461. }
  462. }
  463. void msm_property_destroy_state(struct msm_property_info *info, void *state,
  464. struct msm_property_state *property_state)
  465. {
  466. uint32_t i;
  467. if (!info || !state) {
  468. DRM_ERROR("invalid argument(s)\n");
  469. return;
  470. }
  471. if (property_state && property_state->values) {
  472. /* remove ref count for blobs */
  473. for (i = 0; i < info->property_count; ++i)
  474. if (property_state->values[i].blob) {
  475. drm_property_blob_put(
  476. property_state->values[i].blob);
  477. property_state->values[i].blob = NULL;
  478. }
  479. }
  480. _msm_property_free_state(info, state);
  481. }
  482. void *msm_property_get_blob(struct msm_property_info *info,
  483. struct msm_property_state *property_state,
  484. size_t *byte_len,
  485. uint32_t property_idx)
  486. {
  487. struct drm_property_blob *blob;
  488. size_t len = 0;
  489. void *rc = 0;
  490. if (!info || !property_state || !property_state->values ||
  491. (property_idx >= info->blob_count)) {
  492. DRM_ERROR("invalid argument(s)\n");
  493. } else {
  494. blob = property_state->values[property_idx].blob;
  495. if (blob) {
  496. len = blob->length;
  497. rc = blob->data;
  498. }
  499. }
  500. if (byte_len)
  501. *byte_len = len;
  502. return rc;
  503. }
  504. int msm_property_set_blob(struct msm_property_info *info,
  505. struct drm_property_blob **blob_reference,
  506. void *blob_data,
  507. size_t byte_len,
  508. uint32_t property_idx)
  509. {
  510. struct drm_property_blob *blob = NULL;
  511. int rc = -EINVAL;
  512. if (!info || !blob_reference || (property_idx >= info->blob_count)) {
  513. DRM_ERROR("invalid argument(s)\n");
  514. } else {
  515. /* create blob */
  516. if (blob_data && byte_len) {
  517. blob = drm_property_create_blob(info->dev,
  518. byte_len,
  519. blob_data);
  520. if (IS_ERR_OR_NULL(blob)) {
  521. rc = PTR_ERR(blob);
  522. DRM_ERROR("failed to create blob, %d\n", rc);
  523. goto exit;
  524. }
  525. }
  526. /* update drm object */
  527. rc = drm_object_property_set_value(info->base,
  528. info->property_array[property_idx],
  529. blob ? blob->base.id : 0);
  530. if (rc) {
  531. DRM_ERROR("failed to set blob to property\n");
  532. if (blob)
  533. drm_property_blob_put(blob);
  534. goto exit;
  535. }
  536. /* update local reference */
  537. if (*blob_reference)
  538. drm_property_blob_put(*blob_reference);
  539. *blob_reference = blob;
  540. }
  541. exit:
  542. return rc;
  543. }
  544. int msm_property_set_property(struct msm_property_info *info,
  545. struct msm_property_state *property_state,
  546. uint32_t property_idx,
  547. uint64_t val)
  548. {
  549. int rc = -EINVAL;
  550. if (!info || (property_idx >= info->property_count) ||
  551. property_idx < info->blob_count ||
  552. !property_state || !property_state->values) {
  553. DRM_ERROR("invalid argument(s)\n");
  554. } else {
  555. struct drm_property *drm_prop;
  556. mutex_lock(&info->property_lock);
  557. /* update cached value */
  558. property_state->values[property_idx].value = val;
  559. /* update the new default value for immutables */
  560. drm_prop = info->property_array[property_idx];
  561. if (drm_prop->flags & DRM_MODE_PROP_IMMUTABLE)
  562. info->property_data[property_idx].default_value = val;
  563. mutex_unlock(&info->property_lock);
  564. /* update drm object */
  565. rc = drm_object_property_set_value(info->base, drm_prop, val);
  566. if (rc)
  567. DRM_ERROR("failed set property value, idx %d rc %d\n",
  568. property_idx, rc);
  569. }
  570. return rc;
  571. }