smem.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  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/of_reserved_mem.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/sizes.h>
  14. #include <linux/slab.h>
  15. #include <linux/soc/qcom/smem.h>
  16. #include <linux/soc/qcom/socinfo.h>
  17. /*
  18. * The Qualcomm shared memory system is a allocate only heap structure that
  19. * consists of one of more memory areas that can be accessed by the processors
  20. * in the SoC.
  21. *
  22. * All systems contains a global heap, accessible by all processors in the SoC,
  23. * with a table of contents data structure (@smem_header) at the beginning of
  24. * the main shared memory block.
  25. *
  26. * The global header contains meta data for allocations as well as a fixed list
  27. * of 512 entries (@smem_global_entry) that can be initialized to reference
  28. * parts of the shared memory space.
  29. *
  30. *
  31. * In addition to this global heap a set of "private" heaps can be set up at
  32. * boot time with access restrictions so that only certain processor pairs can
  33. * access the data.
  34. *
  35. * These partitions are referenced from an optional partition table
  36. * (@smem_ptable), that is found 4kB from the end of the main smem region. The
  37. * partition table entries (@smem_ptable_entry) lists the involved processors
  38. * (or hosts) and their location in the main shared memory region.
  39. *
  40. * Each partition starts with a header (@smem_partition_header) that identifies
  41. * the partition and holds properties for the two internal memory regions. The
  42. * two regions are cached and non-cached memory respectively. Each region
  43. * contain a link list of allocation headers (@smem_private_entry) followed by
  44. * their data.
  45. *
  46. * Items in the non-cached region are allocated from the start of the partition
  47. * while items in the cached region are allocated from the end. The free area
  48. * is hence the region between the cached and non-cached offsets. The header of
  49. * cached items comes after the data.
  50. *
  51. * Version 12 (SMEM_GLOBAL_PART_VERSION) changes the item alloc/get procedure
  52. * for the global heap. A new global partition is created from the global heap
  53. * region with partition type (SMEM_GLOBAL_HOST) and the max smem item count is
  54. * set by the bootloader.
  55. *
  56. * To synchronize allocations in the shared memory heaps a remote spinlock must
  57. * be held - currently lock number 3 of the sfpb or tcsr is used for this on all
  58. * platforms.
  59. *
  60. */
  61. /*
  62. * The version member of the smem header contains an array of versions for the
  63. * various software components in the SoC. We verify that the boot loader
  64. * version is a valid version as a sanity check.
  65. */
  66. #define SMEM_MASTER_SBL_VERSION_INDEX 7
  67. #define SMEM_GLOBAL_HEAP_VERSION 11
  68. #define SMEM_GLOBAL_PART_VERSION 12
  69. /*
  70. * The first 8 items are only to be allocated by the boot loader while
  71. * initializing the heap.
  72. */
  73. #define SMEM_ITEM_LAST_FIXED 8
  74. /* Highest accepted item number, for both global and private heaps */
  75. #define SMEM_ITEM_COUNT 512
  76. /* Processor/host identifier for the application processor */
  77. #define SMEM_HOST_APPS 0
  78. /* Processor/host identifier for the global partition */
  79. #define SMEM_GLOBAL_HOST 0xfffe
  80. /* Max number of processors/hosts in a system */
  81. #define SMEM_HOST_COUNT 20
  82. /**
  83. * struct smem_proc_comm - proc_comm communication struct (legacy)
  84. * @command: current command to be executed
  85. * @status: status of the currently requested command
  86. * @params: parameters to the command
  87. */
  88. struct smem_proc_comm {
  89. __le32 command;
  90. __le32 status;
  91. __le32 params[2];
  92. };
  93. /**
  94. * struct smem_global_entry - entry to reference smem items on the heap
  95. * @allocated: boolean to indicate if this entry is used
  96. * @offset: offset to the allocated space
  97. * @size: size of the allocated space, 8 byte aligned
  98. * @aux_base: base address for the memory region used by this unit, or 0 for
  99. * the default region. bits 0,1 are reserved
  100. */
  101. struct smem_global_entry {
  102. __le32 allocated;
  103. __le32 offset;
  104. __le32 size;
  105. __le32 aux_base; /* bits 1:0 reserved */
  106. };
  107. #define AUX_BASE_MASK 0xfffffffc
  108. /**
  109. * struct smem_header - header found in beginning of primary smem region
  110. * @proc_comm: proc_comm communication interface (legacy)
  111. * @version: array of versions for the various subsystems
  112. * @initialized: boolean to indicate that smem is initialized
  113. * @free_offset: index of the first unallocated byte in smem
  114. * @available: number of bytes available for allocation
  115. * @reserved: reserved field, must be 0
  116. * @toc: array of references to items
  117. */
  118. struct smem_header {
  119. struct smem_proc_comm proc_comm[4];
  120. __le32 version[32];
  121. __le32 initialized;
  122. __le32 free_offset;
  123. __le32 available;
  124. __le32 reserved;
  125. struct smem_global_entry toc[SMEM_ITEM_COUNT];
  126. };
  127. /**
  128. * struct smem_ptable_entry - one entry in the @smem_ptable list
  129. * @offset: offset, within the main shared memory region, of the partition
  130. * @size: size of the partition
  131. * @flags: flags for the partition (currently unused)
  132. * @host0: first processor/host with access to this partition
  133. * @host1: second processor/host with access to this partition
  134. * @cacheline: alignment for "cached" entries
  135. * @reserved: reserved entries for later use
  136. */
  137. struct smem_ptable_entry {
  138. __le32 offset;
  139. __le32 size;
  140. __le32 flags;
  141. __le16 host0;
  142. __le16 host1;
  143. __le32 cacheline;
  144. __le32 reserved[7];
  145. };
  146. /**
  147. * struct smem_ptable - partition table for the private partitions
  148. * @magic: magic number, must be SMEM_PTABLE_MAGIC
  149. * @version: version of the partition table
  150. * @num_entries: number of partitions in the table
  151. * @reserved: for now reserved entries
  152. * @entry: list of @smem_ptable_entry for the @num_entries partitions
  153. */
  154. struct smem_ptable {
  155. u8 magic[4];
  156. __le32 version;
  157. __le32 num_entries;
  158. __le32 reserved[5];
  159. struct smem_ptable_entry entry[];
  160. };
  161. static const u8 SMEM_PTABLE_MAGIC[] = { 0x24, 0x54, 0x4f, 0x43 }; /* "$TOC" */
  162. /**
  163. * struct smem_partition_header - header of the partitions
  164. * @magic: magic number, must be SMEM_PART_MAGIC
  165. * @host0: first processor/host with access to this partition
  166. * @host1: second processor/host with access to this partition
  167. * @size: size of the partition
  168. * @offset_free_uncached: offset to the first free byte of uncached memory in
  169. * this partition
  170. * @offset_free_cached: offset to the first free byte of cached memory in this
  171. * partition
  172. * @reserved: for now reserved entries
  173. */
  174. struct smem_partition_header {
  175. u8 magic[4];
  176. __le16 host0;
  177. __le16 host1;
  178. __le32 size;
  179. __le32 offset_free_uncached;
  180. __le32 offset_free_cached;
  181. __le32 reserved[3];
  182. };
  183. /**
  184. * struct smem_partition - describes smem partition
  185. * @virt_base: starting virtual address of partition
  186. * @phys_base: starting physical address of partition
  187. * @cacheline: alignment for "cached" entries
  188. * @size: size of partition
  189. */
  190. struct smem_partition {
  191. void __iomem *virt_base;
  192. phys_addr_t phys_base;
  193. size_t cacheline;
  194. size_t size;
  195. };
  196. static const u8 SMEM_PART_MAGIC[] = { 0x24, 0x50, 0x52, 0x54 };
  197. /**
  198. * struct smem_private_entry - header of each item in the private partition
  199. * @canary: magic number, must be SMEM_PRIVATE_CANARY
  200. * @item: identifying number of the smem item
  201. * @size: size of the data, including padding bytes
  202. * @padding_data: number of bytes of padding of data
  203. * @padding_hdr: number of bytes of padding between the header and the data
  204. * @reserved: for now reserved entry
  205. */
  206. struct smem_private_entry {
  207. u16 canary; /* bytes are the same so no swapping needed */
  208. __le16 item;
  209. __le32 size; /* includes padding bytes */
  210. __le16 padding_data;
  211. __le16 padding_hdr;
  212. __le32 reserved;
  213. };
  214. #define SMEM_PRIVATE_CANARY 0xa5a5
  215. /**
  216. * struct smem_info - smem region info located after the table of contents
  217. * @magic: magic number, must be SMEM_INFO_MAGIC
  218. * @size: size of the smem region
  219. * @base_addr: base address of the smem region
  220. * @reserved: for now reserved entry
  221. * @num_items: highest accepted item number
  222. */
  223. struct smem_info {
  224. u8 magic[4];
  225. __le32 size;
  226. __le32 base_addr;
  227. __le32 reserved;
  228. __le16 num_items;
  229. };
  230. static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */
  231. /**
  232. * struct smem_region - representation of a chunk of memory used for smem
  233. * @aux_base: identifier of aux_mem base
  234. * @virt_base: virtual base address of memory with this aux_mem identifier
  235. * @size: size of the memory region
  236. */
  237. struct smem_region {
  238. phys_addr_t aux_base;
  239. void __iomem *virt_base;
  240. size_t size;
  241. };
  242. /**
  243. * struct qcom_smem - device data for the smem device
  244. * @dev: device pointer
  245. * @hwlock: reference to a hwspinlock
  246. * @ptable: virtual base of partition table
  247. * @global_partition: describes for global partition when in use
  248. * @partitions: list of partitions of current processor/host
  249. * @item_count: max accepted item number
  250. * @socinfo: platform device pointer
  251. * @num_regions: number of @regions
  252. * @regions: list of the memory regions defining the shared memory
  253. */
  254. struct qcom_smem {
  255. struct device *dev;
  256. struct hwspinlock *hwlock;
  257. u32 item_count;
  258. struct platform_device *socinfo;
  259. struct smem_ptable *ptable;
  260. struct smem_partition global_partition;
  261. struct smem_partition partitions[SMEM_HOST_COUNT];
  262. unsigned num_regions;
  263. struct smem_region regions[] __counted_by(num_regions);
  264. };
  265. static void *
  266. phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
  267. {
  268. void *p = phdr;
  269. return p + le32_to_cpu(phdr->offset_free_uncached);
  270. }
  271. static struct smem_private_entry *
  272. phdr_to_first_cached_entry(struct smem_partition_header *phdr,
  273. size_t cacheline)
  274. {
  275. void *p = phdr;
  276. struct smem_private_entry *e;
  277. return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline);
  278. }
  279. static void *
  280. phdr_to_last_cached_entry(struct smem_partition_header *phdr)
  281. {
  282. void *p = phdr;
  283. return p + le32_to_cpu(phdr->offset_free_cached);
  284. }
  285. static struct smem_private_entry *
  286. phdr_to_first_uncached_entry(struct smem_partition_header *phdr)
  287. {
  288. void *p = phdr;
  289. return p + sizeof(*phdr);
  290. }
  291. static struct smem_private_entry *
  292. uncached_entry_next(struct smem_private_entry *e)
  293. {
  294. void *p = e;
  295. return p + sizeof(*e) + le16_to_cpu(e->padding_hdr) +
  296. le32_to_cpu(e->size);
  297. }
  298. static struct smem_private_entry *
  299. cached_entry_next(struct smem_private_entry *e, size_t cacheline)
  300. {
  301. void *p = e;
  302. return p - le32_to_cpu(e->size) - ALIGN(sizeof(*e), cacheline);
  303. }
  304. static void *uncached_entry_to_item(struct smem_private_entry *e)
  305. {
  306. void *p = e;
  307. return p + sizeof(*e) + le16_to_cpu(e->padding_hdr);
  308. }
  309. static void *cached_entry_to_item(struct smem_private_entry *e)
  310. {
  311. void *p = e;
  312. return p - le32_to_cpu(e->size);
  313. }
  314. /* Pointer to the one and only smem handle */
  315. static struct qcom_smem *__smem;
  316. /* Timeout (ms) for the trylock of remote spinlocks */
  317. #define HWSPINLOCK_TIMEOUT 1000
  318. /* The qcom hwspinlock id is always plus one from the smem host id */
  319. #define SMEM_HOST_ID_TO_HWSPINLOCK_ID(__x) ((__x) + 1)
  320. /**
  321. * qcom_smem_bust_hwspin_lock_by_host() - bust the smem hwspinlock for a host
  322. * @host: remote processor id
  323. *
  324. * Busts the hwspin_lock for the given smem host id. This helper is intended
  325. * for remoteproc drivers that manage remoteprocs with an equivalent smem
  326. * driver instance in the remote firmware. Drivers can force a release of the
  327. * smem hwspin_lock if the rproc unexpectedly goes into a bad state.
  328. *
  329. * Context: Process context.
  330. *
  331. * Returns: 0 on success, otherwise negative errno.
  332. */
  333. int qcom_smem_bust_hwspin_lock_by_host(unsigned int host)
  334. {
  335. /* This function is for remote procs, so ignore SMEM_HOST_APPS */
  336. if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT)
  337. return -EINVAL;
  338. return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host));
  339. }
  340. EXPORT_SYMBOL_GPL(qcom_smem_bust_hwspin_lock_by_host);
  341. /**
  342. * qcom_smem_is_available() - Check if SMEM is available
  343. *
  344. * Return: true if SMEM is available, false otherwise.
  345. */
  346. bool qcom_smem_is_available(void)
  347. {
  348. return !!__smem;
  349. }
  350. EXPORT_SYMBOL_GPL(qcom_smem_is_available);
  351. static int qcom_smem_alloc_private(struct qcom_smem *smem,
  352. struct smem_partition *part,
  353. unsigned item,
  354. size_t size)
  355. {
  356. struct smem_private_entry *hdr, *end;
  357. struct smem_partition_header *phdr;
  358. size_t alloc_size;
  359. void *cached;
  360. void *p_end;
  361. phdr = (struct smem_partition_header __force *)part->virt_base;
  362. p_end = (void *)phdr + part->size;
  363. hdr = phdr_to_first_uncached_entry(phdr);
  364. end = phdr_to_last_uncached_entry(phdr);
  365. cached = phdr_to_last_cached_entry(phdr);
  366. if (WARN_ON((void *)end > p_end || cached > p_end))
  367. return -EINVAL;
  368. while (hdr < end) {
  369. if (hdr->canary != SMEM_PRIVATE_CANARY)
  370. goto bad_canary;
  371. if (le16_to_cpu(hdr->item) == item)
  372. return -EEXIST;
  373. hdr = uncached_entry_next(hdr);
  374. }
  375. if (WARN_ON((void *)hdr > p_end))
  376. return -EINVAL;
  377. /* Check that we don't grow into the cached region */
  378. alloc_size = sizeof(*hdr) + ALIGN(size, 8);
  379. if ((void *)hdr + alloc_size > cached) {
  380. dev_err(smem->dev, "Out of memory\n");
  381. return -ENOSPC;
  382. }
  383. hdr->canary = SMEM_PRIVATE_CANARY;
  384. hdr->item = cpu_to_le16(item);
  385. hdr->size = cpu_to_le32(ALIGN(size, 8));
  386. hdr->padding_data = cpu_to_le16(le32_to_cpu(hdr->size) - size);
  387. hdr->padding_hdr = 0;
  388. /*
  389. * Ensure the header is written before we advance the free offset, so
  390. * that remote processors that does not take the remote spinlock still
  391. * gets a consistent view of the linked list.
  392. */
  393. wmb();
  394. le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
  395. return 0;
  396. bad_canary:
  397. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  398. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  399. return -EINVAL;
  400. }
  401. static int qcom_smem_alloc_global(struct qcom_smem *smem,
  402. unsigned item,
  403. size_t size)
  404. {
  405. struct smem_global_entry *entry;
  406. struct smem_header *header;
  407. header = smem->regions[0].virt_base;
  408. entry = &header->toc[item];
  409. if (entry->allocated)
  410. return -EEXIST;
  411. size = ALIGN(size, 8);
  412. if (WARN_ON(size > le32_to_cpu(header->available)))
  413. return -ENOMEM;
  414. entry->offset = header->free_offset;
  415. entry->size = cpu_to_le32(size);
  416. /*
  417. * Ensure the header is consistent before we mark the item allocated,
  418. * so that remote processors will get a consistent view of the item
  419. * even though they do not take the spinlock on read.
  420. */
  421. wmb();
  422. entry->allocated = cpu_to_le32(1);
  423. le32_add_cpu(&header->free_offset, size);
  424. le32_add_cpu(&header->available, -size);
  425. return 0;
  426. }
  427. /**
  428. * qcom_smem_alloc() - allocate space for a smem item
  429. * @host: remote processor id, or -1
  430. * @item: smem item handle
  431. * @size: number of bytes to be allocated
  432. *
  433. * Allocate space for a given smem item of size @size, given that the item is
  434. * not yet allocated.
  435. */
  436. int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
  437. {
  438. struct smem_partition *part;
  439. unsigned long flags;
  440. int ret;
  441. if (!__smem)
  442. return -EPROBE_DEFER;
  443. if (item < SMEM_ITEM_LAST_FIXED) {
  444. dev_err(__smem->dev,
  445. "Rejecting allocation of static entry %d\n", item);
  446. return -EINVAL;
  447. }
  448. if (WARN_ON(item >= __smem->item_count))
  449. return -EINVAL;
  450. ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
  451. HWSPINLOCK_TIMEOUT,
  452. &flags);
  453. if (ret)
  454. return ret;
  455. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  456. part = &__smem->partitions[host];
  457. ret = qcom_smem_alloc_private(__smem, part, item, size);
  458. } else if (__smem->global_partition.virt_base) {
  459. part = &__smem->global_partition;
  460. ret = qcom_smem_alloc_private(__smem, part, item, size);
  461. } else {
  462. ret = qcom_smem_alloc_global(__smem, item, size);
  463. }
  464. hwspin_unlock_irqrestore(__smem->hwlock, &flags);
  465. return ret;
  466. }
  467. EXPORT_SYMBOL_GPL(qcom_smem_alloc);
  468. static void *qcom_smem_get_global(struct qcom_smem *smem,
  469. unsigned item,
  470. size_t *size)
  471. {
  472. struct smem_header *header;
  473. struct smem_region *region;
  474. struct smem_global_entry *entry;
  475. u64 entry_offset;
  476. u32 e_size;
  477. u32 aux_base;
  478. unsigned i;
  479. header = smem->regions[0].virt_base;
  480. entry = &header->toc[item];
  481. if (!entry->allocated)
  482. return ERR_PTR(-ENXIO);
  483. aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
  484. for (i = 0; i < smem->num_regions; i++) {
  485. region = &smem->regions[i];
  486. if ((u32)region->aux_base == aux_base || !aux_base) {
  487. e_size = le32_to_cpu(entry->size);
  488. entry_offset = le32_to_cpu(entry->offset);
  489. if (WARN_ON(e_size + entry_offset > region->size))
  490. return ERR_PTR(-EINVAL);
  491. if (size != NULL)
  492. *size = e_size;
  493. return region->virt_base + entry_offset;
  494. }
  495. }
  496. return ERR_PTR(-ENOENT);
  497. }
  498. static void *qcom_smem_get_private(struct qcom_smem *smem,
  499. struct smem_partition *part,
  500. unsigned item,
  501. size_t *size)
  502. {
  503. struct smem_private_entry *e, *end;
  504. struct smem_partition_header *phdr;
  505. void *item_ptr, *p_end;
  506. u32 padding_data;
  507. u32 e_size;
  508. phdr = (struct smem_partition_header __force *)part->virt_base;
  509. p_end = (void *)phdr + part->size;
  510. e = phdr_to_first_uncached_entry(phdr);
  511. end = phdr_to_last_uncached_entry(phdr);
  512. while (e < end) {
  513. if (e->canary != SMEM_PRIVATE_CANARY)
  514. goto invalid_canary;
  515. if (le16_to_cpu(e->item) == item) {
  516. if (size != NULL) {
  517. e_size = le32_to_cpu(e->size);
  518. padding_data = le16_to_cpu(e->padding_data);
  519. if (WARN_ON(e_size > part->size || padding_data > e_size))
  520. return ERR_PTR(-EINVAL);
  521. *size = e_size - padding_data;
  522. }
  523. item_ptr = uncached_entry_to_item(e);
  524. if (WARN_ON(item_ptr > p_end))
  525. return ERR_PTR(-EINVAL);
  526. return item_ptr;
  527. }
  528. e = uncached_entry_next(e);
  529. }
  530. if (WARN_ON((void *)e > p_end))
  531. return ERR_PTR(-EINVAL);
  532. /* Item was not found in the uncached list, search the cached list */
  533. e = phdr_to_first_cached_entry(phdr, part->cacheline);
  534. end = phdr_to_last_cached_entry(phdr);
  535. if (WARN_ON((void *)e < (void *)phdr || (void *)end > p_end))
  536. return ERR_PTR(-EINVAL);
  537. while (e > end) {
  538. if (e->canary != SMEM_PRIVATE_CANARY)
  539. goto invalid_canary;
  540. if (le16_to_cpu(e->item) == item) {
  541. if (size != NULL) {
  542. e_size = le32_to_cpu(e->size);
  543. padding_data = le16_to_cpu(e->padding_data);
  544. if (WARN_ON(e_size > part->size || padding_data > e_size))
  545. return ERR_PTR(-EINVAL);
  546. *size = e_size - padding_data;
  547. }
  548. item_ptr = cached_entry_to_item(e);
  549. if (WARN_ON(item_ptr < (void *)phdr))
  550. return ERR_PTR(-EINVAL);
  551. return item_ptr;
  552. }
  553. e = cached_entry_next(e, part->cacheline);
  554. }
  555. if (WARN_ON((void *)e < (void *)phdr))
  556. return ERR_PTR(-EINVAL);
  557. return ERR_PTR(-ENOENT);
  558. invalid_canary:
  559. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  560. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  561. return ERR_PTR(-EINVAL);
  562. }
  563. /**
  564. * qcom_smem_get() - resolve ptr of size of a smem item
  565. * @host: the remote processor, or -1
  566. * @item: smem item handle
  567. * @size: pointer to be filled out with size of the item
  568. *
  569. * Looks up smem item and returns pointer to it. Size of smem
  570. * item is returned in @size.
  571. */
  572. void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
  573. {
  574. struct smem_partition *part;
  575. void *ptr = ERR_PTR(-EPROBE_DEFER);
  576. if (!__smem)
  577. return ptr;
  578. if (WARN_ON(item >= __smem->item_count))
  579. return ERR_PTR(-EINVAL);
  580. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  581. part = &__smem->partitions[host];
  582. ptr = qcom_smem_get_private(__smem, part, item, size);
  583. } else if (__smem->global_partition.virt_base) {
  584. part = &__smem->global_partition;
  585. ptr = qcom_smem_get_private(__smem, part, item, size);
  586. } else {
  587. ptr = qcom_smem_get_global(__smem, item, size);
  588. }
  589. return ptr;
  590. }
  591. EXPORT_SYMBOL_GPL(qcom_smem_get);
  592. /**
  593. * qcom_smem_get_free_space() - retrieve amount of free space in a partition
  594. * @host: the remote processor identifying a partition, or -1
  595. *
  596. * To be used by smem clients as a quick way to determine if any new
  597. * allocations has been made.
  598. */
  599. int qcom_smem_get_free_space(unsigned host)
  600. {
  601. struct smem_partition *part;
  602. struct smem_partition_header *phdr;
  603. struct smem_header *header;
  604. unsigned ret;
  605. if (!__smem)
  606. return -EPROBE_DEFER;
  607. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  608. part = &__smem->partitions[host];
  609. phdr = part->virt_base;
  610. ret = le32_to_cpu(phdr->offset_free_cached) -
  611. le32_to_cpu(phdr->offset_free_uncached);
  612. if (ret > le32_to_cpu(part->size))
  613. return -EINVAL;
  614. } else if (__smem->global_partition.virt_base) {
  615. part = &__smem->global_partition;
  616. phdr = part->virt_base;
  617. ret = le32_to_cpu(phdr->offset_free_cached) -
  618. le32_to_cpu(phdr->offset_free_uncached);
  619. if (ret > le32_to_cpu(part->size))
  620. return -EINVAL;
  621. } else {
  622. header = __smem->regions[0].virt_base;
  623. ret = le32_to_cpu(header->available);
  624. if (ret > __smem->regions[0].size)
  625. return -EINVAL;
  626. }
  627. return ret;
  628. }
  629. EXPORT_SYMBOL_GPL(qcom_smem_get_free_space);
  630. static bool addr_in_range(void __iomem *base, size_t size, void *addr)
  631. {
  632. return base && ((void __iomem *)addr >= base && (void __iomem *)addr < base + size);
  633. }
  634. /**
  635. * qcom_smem_virt_to_phys() - return the physical address associated
  636. * with an smem item pointer (previously returned by qcom_smem_get()
  637. * @p: the virtual address to convert
  638. *
  639. * Returns 0 if the pointer provided is not within any smem region.
  640. */
  641. phys_addr_t qcom_smem_virt_to_phys(void *p)
  642. {
  643. struct smem_partition *part;
  644. struct smem_region *area;
  645. u64 offset;
  646. u32 i;
  647. for (i = 0; i < SMEM_HOST_COUNT; i++) {
  648. part = &__smem->partitions[i];
  649. if (addr_in_range(part->virt_base, part->size, p)) {
  650. offset = p - part->virt_base;
  651. return (phys_addr_t)part->phys_base + offset;
  652. }
  653. }
  654. part = &__smem->global_partition;
  655. if (addr_in_range(part->virt_base, part->size, p)) {
  656. offset = p - part->virt_base;
  657. return (phys_addr_t)part->phys_base + offset;
  658. }
  659. for (i = 0; i < __smem->num_regions; i++) {
  660. area = &__smem->regions[i];
  661. if (addr_in_range(area->virt_base, area->size, p)) {
  662. offset = p - area->virt_base;
  663. return (phys_addr_t)area->aux_base + offset;
  664. }
  665. }
  666. return 0;
  667. }
  668. EXPORT_SYMBOL_GPL(qcom_smem_virt_to_phys);
  669. /**
  670. * qcom_smem_get_soc_id() - return the SoC ID
  671. * @id: On success, we return the SoC ID here.
  672. *
  673. * Look up SoC ID from HW/SW build ID and return it.
  674. *
  675. * Return: 0 on success, negative errno on failure.
  676. */
  677. int qcom_smem_get_soc_id(u32 *id)
  678. {
  679. struct socinfo *info;
  680. info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
  681. if (IS_ERR(info))
  682. return PTR_ERR(info);
  683. *id = __le32_to_cpu(info->id);
  684. return 0;
  685. }
  686. EXPORT_SYMBOL_GPL(qcom_smem_get_soc_id);
  687. /**
  688. * qcom_smem_get_feature_code() - return the feature code
  689. * @code: On success, return the feature code here.
  690. *
  691. * Look up the feature code identifier from SMEM and return it.
  692. *
  693. * Return: 0 on success, negative errno on failure.
  694. */
  695. int qcom_smem_get_feature_code(u32 *code)
  696. {
  697. struct socinfo *info;
  698. u32 raw_code;
  699. info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
  700. if (IS_ERR(info))
  701. return PTR_ERR(info);
  702. /* This only makes sense for socinfo >= 16 */
  703. if (__le32_to_cpu(info->fmt) < SOCINFO_VERSION(0, 16))
  704. return -EOPNOTSUPP;
  705. raw_code = __le32_to_cpu(info->feature_code);
  706. /* Ensure the value makes sense */
  707. if (raw_code > SOCINFO_FC_INT_MAX)
  708. raw_code = SOCINFO_FC_UNKNOWN;
  709. *code = raw_code;
  710. return 0;
  711. }
  712. EXPORT_SYMBOL_GPL(qcom_smem_get_feature_code);
  713. static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
  714. {
  715. struct smem_header *header;
  716. __le32 *versions;
  717. header = smem->regions[0].virt_base;
  718. versions = header->version;
  719. return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]);
  720. }
  721. static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem)
  722. {
  723. struct smem_ptable *ptable;
  724. u32 version;
  725. ptable = smem->ptable;
  726. if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic)))
  727. return ERR_PTR(-ENOENT);
  728. version = le32_to_cpu(ptable->version);
  729. if (version != 1) {
  730. dev_err(smem->dev,
  731. "Unsupported partition header version %d\n", version);
  732. return ERR_PTR(-EINVAL);
  733. }
  734. return ptable;
  735. }
  736. static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
  737. {
  738. struct smem_ptable *ptable;
  739. struct smem_info *info;
  740. ptable = qcom_smem_get_ptable(smem);
  741. if (IS_ERR_OR_NULL(ptable))
  742. return SMEM_ITEM_COUNT;
  743. info = (struct smem_info *)&ptable->entry[ptable->num_entries];
  744. if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic)))
  745. return SMEM_ITEM_COUNT;
  746. return le16_to_cpu(info->num_items);
  747. }
  748. /*
  749. * Validate the partition header for a partition whose partition
  750. * table entry is supplied. Returns a pointer to its header if
  751. * valid, or a null pointer otherwise.
  752. */
  753. static struct smem_partition_header *
  754. qcom_smem_partition_header(struct qcom_smem *smem,
  755. struct smem_ptable_entry *entry, u16 host0, u16 host1)
  756. {
  757. struct smem_partition_header *header;
  758. u32 phys_addr;
  759. u32 size;
  760. phys_addr = smem->regions[0].aux_base + le32_to_cpu(entry->offset);
  761. header = devm_ioremap_wc(smem->dev, phys_addr, le32_to_cpu(entry->size));
  762. if (!header)
  763. return NULL;
  764. if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
  765. dev_err(smem->dev, "bad partition magic %4ph\n", header->magic);
  766. return NULL;
  767. }
  768. if (host0 != le16_to_cpu(header->host0)) {
  769. dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
  770. host0, le16_to_cpu(header->host0));
  771. return NULL;
  772. }
  773. if (host1 != le16_to_cpu(header->host1)) {
  774. dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
  775. host1, le16_to_cpu(header->host1));
  776. return NULL;
  777. }
  778. size = le32_to_cpu(header->size);
  779. if (size != le32_to_cpu(entry->size)) {
  780. dev_err(smem->dev, "bad partition size (%u != %u)\n",
  781. size, le32_to_cpu(entry->size));
  782. return NULL;
  783. }
  784. if (le32_to_cpu(header->offset_free_uncached) > size) {
  785. dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
  786. le32_to_cpu(header->offset_free_uncached), size);
  787. return NULL;
  788. }
  789. return header;
  790. }
  791. static int qcom_smem_set_global_partition(struct qcom_smem *smem)
  792. {
  793. struct smem_partition_header *header;
  794. struct smem_ptable_entry *entry;
  795. struct smem_ptable *ptable;
  796. bool found = false;
  797. int i;
  798. if (smem->global_partition.virt_base) {
  799. dev_err(smem->dev, "Already found the global partition\n");
  800. return -EINVAL;
  801. }
  802. ptable = qcom_smem_get_ptable(smem);
  803. if (IS_ERR(ptable))
  804. return PTR_ERR(ptable);
  805. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  806. entry = &ptable->entry[i];
  807. if (!le32_to_cpu(entry->offset))
  808. continue;
  809. if (!le32_to_cpu(entry->size))
  810. continue;
  811. if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
  812. continue;
  813. if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
  814. found = true;
  815. break;
  816. }
  817. }
  818. if (!found) {
  819. dev_err(smem->dev, "Missing entry for global partition\n");
  820. return -EINVAL;
  821. }
  822. header = qcom_smem_partition_header(smem, entry,
  823. SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
  824. if (!header)
  825. return -EINVAL;
  826. smem->global_partition.virt_base = (void __iomem *)header;
  827. smem->global_partition.phys_base = smem->regions[0].aux_base +
  828. le32_to_cpu(entry->offset);
  829. smem->global_partition.size = le32_to_cpu(entry->size);
  830. smem->global_partition.cacheline = le32_to_cpu(entry->cacheline);
  831. return 0;
  832. }
  833. static int
  834. qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
  835. {
  836. struct smem_partition_header *header;
  837. struct smem_ptable_entry *entry;
  838. struct smem_ptable *ptable;
  839. u16 remote_host;
  840. u16 host0, host1;
  841. int i;
  842. ptable = qcom_smem_get_ptable(smem);
  843. if (IS_ERR(ptable))
  844. return PTR_ERR(ptable);
  845. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  846. entry = &ptable->entry[i];
  847. if (!le32_to_cpu(entry->offset))
  848. continue;
  849. if (!le32_to_cpu(entry->size))
  850. continue;
  851. host0 = le16_to_cpu(entry->host0);
  852. host1 = le16_to_cpu(entry->host1);
  853. if (host0 == local_host)
  854. remote_host = host1;
  855. else if (host1 == local_host)
  856. remote_host = host0;
  857. else
  858. continue;
  859. if (remote_host >= SMEM_HOST_COUNT) {
  860. dev_err(smem->dev, "bad host %u\n", remote_host);
  861. return -EINVAL;
  862. }
  863. if (smem->partitions[remote_host].virt_base) {
  864. dev_err(smem->dev, "duplicate host %u\n", remote_host);
  865. return -EINVAL;
  866. }
  867. header = qcom_smem_partition_header(smem, entry, host0, host1);
  868. if (!header)
  869. return -EINVAL;
  870. smem->partitions[remote_host].virt_base = (void __iomem *)header;
  871. smem->partitions[remote_host].phys_base = smem->regions[0].aux_base +
  872. le32_to_cpu(entry->offset);
  873. smem->partitions[remote_host].size = le32_to_cpu(entry->size);
  874. smem->partitions[remote_host].cacheline = le32_to_cpu(entry->cacheline);
  875. }
  876. return 0;
  877. }
  878. static int qcom_smem_map_toc(struct qcom_smem *smem, struct smem_region *region)
  879. {
  880. u32 ptable_start;
  881. /* map starting 4K for smem header */
  882. region->virt_base = devm_ioremap_wc(smem->dev, region->aux_base, SZ_4K);
  883. ptable_start = region->aux_base + region->size - SZ_4K;
  884. /* map last 4k for toc */
  885. smem->ptable = devm_ioremap_wc(smem->dev, ptable_start, SZ_4K);
  886. if (!region->virt_base || !smem->ptable)
  887. return -ENOMEM;
  888. return 0;
  889. }
  890. static int qcom_smem_map_global(struct qcom_smem *smem, u32 size)
  891. {
  892. u32 phys_addr;
  893. phys_addr = smem->regions[0].aux_base;
  894. smem->regions[0].size = size;
  895. smem->regions[0].virt_base = devm_ioremap_wc(smem->dev, phys_addr, size);
  896. if (!smem->regions[0].virt_base)
  897. return -ENOMEM;
  898. return 0;
  899. }
  900. static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name,
  901. struct smem_region *region)
  902. {
  903. struct device *dev = smem->dev;
  904. struct device_node *np;
  905. struct resource r;
  906. int ret;
  907. np = of_parse_phandle(dev->of_node, name, 0);
  908. if (!np) {
  909. dev_err(dev, "No %s specified\n", name);
  910. return -EINVAL;
  911. }
  912. ret = of_address_to_resource(np, 0, &r);
  913. of_node_put(np);
  914. if (ret)
  915. return ret;
  916. region->aux_base = r.start;
  917. region->size = resource_size(&r);
  918. return 0;
  919. }
  920. static int qcom_smem_probe(struct platform_device *pdev)
  921. {
  922. struct smem_header *header;
  923. struct reserved_mem *rmem;
  924. struct qcom_smem *smem;
  925. unsigned long flags;
  926. int num_regions;
  927. int hwlock_id;
  928. u32 version;
  929. u32 size;
  930. int ret;
  931. int i;
  932. num_regions = 1;
  933. if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram"))
  934. num_regions++;
  935. smem = devm_kzalloc(&pdev->dev, struct_size(smem, regions, num_regions),
  936. GFP_KERNEL);
  937. if (!smem)
  938. return -ENOMEM;
  939. smem->dev = &pdev->dev;
  940. smem->num_regions = num_regions;
  941. rmem = of_reserved_mem_lookup(pdev->dev.of_node);
  942. if (rmem) {
  943. smem->regions[0].aux_base = rmem->base;
  944. smem->regions[0].size = rmem->size;
  945. } else {
  946. /*
  947. * Fall back to the memory-region reference, if we're not a
  948. * reserved-memory node.
  949. */
  950. ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]);
  951. if (ret)
  952. return ret;
  953. }
  954. if (num_regions > 1) {
  955. ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]);
  956. if (ret)
  957. return ret;
  958. }
  959. ret = qcom_smem_map_toc(smem, &smem->regions[0]);
  960. if (ret)
  961. return ret;
  962. for (i = 1; i < num_regions; i++) {
  963. smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev,
  964. smem->regions[i].aux_base,
  965. smem->regions[i].size);
  966. if (!smem->regions[i].virt_base) {
  967. dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base);
  968. return -ENOMEM;
  969. }
  970. }
  971. header = smem->regions[0].virt_base;
  972. if (le32_to_cpu(header->initialized) != 1 ||
  973. le32_to_cpu(header->reserved)) {
  974. dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
  975. return -EINVAL;
  976. }
  977. hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
  978. if (hwlock_id < 0) {
  979. if (hwlock_id != -EPROBE_DEFER)
  980. dev_err(&pdev->dev, "failed to retrieve hwlock\n");
  981. return hwlock_id;
  982. }
  983. smem->hwlock = hwspin_lock_request_specific(hwlock_id);
  984. if (!smem->hwlock)
  985. return -ENXIO;
  986. ret = hwspin_lock_timeout_irqsave(smem->hwlock, HWSPINLOCK_TIMEOUT, &flags);
  987. if (ret)
  988. return ret;
  989. size = readl_relaxed(&header->available) + readl_relaxed(&header->free_offset);
  990. hwspin_unlock_irqrestore(smem->hwlock, &flags);
  991. version = qcom_smem_get_sbl_version(smem);
  992. /*
  993. * smem header mapping is required only in heap version scheme, so unmap
  994. * it here. It will be remapped in qcom_smem_map_global() when whole
  995. * partition is mapped again.
  996. */
  997. devm_iounmap(smem->dev, smem->regions[0].virt_base);
  998. switch (version >> 16) {
  999. case SMEM_GLOBAL_PART_VERSION:
  1000. ret = qcom_smem_set_global_partition(smem);
  1001. if (ret < 0)
  1002. return ret;
  1003. smem->item_count = qcom_smem_get_item_count(smem);
  1004. break;
  1005. case SMEM_GLOBAL_HEAP_VERSION:
  1006. qcom_smem_map_global(smem, size);
  1007. smem->item_count = SMEM_ITEM_COUNT;
  1008. break;
  1009. default:
  1010. dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version);
  1011. return -EINVAL;
  1012. }
  1013. BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
  1014. ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
  1015. if (ret < 0 && ret != -ENOENT)
  1016. return ret;
  1017. __smem = smem;
  1018. smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
  1019. PLATFORM_DEVID_NONE, NULL,
  1020. 0);
  1021. if (IS_ERR(smem->socinfo))
  1022. dev_dbg(&pdev->dev, "failed to register socinfo device\n");
  1023. return 0;
  1024. }
  1025. static void qcom_smem_remove(struct platform_device *pdev)
  1026. {
  1027. platform_device_unregister(__smem->socinfo);
  1028. hwspin_lock_free(__smem->hwlock);
  1029. __smem = NULL;
  1030. }
  1031. static const struct of_device_id qcom_smem_of_match[] = {
  1032. { .compatible = "qcom,smem" },
  1033. {}
  1034. };
  1035. MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
  1036. static struct platform_driver qcom_smem_driver = {
  1037. .probe = qcom_smem_probe,
  1038. .remove_new = qcom_smem_remove,
  1039. .driver = {
  1040. .name = "qcom-smem",
  1041. .of_match_table = qcom_smem_of_match,
  1042. .suppress_bind_attrs = true,
  1043. },
  1044. };
  1045. static int __init qcom_smem_init(void)
  1046. {
  1047. return platform_driver_register(&qcom_smem_driver);
  1048. }
  1049. arch_initcall(qcom_smem_init);
  1050. static void __exit qcom_smem_exit(void)
  1051. {
  1052. platform_driver_unregister(&qcom_smem_driver);
  1053. }
  1054. module_exit(qcom_smem_exit)
  1055. MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
  1056. MODULE_DESCRIPTION("Qualcomm Shared Memory Manager");
  1057. MODULE_LICENSE("GPL v2");