smem.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286
  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 25
  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. /*
  315. * Pointer to the one and only smem handle.
  316. * Init to -EPROBE_DEFER to signal SMEM still has to be probed.
  317. * Can be set to -ENODEV if SMEM is not initialized by SBL.
  318. */
  319. static struct qcom_smem *__smem = INIT_ERR_PTR(-EPROBE_DEFER);
  320. /* Timeout (ms) for the trylock of remote spinlocks */
  321. #define HWSPINLOCK_TIMEOUT 1000
  322. /* The qcom hwspinlock id is always plus one from the smem host id */
  323. #define SMEM_HOST_ID_TO_HWSPINLOCK_ID(__x) ((__x) + 1)
  324. /**
  325. * qcom_smem_bust_hwspin_lock_by_host() - bust the smem hwspinlock for a host
  326. * @host: remote processor id
  327. *
  328. * Busts the hwspin_lock for the given smem host id. This helper is intended
  329. * for remoteproc drivers that manage remoteprocs with an equivalent smem
  330. * driver instance in the remote firmware. Drivers can force a release of the
  331. * smem hwspin_lock if the rproc unexpectedly goes into a bad state.
  332. *
  333. * Context: Process context.
  334. *
  335. * Returns: 0 on success, otherwise negative errno.
  336. */
  337. int qcom_smem_bust_hwspin_lock_by_host(unsigned int host)
  338. {
  339. /* This function is for remote procs, so ignore SMEM_HOST_APPS */
  340. if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT)
  341. return -EINVAL;
  342. return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host));
  343. }
  344. EXPORT_SYMBOL_GPL(qcom_smem_bust_hwspin_lock_by_host);
  345. /**
  346. * qcom_smem_is_available() - Check if SMEM is available
  347. *
  348. * Return: true if SMEM is available, false otherwise.
  349. */
  350. bool qcom_smem_is_available(void)
  351. {
  352. return !IS_ERR(__smem);
  353. }
  354. EXPORT_SYMBOL_GPL(qcom_smem_is_available);
  355. static int qcom_smem_alloc_private(struct qcom_smem *smem,
  356. struct smem_partition *part,
  357. unsigned item,
  358. size_t size)
  359. {
  360. struct smem_private_entry *hdr, *end;
  361. struct smem_partition_header *phdr;
  362. size_t alloc_size;
  363. void *cached;
  364. void *p_end;
  365. phdr = (struct smem_partition_header __force *)part->virt_base;
  366. p_end = (void *)phdr + part->size;
  367. hdr = phdr_to_first_uncached_entry(phdr);
  368. end = phdr_to_last_uncached_entry(phdr);
  369. cached = phdr_to_last_cached_entry(phdr);
  370. if (WARN_ON((void *)end > p_end || cached > p_end))
  371. return -EINVAL;
  372. while (hdr < end) {
  373. if (hdr->canary != SMEM_PRIVATE_CANARY)
  374. goto bad_canary;
  375. if (le16_to_cpu(hdr->item) == item)
  376. return -EEXIST;
  377. hdr = uncached_entry_next(hdr);
  378. }
  379. if (WARN_ON((void *)hdr > p_end))
  380. return -EINVAL;
  381. /* Check that we don't grow into the cached region */
  382. alloc_size = sizeof(*hdr) + ALIGN(size, 8);
  383. if ((void *)hdr + alloc_size > cached) {
  384. dev_err(smem->dev, "Out of memory\n");
  385. return -ENOSPC;
  386. }
  387. hdr->canary = SMEM_PRIVATE_CANARY;
  388. hdr->item = cpu_to_le16(item);
  389. hdr->size = cpu_to_le32(ALIGN(size, 8));
  390. hdr->padding_data = cpu_to_le16(le32_to_cpu(hdr->size) - size);
  391. hdr->padding_hdr = 0;
  392. /*
  393. * Ensure the header is written before we advance the free offset, so
  394. * that remote processors that does not take the remote spinlock still
  395. * gets a consistent view of the linked list.
  396. */
  397. wmb();
  398. le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
  399. return 0;
  400. bad_canary:
  401. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  402. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  403. return -EINVAL;
  404. }
  405. static int qcom_smem_alloc_global(struct qcom_smem *smem,
  406. unsigned item,
  407. size_t size)
  408. {
  409. struct smem_global_entry *entry;
  410. struct smem_header *header;
  411. header = smem->regions[0].virt_base;
  412. entry = &header->toc[item];
  413. if (entry->allocated)
  414. return -EEXIST;
  415. size = ALIGN(size, 8);
  416. if (WARN_ON(size > le32_to_cpu(header->available)))
  417. return -ENOMEM;
  418. entry->offset = header->free_offset;
  419. entry->size = cpu_to_le32(size);
  420. /*
  421. * Ensure the header is consistent before we mark the item allocated,
  422. * so that remote processors will get a consistent view of the item
  423. * even though they do not take the spinlock on read.
  424. */
  425. wmb();
  426. entry->allocated = cpu_to_le32(1);
  427. le32_add_cpu(&header->free_offset, size);
  428. le32_add_cpu(&header->available, -size);
  429. return 0;
  430. }
  431. /**
  432. * qcom_smem_alloc() - allocate space for a smem item
  433. * @host: remote processor id, or -1
  434. * @item: smem item handle
  435. * @size: number of bytes to be allocated
  436. *
  437. * Allocate space for a given smem item of size @size, given that the item is
  438. * not yet allocated.
  439. *
  440. * Return: 0 on success, negative errno on failure.
  441. */
  442. int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
  443. {
  444. struct smem_partition *part;
  445. unsigned long flags;
  446. int ret;
  447. if (IS_ERR(__smem))
  448. return PTR_ERR(__smem);
  449. if (item < SMEM_ITEM_LAST_FIXED) {
  450. dev_err(__smem->dev,
  451. "Rejecting allocation of static entry %d\n", item);
  452. return -EINVAL;
  453. }
  454. if (item >= __smem->item_count)
  455. return -EINVAL;
  456. ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
  457. HWSPINLOCK_TIMEOUT,
  458. &flags);
  459. if (ret)
  460. return ret;
  461. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  462. part = &__smem->partitions[host];
  463. ret = qcom_smem_alloc_private(__smem, part, item, size);
  464. } else if (__smem->global_partition.virt_base) {
  465. part = &__smem->global_partition;
  466. ret = qcom_smem_alloc_private(__smem, part, item, size);
  467. } else {
  468. ret = qcom_smem_alloc_global(__smem, item, size);
  469. }
  470. hwspin_unlock_irqrestore(__smem->hwlock, &flags);
  471. return ret;
  472. }
  473. EXPORT_SYMBOL_GPL(qcom_smem_alloc);
  474. static void *qcom_smem_get_global(struct qcom_smem *smem,
  475. unsigned item,
  476. size_t *size)
  477. {
  478. struct smem_header *header;
  479. struct smem_region *region;
  480. struct smem_global_entry *entry;
  481. u64 entry_offset;
  482. u32 e_size;
  483. u32 aux_base;
  484. unsigned i;
  485. header = smem->regions[0].virt_base;
  486. entry = &header->toc[item];
  487. if (!entry->allocated)
  488. return ERR_PTR(-ENXIO);
  489. aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
  490. for (i = 0; i < smem->num_regions; i++) {
  491. region = &smem->regions[i];
  492. if ((u32)region->aux_base == aux_base || !aux_base) {
  493. e_size = le32_to_cpu(entry->size);
  494. entry_offset = le32_to_cpu(entry->offset);
  495. if (WARN_ON(e_size + entry_offset > region->size))
  496. return ERR_PTR(-EINVAL);
  497. if (size != NULL)
  498. *size = e_size;
  499. return region->virt_base + entry_offset;
  500. }
  501. }
  502. return ERR_PTR(-ENOENT);
  503. }
  504. static void *qcom_smem_get_private(struct qcom_smem *smem,
  505. struct smem_partition *part,
  506. unsigned item,
  507. size_t *size)
  508. {
  509. struct smem_private_entry *e, *end;
  510. struct smem_partition_header *phdr;
  511. void *item_ptr, *p_end;
  512. u32 padding_data;
  513. u32 e_size;
  514. phdr = (struct smem_partition_header __force *)part->virt_base;
  515. p_end = (void *)phdr + part->size;
  516. e = phdr_to_first_uncached_entry(phdr);
  517. end = phdr_to_last_uncached_entry(phdr);
  518. while (e < end) {
  519. if (e->canary != SMEM_PRIVATE_CANARY)
  520. goto invalid_canary;
  521. if (le16_to_cpu(e->item) == item) {
  522. if (size != NULL) {
  523. e_size = le32_to_cpu(e->size);
  524. padding_data = le16_to_cpu(e->padding_data);
  525. if (WARN_ON(e_size > part->size || padding_data > e_size))
  526. return ERR_PTR(-EINVAL);
  527. *size = e_size - padding_data;
  528. }
  529. item_ptr = uncached_entry_to_item(e);
  530. if (WARN_ON(item_ptr > p_end))
  531. return ERR_PTR(-EINVAL);
  532. return item_ptr;
  533. }
  534. e = uncached_entry_next(e);
  535. }
  536. if (WARN_ON((void *)e > p_end))
  537. return ERR_PTR(-EINVAL);
  538. /* Item was not found in the uncached list, search the cached list */
  539. e = phdr_to_first_cached_entry(phdr, part->cacheline);
  540. end = phdr_to_last_cached_entry(phdr);
  541. if (WARN_ON((void *)e < (void *)phdr || (void *)end > p_end))
  542. return ERR_PTR(-EINVAL);
  543. while (e > end) {
  544. if (e->canary != SMEM_PRIVATE_CANARY)
  545. goto invalid_canary;
  546. if (le16_to_cpu(e->item) == item) {
  547. if (size != NULL) {
  548. e_size = le32_to_cpu(e->size);
  549. padding_data = le16_to_cpu(e->padding_data);
  550. if (WARN_ON(e_size > part->size || padding_data > e_size))
  551. return ERR_PTR(-EINVAL);
  552. *size = e_size - padding_data;
  553. }
  554. item_ptr = cached_entry_to_item(e);
  555. if (WARN_ON(item_ptr < (void *)phdr))
  556. return ERR_PTR(-EINVAL);
  557. return item_ptr;
  558. }
  559. e = cached_entry_next(e, part->cacheline);
  560. }
  561. if (WARN_ON((void *)e < (void *)phdr))
  562. return ERR_PTR(-EINVAL);
  563. return ERR_PTR(-ENOENT);
  564. invalid_canary:
  565. dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
  566. le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
  567. return ERR_PTR(-EINVAL);
  568. }
  569. /**
  570. * qcom_smem_get() - resolve ptr of size of a smem item
  571. * @host: the remote processor, or -1
  572. * @item: smem item handle
  573. * @size: pointer to be filled out with size of the item
  574. *
  575. * Looks up smem item and returns pointer to it. Size of smem
  576. * item is returned in @size.
  577. *
  578. * Return: a pointer to an SMEM item on success, ERR_PTR() on failure.
  579. */
  580. void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
  581. {
  582. struct smem_partition *part;
  583. void *ptr;
  584. if (IS_ERR(__smem))
  585. return __smem;
  586. if (item >= __smem->item_count)
  587. return ERR_PTR(-EINVAL);
  588. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  589. part = &__smem->partitions[host];
  590. ptr = qcom_smem_get_private(__smem, part, item, size);
  591. } else if (__smem->global_partition.virt_base) {
  592. part = &__smem->global_partition;
  593. ptr = qcom_smem_get_private(__smem, part, item, size);
  594. } else {
  595. ptr = qcom_smem_get_global(__smem, item, size);
  596. }
  597. return ptr;
  598. }
  599. EXPORT_SYMBOL_GPL(qcom_smem_get);
  600. /**
  601. * qcom_smem_get_free_space() - retrieve amount of free space in a partition
  602. * @host: the remote processor identifying a partition, or -1
  603. *
  604. * To be used by smem clients as a quick way to determine if any new
  605. * allocations has been made.
  606. *
  607. * Return: number of available bytes on success, negative errno on failure.
  608. */
  609. int qcom_smem_get_free_space(unsigned host)
  610. {
  611. struct smem_partition *part;
  612. struct smem_partition_header *phdr;
  613. struct smem_header *header;
  614. unsigned ret;
  615. if (IS_ERR(__smem))
  616. return PTR_ERR(__smem);
  617. if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
  618. part = &__smem->partitions[host];
  619. phdr = part->virt_base;
  620. ret = le32_to_cpu(phdr->offset_free_cached) -
  621. le32_to_cpu(phdr->offset_free_uncached);
  622. if (ret > le32_to_cpu(part->size))
  623. return -EINVAL;
  624. } else if (__smem->global_partition.virt_base) {
  625. part = &__smem->global_partition;
  626. phdr = part->virt_base;
  627. ret = le32_to_cpu(phdr->offset_free_cached) -
  628. le32_to_cpu(phdr->offset_free_uncached);
  629. if (ret > le32_to_cpu(part->size))
  630. return -EINVAL;
  631. } else {
  632. header = __smem->regions[0].virt_base;
  633. ret = le32_to_cpu(header->available);
  634. if (ret > __smem->regions[0].size)
  635. return -EINVAL;
  636. }
  637. return ret;
  638. }
  639. EXPORT_SYMBOL_GPL(qcom_smem_get_free_space);
  640. static bool addr_in_range(void __iomem *base, size_t size, void *addr)
  641. {
  642. return base && ((void __iomem *)addr >= base && (void __iomem *)addr < base + size);
  643. }
  644. /**
  645. * qcom_smem_virt_to_phys() - return the physical address associated
  646. * with an smem item pointer (previously returned by qcom_smem_get()
  647. * @p: the virtual address to convert
  648. *
  649. * Return: physical address of the SMEM item (if found), 0 otherwise
  650. */
  651. phys_addr_t qcom_smem_virt_to_phys(void *p)
  652. {
  653. struct smem_partition *part;
  654. struct smem_region *area;
  655. u64 offset;
  656. u32 i;
  657. for (i = 0; i < SMEM_HOST_COUNT; i++) {
  658. part = &__smem->partitions[i];
  659. if (addr_in_range(part->virt_base, part->size, p)) {
  660. offset = p - part->virt_base;
  661. return (phys_addr_t)part->phys_base + offset;
  662. }
  663. }
  664. part = &__smem->global_partition;
  665. if (addr_in_range(part->virt_base, part->size, p)) {
  666. offset = p - part->virt_base;
  667. return (phys_addr_t)part->phys_base + offset;
  668. }
  669. for (i = 0; i < __smem->num_regions; i++) {
  670. area = &__smem->regions[i];
  671. if (addr_in_range(area->virt_base, area->size, p)) {
  672. offset = p - area->virt_base;
  673. return (phys_addr_t)area->aux_base + offset;
  674. }
  675. }
  676. return 0;
  677. }
  678. EXPORT_SYMBOL_GPL(qcom_smem_virt_to_phys);
  679. /**
  680. * qcom_smem_get_soc_id() - return the SoC ID
  681. * @id: On success, we return the SoC ID here.
  682. *
  683. * Look up SoC ID from HW/SW build ID and return it.
  684. *
  685. * Return: 0 on success, negative errno on failure.
  686. */
  687. int qcom_smem_get_soc_id(u32 *id)
  688. {
  689. struct socinfo *info;
  690. info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
  691. if (IS_ERR(info))
  692. return PTR_ERR(info);
  693. *id = __le32_to_cpu(info->id);
  694. return 0;
  695. }
  696. EXPORT_SYMBOL_GPL(qcom_smem_get_soc_id);
  697. /**
  698. * qcom_smem_get_feature_code() - return the feature code
  699. * @code: On success, return the feature code here.
  700. *
  701. * Look up the feature code identifier from SMEM and return it.
  702. *
  703. * Return: 0 on success, negative errno on failure.
  704. */
  705. int qcom_smem_get_feature_code(u32 *code)
  706. {
  707. struct socinfo *info;
  708. u32 raw_code;
  709. info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL);
  710. if (IS_ERR(info))
  711. return PTR_ERR(info);
  712. /* This only makes sense for socinfo >= 16 */
  713. if (__le32_to_cpu(info->fmt) < SOCINFO_VERSION(0, 16))
  714. return -EOPNOTSUPP;
  715. raw_code = __le32_to_cpu(info->feature_code);
  716. /* Ensure the value makes sense */
  717. if (raw_code > SOCINFO_FC_INT_MAX)
  718. raw_code = SOCINFO_FC_UNKNOWN;
  719. *code = raw_code;
  720. return 0;
  721. }
  722. EXPORT_SYMBOL_GPL(qcom_smem_get_feature_code);
  723. static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
  724. {
  725. struct smem_header *header;
  726. __le32 *versions;
  727. header = smem->regions[0].virt_base;
  728. versions = header->version;
  729. return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]);
  730. }
  731. static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem)
  732. {
  733. struct smem_ptable *ptable;
  734. u32 version;
  735. ptable = smem->ptable;
  736. if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic)))
  737. return ERR_PTR(-ENOENT);
  738. version = le32_to_cpu(ptable->version);
  739. if (version != 1) {
  740. dev_err(smem->dev,
  741. "Unsupported partition header version %d\n", version);
  742. return ERR_PTR(-EINVAL);
  743. }
  744. return ptable;
  745. }
  746. static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
  747. {
  748. struct smem_ptable *ptable;
  749. struct smem_info *info;
  750. ptable = qcom_smem_get_ptable(smem);
  751. if (IS_ERR_OR_NULL(ptable))
  752. return SMEM_ITEM_COUNT;
  753. info = (struct smem_info *)&ptable->entry[le32_to_cpu(ptable->num_entries)];
  754. if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic)))
  755. return SMEM_ITEM_COUNT;
  756. return le16_to_cpu(info->num_items);
  757. }
  758. /*
  759. * Validate the partition header for a partition whose partition
  760. * table entry is supplied. Returns a pointer to its header if
  761. * valid, or a null pointer otherwise.
  762. */
  763. static struct smem_partition_header *
  764. qcom_smem_partition_header(struct qcom_smem *smem,
  765. struct smem_ptable_entry *entry, u16 host0, u16 host1)
  766. {
  767. struct smem_partition_header *header;
  768. u32 phys_addr;
  769. u32 size;
  770. phys_addr = smem->regions[0].aux_base + le32_to_cpu(entry->offset);
  771. header = devm_ioremap_wc(smem->dev, phys_addr, le32_to_cpu(entry->size));
  772. if (!header)
  773. return NULL;
  774. if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
  775. dev_err(smem->dev, "bad partition magic %4ph\n", header->magic);
  776. return NULL;
  777. }
  778. if (host0 != le16_to_cpu(header->host0)) {
  779. dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
  780. host0, le16_to_cpu(header->host0));
  781. return NULL;
  782. }
  783. if (host1 != le16_to_cpu(header->host1)) {
  784. dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
  785. host1, le16_to_cpu(header->host1));
  786. return NULL;
  787. }
  788. size = le32_to_cpu(header->size);
  789. if (size != le32_to_cpu(entry->size)) {
  790. dev_err(smem->dev, "bad partition size (%u != %u)\n",
  791. size, le32_to_cpu(entry->size));
  792. return NULL;
  793. }
  794. if (le32_to_cpu(header->offset_free_uncached) > size) {
  795. dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
  796. le32_to_cpu(header->offset_free_uncached), size);
  797. return NULL;
  798. }
  799. return header;
  800. }
  801. static int qcom_smem_set_global_partition(struct qcom_smem *smem)
  802. {
  803. struct smem_partition_header *header;
  804. struct smem_ptable_entry *entry;
  805. struct smem_ptable *ptable;
  806. bool found = false;
  807. int i;
  808. if (smem->global_partition.virt_base) {
  809. dev_err(smem->dev, "Already found the global partition\n");
  810. return -EINVAL;
  811. }
  812. ptable = qcom_smem_get_ptable(smem);
  813. if (IS_ERR(ptable))
  814. return PTR_ERR(ptable);
  815. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  816. entry = &ptable->entry[i];
  817. if (!le32_to_cpu(entry->offset))
  818. continue;
  819. if (!le32_to_cpu(entry->size))
  820. continue;
  821. if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
  822. continue;
  823. if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
  824. found = true;
  825. break;
  826. }
  827. }
  828. if (!found) {
  829. dev_err(smem->dev, "Missing entry for global partition\n");
  830. return -EINVAL;
  831. }
  832. header = qcom_smem_partition_header(smem, entry,
  833. SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
  834. if (!header)
  835. return -EINVAL;
  836. smem->global_partition.virt_base = (void __iomem *)header;
  837. smem->global_partition.phys_base = smem->regions[0].aux_base +
  838. le32_to_cpu(entry->offset);
  839. smem->global_partition.size = le32_to_cpu(entry->size);
  840. smem->global_partition.cacheline = le32_to_cpu(entry->cacheline);
  841. return 0;
  842. }
  843. static int
  844. qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
  845. {
  846. struct smem_partition_header *header;
  847. struct smem_ptable_entry *entry;
  848. struct smem_ptable *ptable;
  849. u16 remote_host;
  850. u16 host0, host1;
  851. int i;
  852. ptable = qcom_smem_get_ptable(smem);
  853. if (IS_ERR(ptable))
  854. return PTR_ERR(ptable);
  855. for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
  856. entry = &ptable->entry[i];
  857. if (!le32_to_cpu(entry->offset))
  858. continue;
  859. if (!le32_to_cpu(entry->size))
  860. continue;
  861. host0 = le16_to_cpu(entry->host0);
  862. host1 = le16_to_cpu(entry->host1);
  863. if (host0 == local_host)
  864. remote_host = host1;
  865. else if (host1 == local_host)
  866. remote_host = host0;
  867. else
  868. continue;
  869. if (remote_host >= SMEM_HOST_COUNT) {
  870. dev_err(smem->dev, "bad host %u\n", remote_host);
  871. return -EINVAL;
  872. }
  873. if (smem->partitions[remote_host].virt_base) {
  874. dev_err(smem->dev, "duplicate host %u\n", remote_host);
  875. return -EINVAL;
  876. }
  877. header = qcom_smem_partition_header(smem, entry, host0, host1);
  878. if (!header)
  879. return -EINVAL;
  880. smem->partitions[remote_host].virt_base = (void __iomem *)header;
  881. smem->partitions[remote_host].phys_base = smem->regions[0].aux_base +
  882. le32_to_cpu(entry->offset);
  883. smem->partitions[remote_host].size = le32_to_cpu(entry->size);
  884. smem->partitions[remote_host].cacheline = le32_to_cpu(entry->cacheline);
  885. }
  886. return 0;
  887. }
  888. static int qcom_smem_map_toc(struct qcom_smem *smem, struct smem_region *region)
  889. {
  890. u32 ptable_start;
  891. /* map starting 4K for smem header */
  892. region->virt_base = devm_ioremap_wc(smem->dev, region->aux_base, SZ_4K);
  893. ptable_start = region->aux_base + region->size - SZ_4K;
  894. /* map last 4k for toc */
  895. smem->ptable = devm_ioremap_wc(smem->dev, ptable_start, SZ_4K);
  896. if (!region->virt_base || !smem->ptable)
  897. return -ENOMEM;
  898. return 0;
  899. }
  900. static int qcom_smem_map_global(struct qcom_smem *smem, u32 size)
  901. {
  902. u32 phys_addr;
  903. phys_addr = smem->regions[0].aux_base;
  904. smem->regions[0].size = size;
  905. smem->regions[0].virt_base = devm_ioremap_wc(smem->dev, phys_addr, size);
  906. if (!smem->regions[0].virt_base)
  907. return -ENOMEM;
  908. return 0;
  909. }
  910. static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name,
  911. struct smem_region *region)
  912. {
  913. struct device *dev = smem->dev;
  914. struct device_node *np;
  915. struct resource r;
  916. int ret;
  917. np = of_parse_phandle(dev->of_node, name, 0);
  918. if (!np) {
  919. dev_err(dev, "No %s specified\n", name);
  920. return -EINVAL;
  921. }
  922. ret = of_address_to_resource(np, 0, &r);
  923. of_node_put(np);
  924. if (ret)
  925. return ret;
  926. region->aux_base = r.start;
  927. region->size = resource_size(&r);
  928. return 0;
  929. }
  930. static int qcom_smem_probe(struct platform_device *pdev)
  931. {
  932. struct smem_header *header;
  933. struct reserved_mem *rmem;
  934. struct qcom_smem *smem;
  935. unsigned long flags;
  936. int num_regions;
  937. int hwlock_id;
  938. u32 version;
  939. u32 size;
  940. int ret;
  941. int i;
  942. num_regions = 1;
  943. if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram"))
  944. num_regions++;
  945. smem = devm_kzalloc(&pdev->dev, struct_size(smem, regions, num_regions),
  946. GFP_KERNEL);
  947. if (!smem)
  948. return -ENOMEM;
  949. smem->dev = &pdev->dev;
  950. smem->num_regions = num_regions;
  951. rmem = of_reserved_mem_lookup(pdev->dev.of_node);
  952. if (rmem) {
  953. smem->regions[0].aux_base = rmem->base;
  954. smem->regions[0].size = rmem->size;
  955. } else {
  956. /*
  957. * Fall back to the memory-region reference, if we're not a
  958. * reserved-memory node.
  959. */
  960. ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]);
  961. if (ret)
  962. return ret;
  963. }
  964. if (num_regions > 1) {
  965. ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]);
  966. if (ret)
  967. return ret;
  968. }
  969. ret = qcom_smem_map_toc(smem, &smem->regions[0]);
  970. if (ret)
  971. return ret;
  972. for (i = 1; i < num_regions; i++) {
  973. smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev,
  974. smem->regions[i].aux_base,
  975. smem->regions[i].size);
  976. if (!smem->regions[i].virt_base) {
  977. dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base);
  978. return -ENOMEM;
  979. }
  980. }
  981. header = smem->regions[0].virt_base;
  982. if (le32_to_cpu(header->initialized) != 1 ||
  983. le32_to_cpu(header->reserved)) {
  984. __smem = ERR_PTR(-ENODEV);
  985. return dev_err_probe(&pdev->dev, PTR_ERR(__smem), "SMEM is not initialized by SBL\n");
  986. }
  987. hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
  988. if (hwlock_id < 0)
  989. return dev_err_probe(&pdev->dev, hwlock_id,
  990. "failed to retrieve hwlock\n");
  991. smem->hwlock = devm_hwspin_lock_request_specific(&pdev->dev, hwlock_id);
  992. if (!smem->hwlock)
  993. return -ENXIO;
  994. ret = hwspin_lock_timeout_irqsave(smem->hwlock, HWSPINLOCK_TIMEOUT, &flags);
  995. if (ret)
  996. return ret;
  997. size = readl_relaxed(&header->available) + readl_relaxed(&header->free_offset);
  998. hwspin_unlock_irqrestore(smem->hwlock, &flags);
  999. version = qcom_smem_get_sbl_version(smem);
  1000. /*
  1001. * smem header mapping is required only in heap version scheme, so unmap
  1002. * it here. It will be remapped in qcom_smem_map_global() when whole
  1003. * partition is mapped again.
  1004. */
  1005. devm_iounmap(smem->dev, smem->regions[0].virt_base);
  1006. switch (version >> 16) {
  1007. case SMEM_GLOBAL_PART_VERSION:
  1008. ret = qcom_smem_set_global_partition(smem);
  1009. if (ret < 0)
  1010. return ret;
  1011. smem->item_count = qcom_smem_get_item_count(smem);
  1012. break;
  1013. case SMEM_GLOBAL_HEAP_VERSION:
  1014. ret = qcom_smem_map_global(smem, size);
  1015. if (ret < 0)
  1016. return ret;
  1017. smem->item_count = SMEM_ITEM_COUNT;
  1018. break;
  1019. default:
  1020. dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version);
  1021. return -EINVAL;
  1022. }
  1023. BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
  1024. ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
  1025. if (ret < 0 && ret != -ENOENT)
  1026. return ret;
  1027. __smem = smem;
  1028. smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
  1029. PLATFORM_DEVID_NONE, NULL,
  1030. 0);
  1031. if (IS_ERR(smem->socinfo))
  1032. dev_dbg(&pdev->dev, "failed to register socinfo device\n");
  1033. return 0;
  1034. }
  1035. static void qcom_smem_remove(struct platform_device *pdev)
  1036. {
  1037. platform_device_unregister(__smem->socinfo);
  1038. /* Set to -EPROBE_DEFER to signal unprobed state */
  1039. __smem = ERR_PTR(-EPROBE_DEFER);
  1040. }
  1041. static const struct of_device_id qcom_smem_of_match[] = {
  1042. { .compatible = "qcom,smem" },
  1043. {}
  1044. };
  1045. MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
  1046. static struct platform_driver qcom_smem_driver = {
  1047. .probe = qcom_smem_probe,
  1048. .remove = qcom_smem_remove,
  1049. .driver = {
  1050. .name = "qcom-smem",
  1051. .of_match_table = qcom_smem_of_match,
  1052. .suppress_bind_attrs = true,
  1053. },
  1054. };
  1055. static int __init qcom_smem_init(void)
  1056. {
  1057. return platform_driver_register(&qcom_smem_driver);
  1058. }
  1059. arch_initcall(qcom_smem_init);
  1060. static void __exit qcom_smem_exit(void)
  1061. {
  1062. platform_driver_unregister(&qcom_smem_driver);
  1063. }
  1064. module_exit(qcom_smem_exit)
  1065. MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
  1066. MODULE_DESCRIPTION("Qualcomm Shared Memory Manager");
  1067. MODULE_LICENSE("GPL v2");