smem.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015, Sony Mobile Communications AB.
  4. * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  5. */
  6. #include <linux/hwspinlock.h>
  7. #include <linux/io.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/of_address.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/sizes.h>
  13. #include <linux/slab.h>
  14. #include <linux/soc/qcom/smem.h>
  15. /*
  16. * The Qualcomm shared memory system is a allocate only heap structure that
  17. * consists of one of more memory areas that can be accessed by the processors
  18. * in the SoC.
  19. *
  20. * All systems contains a global heap, accessible by all processors in the SoC,
  21. * with a table of contents data structure (@smem_header) at the beginning of
  22. * the main shared memory block.
  23. *
  24. * The global header contains meta data for allocations as well as a fixed list
  25. * of 512 entries (@smem_global_entry) that can be initialized to reference
  26. * parts of the shared memory space.
  27. *
  28. *
  29. * In addition to this global heap a set of "private" heaps can be set up at
  30. * boot time with access restrictions so that only certain processor pairs can
  31. * access the data.
  32. *
  33. * These partitions are referenced from an optional partition table
  34. * (@smem_ptable), that is found 4kB from the end of the main smem region. The
  35. * partition table entries (@smem_ptable_entry) lists the involved processors
  36. * (or hosts) and their location in the main shared memory region.
  37. *
  38. * Each partition starts with a header (@smem_partition_header) that identifies
  39. * the partition and holds properties for the two internal memory regions. The
  40. * two regions are cached and non-cached memory respectively. Each region
  41. * contain a link list of allocation headers (@smem_private_entry) followed by
  42. * their data.
  43. *
  44. * Items in the non-cached region are allocated from the start of the partition
  45. * while items in the cached region are allocated from the end. The free area
  46. * is hence the region between the cached and non-cached offsets. The header of
  47. * cached items comes after the data.
  48. *
  49. * Version 12 (SMEM_GLOBAL_PART_VERSION) changes the item alloc/get procedure
  50. * for the global heap. A new global partition is created from the global heap
  51. * region with partition type (SMEM_GLOBAL_HOST) and the max smem item count is
  52. * set by the bootloader.
  53. *
  54. * To synchronize allocations in the shared memory heaps a remote spinlock must
  55. * be held - currently lock number 3 of the sfpb or tcsr is used for this on all
  56. * platforms.
  57. *
  58. */
  59. /*
  60. * The version member of the smem header contains an array of versions for the
  61. * various software components in the SoC. We verify that the boot loader
  62. * version is a valid version as a sanity check.
  63. */
  64. #define SMEM_MASTER_SBL_VERSION_INDEX 7
  65. #define SMEM_GLOBAL_HEAP_VERSION 11
  66. #define SMEM_GLOBAL_PART_VERSION 12
  67. /*
  68. * The first 8 items are only to be allocated by the boot loader while
  69. * initializing the heap.
  70. */
  71. #define SMEM_ITEM_LAST_FIXED 8
  72. /* Highest accepted item number, for both global and private heaps */
  73. #define SMEM_ITEM_COUNT 512
  74. /* Processor/host identifier for the application processor */
  75. #define SMEM_HOST_APPS 0
  76. /* Processor/host identifier for the global partition */
  77. #define SMEM_GLOBAL_HOST 0xfffe
  78. /* Max number of processors/hosts in a system */
  79. #define SMEM_HOST_COUNT 11
  80. /**
  81. * struct smem_proc_comm - proc_comm communication struct (legacy)
  82. * @command: current command to be executed
  83. * @status: status of the currently requested command
  84. * @params: parameters to the command
  85. */
  86. struct smem_proc_comm {
  87. __le32 command;
  88. __le32 status;
  89. __le32 params[2];
  90. };
  91. /**
  92. * struct smem_global_entry - entry to reference smem items on the heap
  93. * @allocated: boolean to indicate if this entry is used
  94. * @offset: offset to the allocated space
  95. * @size: size of the allocated space, 8 byte aligned
  96. * @aux_base: base address for the memory region used by this unit, or 0 for
  97. * the default region. bits 0,1 are reserved
  98. */
  99. struct smem_global_entry {
  100. __le32 allocated;
  101. __le32 offset;
  102. __le32 size;
  103. __le32 aux_base; /* bits 1:0 reserved */
  104. };
  105. #define AUX_BASE_MASK 0xfffffffc
  106. /**
  107. * struct smem_header - header found in beginning of primary smem region
  108. * @proc_comm: proc_comm communication interface (legacy)
  109. * @version: array of versions for the various subsystems
  110. * @initialized: boolean to indicate that smem is initialized
  111. * @free_offset: index of the first unallocated byte in smem
  112. * @available: number of bytes available for allocation
  113. * @reserved: reserved field, must be 0
  114. * toc: array of references to items
  115. */
  116. struct smem_header {
  117. struct smem_proc_comm proc_comm[4];
  118. __le32 version[32];
  119. __le32 initialized;
  120. __le32 free_offset;
  121. __le32 available;
  122. __le32 reserved;
  123. struct smem_global_entry toc[SMEM_ITEM_COUNT];
  124. };
  125. /**
  126. * struct smem_ptable_entry - one entry in the @smem_ptable list
  127. * @offset: offset, within the main shared memory region, of the partition
  128. * @size: size of the partition
  129. * @flags: flags for the partition (currently unused)
  130. * @host0: first processor/host with access to this partition
  131. * @host1: second processor/host with access to this partition
  132. * @cacheline: alignment for "cached" entries
  133. * @reserved: reserved entries for later use
  134. */
  135. struct smem_ptable_entry {
  136. __le32 offset;
  137. __le32 size;
  138. __le32 flags;
  139. __le16 host0;
  140. __le16 host1;
  141. __le32 cacheline;
  142. __le32 reserved[7];
  143. };
  144. /**
  145. * struct smem_ptable - partition table for the private partitions
  146. * @magic: magic number, must be SMEM_PTABLE_MAGIC
  147. * @version: version of the partition table
  148. * @num_entries: number of partitions in the table
  149. * @reserved: for now reserved entries
  150. * @entry: list of @smem_ptable_entry for the @num_entries partitions
  151. */
  152. struct smem_ptable {
  153. u8 magic[4];
  154. __le32 version;
  155. __le32 num_entries;
  156. __le32 reserved[5];
  157. struct smem_ptable_entry entry[];
  158. };
  159. static const u8 SMEM_PTABLE_MAGIC[] = { 0x24, 0x54, 0x4f, 0x43 }; /* "$TOC" */
  160. /**
  161. * struct smem_partition_header - header of the partitions
  162. * @magic: magic number, must be SMEM_PART_MAGIC
  163. * @host0: first processor/host with access to this partition
  164. * @host1: second processor/host with access to this partition
  165. * @size: size of the partition
  166. * @offset_free_uncached: offset to the first free byte of uncached memory in
  167. * this partition
  168. * @offset_free_cached: offset to the first free byte of cached memory in this
  169. * partition
  170. * @reserved: for now reserved entries
  171. */
  172. struct smem_partition_header {
  173. u8 magic[4];
  174. __le16 host0;
  175. __le16 host1;
  176. __le32 size;
  177. __le32 offset_free_uncached;
  178. __le32 offset_free_cached;
  179. __le32 reserved[3];
  180. };
  181. static const u8 SMEM_PART_MAGIC[] = { 0x24, 0x50, 0x52, 0x54 };
  182. /**
  183. * struct smem_private_entry - header of each item in the private partition
  184. * @canary: magic number, must be SMEM_PRIVATE_CANARY
  185. * @item: identifying number of the smem item
  186. * @size: size of the data, including padding bytes
  187. * @padding_data: number of bytes of padding of data
  188. * @padding_hdr: number of bytes of padding between the header and the data
  189. * @reserved: for now reserved entry
  190. */
  191. struct smem_private_entry {
  192. u16 canary; /* bytes are the same so no swapping needed */
  193. __le16 item;
  194. __le32 size; /* includes padding bytes */
  195. __le16 padding_data;
  196. __le16 padding_hdr;
  197. __le32 reserved;
  198. };
  199. #define SMEM_PRIVATE_CANARY 0xa5a5
  200. /**
  201. * struct smem_info - smem region info located after the table of contents
  202. * @magic: magic number, must be SMEM_INFO_MAGIC
  203. * @size: size of the smem region
  204. * @base_addr: base address of the smem region
  205. * @reserved: for now reserved entry
  206. * @num_items: highest accepted item number
  207. */
  208. struct smem_info {
  209. u8 magic[4];
  210. __le32 size;
  211. __le32 base_addr;
  212. __le32 reserved;
  213. __le16 num_items;
  214. };
  215. static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */
  216. /**
  217. * struct smem_region - representation of a chunk of memory used for smem
  218. * @aux_base: identifier of aux_mem base
  219. * @virt_base: virtual base address of memory with this aux_mem identifier
  220. * @size: size of the memory region
  221. */
  222. struct smem_region {
  223. u32 aux_base;
  224. void __iomem *virt_base;
  225. size_t size;
  226. };
  227. /**
  228. * struct qcom_smem - device data for the smem device
  229. * @dev: device pointer
  230. * @hwlock: reference to a hwspinlock
  231. * @global_partition: pointer to global partition when in use
  232. * @global_cacheline: cacheline size for global partition
  233. * @partitions: list of pointers to partitions affecting the current
  234. * processor/host
  235. * @cacheline: list of cacheline sizes for each host
  236. * @item_count: max accepted item number
  237. * @num_regions: number of @regions
  238. * @regions: list of the memory regions defining the shared memory
  239. */
  240. struct qcom_smem {
  241. struct device *dev;
  242. struct hwspinlock *hwlock;
  243. struct smem_partition_header *global_partition;
  244. size_t global_cacheline;
  245. struct smem_partition_header *partitions[SMEM_HOST_COUNT];
  246. size_t cacheline[SMEM_HOST_COUNT];
  247. u32 item_count;
  248. struct platform_device *socinfo;
  249. unsigned num_regions;
  250. struct smem_region regions[];
  251. };
  252. static void *
  253. phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
  254. {
  255. void *p = phdr;
  256. return p + le32_to_cpu(phdr->offset_free_uncached);
  257. }
  258. static struct smem_private_entry *
  259. phdr_to_first_cached_entry(struct smem_partition_header *phdr,
  260. size_t cacheline)
  261. {
  262. void *p = phdr;
  263. struct smem_private_entry *e;
  264. return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline);
  265. }
  266. static void *
  267. phdr_to_last_cached_entry(struct smem_partition_header *phdr)
  268. {
  269. void *p = phdr;
  270. return p + le32_to_cpu(phdr->offset_free_cached);
  271. }
  272. static struct smem_private_entry *
  273. phdr_to_first_uncached_entry(struct smem_partition_header *phdr)
  274. {
  275. void *p = phdr;
  276. return p + sizeof(*phdr);
  277. }
  278. static struct smem_private_entry *
  279. uncached_entry_next(struct smem_private_entry *e)
  280. {
  281. void *p = e;
  282. return p + sizeof(*e) + le16_to_cpu(e->padding_hdr) +
  283. le32_to_cpu(e->size);
  284. }
  285. static struct smem_private_entry *
  286. cached_entry_next(struct smem_private_entry *e, size_t cacheline)
  287. {
  288. void *p = e;
  289. return p - le32_to_cpu(e->size) - ALIGN(sizeof(*e), cacheline);
  290. }
  291. static void *uncached_entry_to_item(struct smem_private_entry *e)
  292. {
  293. void *p = e;
  294. return p + sizeof(*e) + le16_to_cpu(e->padding_hdr);
  295. }
  296. static void *cached_entry_to_item(struct smem_private_entry *e)
  297. {
  298. void *p = e;
  299. return p - le32_to_cpu(e->size);
  300. }
  301. /* Pointer to the one and only smem handle */
  302. static struct qcom_smem *__smem;
  303. /* Timeout (ms) for the trylock of remote spinlocks */
  304. #define HWSPINLOCK_TIMEOUT 1000
  305. static int qcom_smem_alloc_private(struct qcom_smem *smem,
  306. struct smem_partition_header *phdr,
  307. unsigned item,
  308. size_t size)
  309. {
  310. struct smem_private_entry *hdr, *end;
  311. size_t alloc_size;
  312. void *cached;
  313. hdr = phdr_to_first_uncached_entry(phdr);
  314. end = phdr_to_last_uncached_entry(phdr);
  315. cached = phdr_to_last_cached_entry(phdr);
  316. while (hdr < end) {
  317. if (hdr->canary != SMEM_PRIVATE_CANARY)
  318. goto bad_canary;
  319. if (le16_to_cpu(hdr->item) == item)
  320. return -EEXIST;
  321. hdr = uncached_entry_next(hdr);
  322. }
  323. /* Check that we don't grow into the cached region */
  324. alloc_size = sizeof(*hdr) + ALIGN(size, 8);
  325. if ((void *)hdr + alloc_size > cached) {
  326. dev_err(smem->dev, "Out of memory\n");
  327. return -ENOSPC;
  328. }
  329. hdr->canary = SMEM_PRIVATE_CANARY;
  330. hdr->item = cpu_to_le16(item);
  331. hdr->size = cpu_to_le32(ALIGN(size, 8));
  332. hdr->padding_data = cpu_to_le16(le32_to_cpu(hdr->size) - size);
  333. hdr->padding_hdr = 0;
  334. /*
  335. * Ensure the header is written before we advance the free offset, so
  336. * that remote processors that does not take the remote spinlock still
  337. * gets a consistent view of the linked list.
  338. */
  339. wmb();
  340. le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
  341. return 0;
  342. bad_canary:
  343. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  344. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  345. return -EINVAL;
  346. }
  347. static int qcom_smem_alloc_global(struct qcom_smem *smem,
  348. unsigned item,
  349. size_t size)
  350. {
  351. struct smem_global_entry *entry;
  352. struct smem_header *header;
  353. header = smem->regions[0].virt_base;
  354. entry = &header->toc[item];
  355. if (entry->allocated)
  356. return -EEXIST;
  357. size = ALIGN(size, 8);
  358. if (WARN_ON(size > le32_to_cpu(header->available)))
  359. return -ENOMEM;
  360. entry->offset = header->free_offset;
  361. entry->size = cpu_to_le32(size);
  362. /*
  363. * Ensure the header is consistent before we mark the item allocated,
  364. * so that remote processors will get a consistent view of the item
  365. * even though they do not take the spinlock on read.
  366. */
  367. wmb();
  368. entry->allocated = cpu_to_le32(1);
  369. le32_add_cpu(&header->free_offset, size);
  370. le32_add_cpu(&header->available, -size);
  371. return 0;
  372. }
  373. /**
  374. * qcom_smem_alloc() - allocate space for a smem item
  375. * @host: remote processor id, or -1
  376. * @item: smem item handle
  377. * @size: number of bytes to be allocated
  378. *
  379. * Allocate space for a given smem item of size @size, given that the item is
  380. * not yet allocated.
  381. */
  382. int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
  383. {
  384. struct smem_partition_header *phdr;
  385. unsigned long flags;
  386. int ret;
  387. if (!__smem)
  388. return -EPROBE_DEFER;
  389. if (item < SMEM_ITEM_LAST_FIXED) {
  390. dev_err(__smem->dev,
  391. "Rejecting allocation of static entry %d\n", item);
  392. return -EINVAL;
  393. }
  394. if (WARN_ON(item >= __smem->item_count))
  395. return -EINVAL;
  396. ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
  397. HWSPINLOCK_TIMEOUT,
  398. &flags);
  399. if (ret)
  400. return ret;
  401. if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
  402. phdr = __smem->partitions[host];
  403. ret = qcom_smem_alloc_private(__smem, phdr, item, size);
  404. } else if (__smem->global_partition) {
  405. phdr = __smem->global_partition;
  406. ret = qcom_smem_alloc_private(__smem, phdr, item, size);
  407. } else {
  408. ret = qcom_smem_alloc_global(__smem, item, size);
  409. }
  410. hwspin_unlock_irqrestore(__smem->hwlock, &flags);
  411. return ret;
  412. }
  413. EXPORT_SYMBOL(qcom_smem_alloc);
  414. static void *qcom_smem_get_global(struct qcom_smem *smem,
  415. unsigned item,
  416. size_t *size)
  417. {
  418. struct smem_header *header;
  419. struct smem_region *region;
  420. struct smem_global_entry *entry;
  421. u32 aux_base;
  422. unsigned i;
  423. header = smem->regions[0].virt_base;
  424. entry = &header->toc[item];
  425. if (!entry->allocated)
  426. return ERR_PTR(-ENXIO);
  427. aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
  428. for (i = 0; i < smem->num_regions; i++) {
  429. region = &smem->regions[i];
  430. if (region->aux_base == aux_base || !aux_base) {
  431. if (size != NULL)
  432. *size = le32_to_cpu(entry->size);
  433. return region->virt_base + le32_to_cpu(entry->offset);
  434. }
  435. }
  436. return ERR_PTR(-ENOENT);
  437. }
  438. static void *qcom_smem_get_private(struct qcom_smem *smem,
  439. struct smem_partition_header *phdr,
  440. size_t cacheline,
  441. unsigned item,
  442. size_t *size)
  443. {
  444. struct smem_private_entry *e, *end;
  445. e = phdr_to_first_uncached_entry(phdr);
  446. end = phdr_to_last_uncached_entry(phdr);
  447. while (e < end) {
  448. if (e->canary != SMEM_PRIVATE_CANARY)
  449. goto invalid_canary;
  450. if (le16_to_cpu(e->item) == item) {
  451. if (size != NULL)
  452. *size = le32_to_cpu(e->size) -
  453. le16_to_cpu(e->padding_data);
  454. return uncached_entry_to_item(e);
  455. }
  456. e = uncached_entry_next(e);
  457. }
  458. /* Item was not found in the uncached list, search the cached list */
  459. e = phdr_to_first_cached_entry(phdr, cacheline);
  460. end = phdr_to_last_cached_entry(phdr);
  461. while (e > end) {
  462. if (e->canary != SMEM_PRIVATE_CANARY)
  463. goto invalid_canary;
  464. if (le16_to_cpu(e->item) == item) {
  465. if (size != NULL)
  466. *size = le32_to_cpu(e->size) -
  467. le16_to_cpu(e->padding_data);
  468. return cached_entry_to_item(e);
  469. }
  470. e = cached_entry_next(e, cacheline);
  471. }
  472. return ERR_PTR(-ENOENT);
  473. invalid_canary:
  474. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  475. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  476. return ERR_PTR(-EINVAL);
  477. }
  478. /**
  479. * qcom_smem_get() - resolve ptr of size of a smem item
  480. * @host: the remote processor, or -1
  481. * @item: smem item handle
  482. * @size: pointer to be filled out with size of the item
  483. *
  484. * Looks up smem item and returns pointer to it. Size of smem
  485. * item is returned in @size.
  486. */
  487. void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
  488. {
  489. struct smem_partition_header *phdr;
  490. unsigned long flags;
  491. size_t cacheln;
  492. int ret;
  493. void *ptr = ERR_PTR(-EPROBE_DEFER);
  494. if (!__smem)
  495. return ptr;
  496. if (WARN_ON(item >= __smem->item_count))
  497. return ERR_PTR(-EINVAL);
  498. ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
  499. HWSPINLOCK_TIMEOUT,
  500. &flags);
  501. if (ret)
  502. return ERR_PTR(ret);
  503. if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
  504. phdr = __smem->partitions[host];
  505. cacheln = __smem->cacheline[host];
  506. ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size);
  507. } else if (__smem->global_partition) {
  508. phdr = __smem->global_partition;
  509. cacheln = __smem->global_cacheline;
  510. ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size);
  511. } else {
  512. ptr = qcom_smem_get_global(__smem, item, size);
  513. }
  514. hwspin_unlock_irqrestore(__smem->hwlock, &flags);
  515. return ptr;
  516. }
  517. EXPORT_SYMBOL(qcom_smem_get);
  518. /**
  519. * qcom_smem_get_free_space() - retrieve amount of free space in a partition
  520. * @host: the remote processor identifying a partition, or -1
  521. *
  522. * To be used by smem clients as a quick way to determine if any new
  523. * allocations has been made.
  524. */
  525. int qcom_smem_get_free_space(unsigned host)
  526. {
  527. struct smem_partition_header *phdr;
  528. struct smem_header *header;
  529. unsigned ret;
  530. if (!__smem)
  531. return -EPROBE_DEFER;
  532. if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
  533. phdr = __smem->partitions[host];
  534. ret = le32_to_cpu(phdr->offset_free_cached) -
  535. le32_to_cpu(phdr->offset_free_uncached);
  536. } else if (__smem->global_partition) {
  537. phdr = __smem->global_partition;
  538. ret = le32_to_cpu(phdr->offset_free_cached) -
  539. le32_to_cpu(phdr->offset_free_uncached);
  540. } else {
  541. header = __smem->regions[0].virt_base;
  542. ret = le32_to_cpu(header->available);
  543. }
  544. return ret;
  545. }
  546. EXPORT_SYMBOL(qcom_smem_get_free_space);
  547. /**
  548. * qcom_smem_virt_to_phys() - return the physical address associated
  549. * with an smem item pointer (previously returned by qcom_smem_get()
  550. * @p: the virtual address to convert
  551. *
  552. * Returns 0 if the pointer provided is not within any smem region.
  553. */
  554. phys_addr_t qcom_smem_virt_to_phys(void *p)
  555. {
  556. unsigned i;
  557. for (i = 0; i < __smem->num_regions; i++) {
  558. struct smem_region *region = &__smem->regions[i];
  559. if (p < region->virt_base)
  560. continue;
  561. if (p < region->virt_base + region->size) {
  562. u64 offset = p - region->virt_base;
  563. return (phys_addr_t)region->aux_base + offset;
  564. }
  565. }
  566. return 0;
  567. }
  568. EXPORT_SYMBOL(qcom_smem_virt_to_phys);
  569. static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
  570. {
  571. struct smem_header *header;
  572. __le32 *versions;
  573. header = smem->regions[0].virt_base;
  574. versions = header->version;
  575. return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]);
  576. }
  577. static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem)
  578. {
  579. struct smem_ptable *ptable;
  580. u32 version;
  581. ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K;
  582. if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic)))
  583. return ERR_PTR(-ENOENT);
  584. version = le32_to_cpu(ptable->version);
  585. if (version != 1) {
  586. dev_err(smem->dev,
  587. "Unsupported partition header version %d\n", version);
  588. return ERR_PTR(-EINVAL);
  589. }
  590. return ptable;
  591. }
  592. static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
  593. {
  594. struct smem_ptable *ptable;
  595. struct smem_info *info;
  596. ptable = qcom_smem_get_ptable(smem);
  597. if (IS_ERR_OR_NULL(ptable))
  598. return SMEM_ITEM_COUNT;
  599. info = (struct smem_info *)&ptable->entry[ptable->num_entries];
  600. if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic)))
  601. return SMEM_ITEM_COUNT;
  602. return le16_to_cpu(info->num_items);
  603. }
  604. /*
  605. * Validate the partition header for a partition whose partition
  606. * table entry is supplied. Returns a pointer to its header if
  607. * valid, or a null pointer otherwise.
  608. */
  609. static struct smem_partition_header *
  610. qcom_smem_partition_header(struct qcom_smem *smem,
  611. struct smem_ptable_entry *entry, u16 host0, u16 host1)
  612. {
  613. struct smem_partition_header *header;
  614. u32 size;
  615. header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
  616. if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
  617. dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
  618. header->magic[0], header->magic[1],
  619. header->magic[2], header->magic[3]);
  620. return NULL;
  621. }
  622. if (host0 != le16_to_cpu(header->host0)) {
  623. dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
  624. host0, le16_to_cpu(header->host0));
  625. return NULL;
  626. }
  627. if (host1 != le16_to_cpu(header->host1)) {
  628. dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
  629. host1, le16_to_cpu(header->host1));
  630. return NULL;
  631. }
  632. size = le32_to_cpu(header->size);
  633. if (size != le32_to_cpu(entry->size)) {
  634. dev_err(smem->dev, "bad partition size (%u != %u)\n",
  635. size, le32_to_cpu(entry->size));
  636. return NULL;
  637. }
  638. if (le32_to_cpu(header->offset_free_uncached) > size) {
  639. dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
  640. le32_to_cpu(header->offset_free_uncached), size);
  641. return NULL;
  642. }
  643. return header;
  644. }
  645. static int qcom_smem_set_global_partition(struct qcom_smem *smem)
  646. {
  647. struct smem_partition_header *header;
  648. struct smem_ptable_entry *entry;
  649. struct smem_ptable *ptable;
  650. bool found = false;
  651. int i;
  652. if (smem->global_partition) {
  653. dev_err(smem->dev, "Already found the global partition\n");
  654. return -EINVAL;
  655. }
  656. ptable = qcom_smem_get_ptable(smem);
  657. if (IS_ERR(ptable))
  658. return PTR_ERR(ptable);
  659. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  660. entry = &ptable->entry[i];
  661. if (!le32_to_cpu(entry->offset))
  662. continue;
  663. if (!le32_to_cpu(entry->size))
  664. continue;
  665. if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
  666. continue;
  667. if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
  668. found = true;
  669. break;
  670. }
  671. }
  672. if (!found) {
  673. dev_err(smem->dev, "Missing entry for global partition\n");
  674. return -EINVAL;
  675. }
  676. header = qcom_smem_partition_header(smem, entry,
  677. SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
  678. if (!header)
  679. return -EINVAL;
  680. smem->global_partition = header;
  681. smem->global_cacheline = le32_to_cpu(entry->cacheline);
  682. return 0;
  683. }
  684. static int
  685. qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
  686. {
  687. struct smem_partition_header *header;
  688. struct smem_ptable_entry *entry;
  689. struct smem_ptable *ptable;
  690. unsigned int remote_host;
  691. u16 host0, host1;
  692. int i;
  693. ptable = qcom_smem_get_ptable(smem);
  694. if (IS_ERR(ptable))
  695. return PTR_ERR(ptable);
  696. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  697. entry = &ptable->entry[i];
  698. if (!le32_to_cpu(entry->offset))
  699. continue;
  700. if (!le32_to_cpu(entry->size))
  701. continue;
  702. host0 = le16_to_cpu(entry->host0);
  703. host1 = le16_to_cpu(entry->host1);
  704. if (host0 == local_host)
  705. remote_host = host1;
  706. else if (host1 == local_host)
  707. remote_host = host0;
  708. else
  709. continue;
  710. if (remote_host >= SMEM_HOST_COUNT) {
  711. dev_err(smem->dev, "bad host %hu\n", remote_host);
  712. return -EINVAL;
  713. }
  714. if (smem->partitions[remote_host]) {
  715. dev_err(smem->dev, "duplicate host %hu\n", remote_host);
  716. return -EINVAL;
  717. }
  718. header = qcom_smem_partition_header(smem, entry, host0, host1);
  719. if (!header)
  720. return -EINVAL;
  721. smem->partitions[remote_host] = header;
  722. smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
  723. }
  724. return 0;
  725. }
  726. static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
  727. const char *name, int i)
  728. {
  729. struct device_node *np;
  730. struct resource r;
  731. resource_size_t size;
  732. int ret;
  733. np = of_parse_phandle(dev->of_node, name, 0);
  734. if (!np) {
  735. dev_err(dev, "No %s specified\n", name);
  736. return -EINVAL;
  737. }
  738. ret = of_address_to_resource(np, 0, &r);
  739. of_node_put(np);
  740. if (ret)
  741. return ret;
  742. size = resource_size(&r);
  743. smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
  744. if (!smem->regions[i].virt_base)
  745. return -ENOMEM;
  746. smem->regions[i].aux_base = (u32)r.start;
  747. smem->regions[i].size = size;
  748. return 0;
  749. }
  750. static int qcom_smem_probe(struct platform_device *pdev)
  751. {
  752. struct smem_header *header;
  753. struct qcom_smem *smem;
  754. size_t array_size;
  755. int num_regions;
  756. int hwlock_id;
  757. u32 version;
  758. int ret;
  759. num_regions = 1;
  760. if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL))
  761. num_regions++;
  762. array_size = num_regions * sizeof(struct smem_region);
  763. smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL);
  764. if (!smem)
  765. return -ENOMEM;
  766. smem->dev = &pdev->dev;
  767. smem->num_regions = num_regions;
  768. ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0);
  769. if (ret)
  770. return ret;
  771. if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev,
  772. "qcom,rpm-msg-ram", 1)))
  773. return ret;
  774. header = smem->regions[0].virt_base;
  775. if (le32_to_cpu(header->initialized) != 1 ||
  776. le32_to_cpu(header->reserved)) {
  777. dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
  778. return -EINVAL;
  779. }
  780. version = qcom_smem_get_sbl_version(smem);
  781. switch (version >> 16) {
  782. case SMEM_GLOBAL_PART_VERSION:
  783. ret = qcom_smem_set_global_partition(smem);
  784. if (ret < 0)
  785. return ret;
  786. smem->item_count = qcom_smem_get_item_count(smem);
  787. break;
  788. case SMEM_GLOBAL_HEAP_VERSION:
  789. smem->item_count = SMEM_ITEM_COUNT;
  790. break;
  791. default:
  792. dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version);
  793. return -EINVAL;
  794. }
  795. BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
  796. ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
  797. if (ret < 0 && ret != -ENOENT)
  798. return ret;
  799. hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
  800. if (hwlock_id < 0) {
  801. if (hwlock_id != -EPROBE_DEFER)
  802. dev_err(&pdev->dev, "failed to retrieve hwlock\n");
  803. return hwlock_id;
  804. }
  805. smem->hwlock = hwspin_lock_request_specific(hwlock_id);
  806. if (!smem->hwlock)
  807. return -ENXIO;
  808. __smem = smem;
  809. smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
  810. PLATFORM_DEVID_NONE, NULL,
  811. 0);
  812. if (IS_ERR(smem->socinfo))
  813. dev_dbg(&pdev->dev, "failed to register socinfo device\n");
  814. return 0;
  815. }
  816. static int qcom_smem_remove(struct platform_device *pdev)
  817. {
  818. platform_device_unregister(__smem->socinfo);
  819. hwspin_lock_free(__smem->hwlock);
  820. __smem = NULL;
  821. return 0;
  822. }
  823. static const struct of_device_id qcom_smem_of_match[] = {
  824. { .compatible = "qcom,smem" },
  825. {}
  826. };
  827. MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
  828. static struct platform_driver qcom_smem_driver = {
  829. .probe = qcom_smem_probe,
  830. .remove = qcom_smem_remove,
  831. .driver = {
  832. .name = "qcom-smem",
  833. .of_match_table = qcom_smem_of_match,
  834. .suppress_bind_attrs = true,
  835. },
  836. };
  837. static int __init qcom_smem_init(void)
  838. {
  839. return platform_driver_register(&qcom_smem_driver);
  840. }
  841. arch_initcall(qcom_smem_init);
  842. static void __exit qcom_smem_exit(void)
  843. {
  844. platform_driver_unregister(&qcom_smem_driver);
  845. }
  846. module_exit(qcom_smem_exit)
  847. MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
  848. MODULE_DESCRIPTION("Qualcomm Shared Memory Manager");
  849. MODULE_LICENSE("GPL v2");