0012-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. From 725e07b7b70c601ebbe15436736addc01953dfe7 Mon Sep 17 00:00:00 2001
  2. From: popcornmix <popcornmix@gmail.com>
  3. Date: Wed, 3 Jul 2013 00:31:47 +0100
  4. Subject: [PATCH 012/114] cma: Add vc_cma driver to enable use of CMA
  5. Signed-off-by: popcornmix <popcornmix@gmail.com>
  6. ---
  7. drivers/char/Kconfig | 2 +
  8. drivers/char/Makefile | 1 +
  9. drivers/char/broadcom/Kconfig | 15 +
  10. drivers/char/broadcom/Makefile | 1 +
  11. drivers/char/broadcom/vc_cma/Makefile | 14 +
  12. drivers/char/broadcom/vc_cma/vc_cma.c | 1143 +++++++++++++++++++++++++++++++++
  13. drivers/misc/Makefile | 2 +-
  14. include/linux/broadcom/vc_cma.h | 29 +
  15. 8 files changed, 1206 insertions(+), 1 deletion(-)
  16. create mode 100644 drivers/char/broadcom/Kconfig
  17. create mode 100644 drivers/char/broadcom/Makefile
  18. create mode 100644 drivers/char/broadcom/vc_cma/Makefile
  19. create mode 100644 drivers/char/broadcom/vc_cma/vc_cma.c
  20. create mode 100644 include/linux/broadcom/vc_cma.h
  21. --- a/drivers/char/Kconfig
  22. +++ b/drivers/char/Kconfig
  23. @@ -583,6 +583,8 @@ config DEVPORT
  24. source "drivers/s390/char/Kconfig"
  25. +source "drivers/char/broadcom/Kconfig"
  26. +
  27. config MSM_SMD_PKT
  28. bool "Enable device interface for some SMD packet ports"
  29. default n
  30. --- a/drivers/char/Makefile
  31. +++ b/drivers/char/Makefile
  32. @@ -62,3 +62,4 @@ js-rtc-y = rtc.o
  33. obj-$(CONFIG_TILE_SROM) += tile-srom.o
  34. obj-$(CONFIG_XILLYBUS) += xillybus/
  35. +obj-$(CONFIG_BRCM_CHAR_DRIVERS) += broadcom/
  36. --- /dev/null
  37. +++ b/drivers/char/broadcom/Kconfig
  38. @@ -0,0 +1,15 @@
  39. +#
  40. +# Broadcom char driver config
  41. +#
  42. +
  43. +menuconfig BRCM_CHAR_DRIVERS
  44. + bool "Broadcom Char Drivers"
  45. + help
  46. + Broadcom's char drivers
  47. +
  48. +config BCM_VC_CMA
  49. + bool "Videocore CMA"
  50. + depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
  51. + default n
  52. + help
  53. + Helper for videocore CMA access.
  54. --- /dev/null
  55. +++ b/drivers/char/broadcom/Makefile
  56. @@ -0,0 +1 @@
  57. +obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
  58. --- /dev/null
  59. +++ b/drivers/char/broadcom/vc_cma/Makefile
  60. @@ -0,0 +1,14 @@
  61. +ccflags-y += -Wall -Wstrict-prototypes -Wno-trigraphs
  62. +ccflags-y += -Werror
  63. +ccflags-y += -Iinclude/linux/broadcom
  64. +ccflags-y += -Idrivers/misc/vc04_services
  65. +ccflags-y += -Idrivers/misc/vc04_services/interface/vchi
  66. +ccflags-y += -Idrivers/misc/vc04_services/interface/vchiq_arm
  67. +
  68. +ccflags-y += -D__KERNEL__
  69. +ccflags-y += -D__linux__
  70. +ccflags-y += -Werror
  71. +
  72. +obj-$(CONFIG_BCM_VC_CMA) += vc-cma.o
  73. +
  74. +vc-cma-objs := vc_cma.o
  75. --- /dev/null
  76. +++ b/drivers/char/broadcom/vc_cma/vc_cma.c
  77. @@ -0,0 +1,1143 @@
  78. +/**
  79. + * Copyright (c) 2010-2012 Broadcom. All rights reserved.
  80. + *
  81. + * Redistribution and use in source and binary forms, with or without
  82. + * modification, are permitted provided that the following conditions
  83. + * are met:
  84. + * 1. Redistributions of source code must retain the above copyright
  85. + * notice, this list of conditions, and the following disclaimer,
  86. + * without modification.
  87. + * 2. Redistributions in binary form must reproduce the above copyright
  88. + * notice, this list of conditions and the following disclaimer in the
  89. + * documentation and/or other materials provided with the distribution.
  90. + * 3. The names of the above-listed copyright holders may not be used
  91. + * to endorse or promote products derived from this software without
  92. + * specific prior written permission.
  93. + *
  94. + * ALTERNATIVELY, this software may be distributed under the terms of the
  95. + * GNU General Public License ("GPL") version 2, as published by the Free
  96. + * Software Foundation.
  97. + *
  98. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  99. + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  100. + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  101. + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  102. + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  103. + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  104. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  105. + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  106. + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  107. + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  108. + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  109. + */
  110. +
  111. +#include <linux/kernel.h>
  112. +#include <linux/module.h>
  113. +#include <linux/kthread.h>
  114. +#include <linux/fs.h>
  115. +#include <linux/device.h>
  116. +#include <linux/cdev.h>
  117. +#include <linux/mm.h>
  118. +#include <linux/proc_fs.h>
  119. +#include <linux/seq_file.h>
  120. +#include <linux/dma-mapping.h>
  121. +#include <linux/dma-contiguous.h>
  122. +#include <linux/platform_device.h>
  123. +#include <linux/uaccess.h>
  124. +#include <asm/cacheflush.h>
  125. +
  126. +#include "vc_cma.h"
  127. +
  128. +#include "vchiq_util.h"
  129. +#include "vchiq_connected.h"
  130. +//#include "debug_sym.h"
  131. +//#include "vc_mem.h"
  132. +
  133. +#define DRIVER_NAME "vc-cma"
  134. +
  135. +#define LOG_DBG(fmt, ...) \
  136. + if (vc_cma_debug) \
  137. + printk(KERN_INFO fmt "\n", ##__VA_ARGS__)
  138. +#define LOG_ERR(fmt, ...) \
  139. + printk(KERN_ERR fmt "\n", ##__VA_ARGS__)
  140. +
  141. +#define VC_CMA_FOURCC VCHIQ_MAKE_FOURCC('C', 'M', 'A', ' ')
  142. +#define VC_CMA_VERSION 2
  143. +
  144. +#define VC_CMA_CHUNK_ORDER 6 /* 256K */
  145. +#define VC_CMA_CHUNK_SIZE (4096 << VC_CMA_CHUNK_ORDER)
  146. +#define VC_CMA_MAX_PARAMS_PER_MSG \
  147. + ((VCHIQ_MAX_MSG_SIZE - sizeof(unsigned short))/sizeof(unsigned short))
  148. +#define VC_CMA_RESERVE_COUNT_MAX 16
  149. +
  150. +#define PAGES_PER_CHUNK (VC_CMA_CHUNK_SIZE / PAGE_SIZE)
  151. +
  152. +#define VCADDR_TO_PHYSADDR(vcaddr) (mm_vc_mem_phys_addr + vcaddr)
  153. +
  154. +#define loud_error(...) \
  155. + LOG_ERR("===== " __VA_ARGS__)
  156. +
  157. +enum {
  158. + VC_CMA_MSG_QUIT,
  159. + VC_CMA_MSG_OPEN,
  160. + VC_CMA_MSG_TICK,
  161. + VC_CMA_MSG_ALLOC, /* chunk count */
  162. + VC_CMA_MSG_FREE, /* chunk, chunk, ... */
  163. + VC_CMA_MSG_ALLOCATED, /* chunk, chunk, ... */
  164. + VC_CMA_MSG_REQUEST_ALLOC, /* chunk count */
  165. + VC_CMA_MSG_REQUEST_FREE, /* chunk count */
  166. + VC_CMA_MSG_RESERVE, /* bytes lo, bytes hi */
  167. + VC_CMA_MSG_UPDATE_RESERVE,
  168. + VC_CMA_MSG_MAX
  169. +};
  170. +
  171. +struct cma_msg {
  172. + unsigned short type;
  173. + unsigned short params[VC_CMA_MAX_PARAMS_PER_MSG];
  174. +};
  175. +
  176. +struct vc_cma_reserve_user {
  177. + unsigned int pid;
  178. + unsigned int reserve;
  179. +};
  180. +
  181. +/* Device (/dev) related variables */
  182. +static dev_t vc_cma_devnum;
  183. +static struct class *vc_cma_class;
  184. +static struct cdev vc_cma_cdev;
  185. +static int vc_cma_inited;
  186. +static int vc_cma_debug;
  187. +
  188. +/* Proc entry */
  189. +static struct proc_dir_entry *vc_cma_proc_entry;
  190. +
  191. +phys_addr_t vc_cma_base;
  192. +struct page *vc_cma_base_page;
  193. +unsigned int vc_cma_size;
  194. +EXPORT_SYMBOL(vc_cma_size);
  195. +unsigned int vc_cma_initial;
  196. +unsigned int vc_cma_chunks;
  197. +unsigned int vc_cma_chunks_used;
  198. +unsigned int vc_cma_chunks_reserved;
  199. +
  200. +static int in_loud_error;
  201. +
  202. +unsigned int vc_cma_reserve_total;
  203. +unsigned int vc_cma_reserve_count;
  204. +struct vc_cma_reserve_user vc_cma_reserve_users[VC_CMA_RESERVE_COUNT_MAX];
  205. +static DEFINE_SEMAPHORE(vc_cma_reserve_mutex);
  206. +static DEFINE_SEMAPHORE(vc_cma_worker_queue_push_mutex);
  207. +
  208. +static u64 vc_cma_dma_mask = DMA_BIT_MASK(32);
  209. +static struct platform_device vc_cma_device = {
  210. + .name = "vc-cma",
  211. + .id = 0,
  212. + .dev = {
  213. + .dma_mask = &vc_cma_dma_mask,
  214. + .coherent_dma_mask = DMA_BIT_MASK(32),
  215. + },
  216. +};
  217. +
  218. +static VCHIQ_INSTANCE_T cma_instance;
  219. +static VCHIQ_SERVICE_HANDLE_T cma_service;
  220. +static VCHIU_QUEUE_T cma_msg_queue;
  221. +static struct task_struct *cma_worker;
  222. +
  223. +static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid);
  224. +static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply);
  225. +static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
  226. + VCHIQ_HEADER_T * header,
  227. + VCHIQ_SERVICE_HANDLE_T service,
  228. + void *bulk_userdata);
  229. +static void send_vc_msg(unsigned short type,
  230. + unsigned short param1, unsigned short param2);
  231. +static bool send_worker_msg(VCHIQ_HEADER_T * msg);
  232. +
  233. +static int early_vc_cma_mem(char *p)
  234. +{
  235. + unsigned int new_size;
  236. + printk(KERN_NOTICE "early_vc_cma_mem(%s)", p);
  237. + vc_cma_size = memparse(p, &p);
  238. + vc_cma_initial = vc_cma_size;
  239. + if (*p == '/')
  240. + vc_cma_size = memparse(p + 1, &p);
  241. + if (*p == '@')
  242. + vc_cma_base = memparse(p + 1, &p);
  243. +
  244. + new_size = (vc_cma_size - ((-vc_cma_base) & (VC_CMA_CHUNK_SIZE - 1)))
  245. + & ~(VC_CMA_CHUNK_SIZE - 1);
  246. + if (new_size > vc_cma_size)
  247. + vc_cma_size = 0;
  248. + vc_cma_initial = (vc_cma_initial + VC_CMA_CHUNK_SIZE - 1)
  249. + & ~(VC_CMA_CHUNK_SIZE - 1);
  250. + if (vc_cma_initial > vc_cma_size)
  251. + vc_cma_initial = vc_cma_size;
  252. + vc_cma_base = (vc_cma_base + VC_CMA_CHUNK_SIZE - 1)
  253. + & ~(VC_CMA_CHUNK_SIZE - 1);
  254. +
  255. + printk(KERN_NOTICE " -> initial %x, size %x, base %x", vc_cma_initial,
  256. + vc_cma_size, (unsigned int)vc_cma_base);
  257. +
  258. + return 0;
  259. +}
  260. +
  261. +early_param("vc-cma-mem", early_vc_cma_mem);
  262. +
  263. +void vc_cma_early_init(void)
  264. +{
  265. + LOG_DBG("vc_cma_early_init - vc_cma_chunks = %d", vc_cma_chunks);
  266. + if (vc_cma_size) {
  267. + int rc = platform_device_register(&vc_cma_device);
  268. + LOG_DBG("platform_device_register -> %d", rc);
  269. + }
  270. +}
  271. +
  272. +void vc_cma_reserve(void)
  273. +{
  274. + /* if vc_cma_size is set, then declare vc CMA area of the same
  275. + * size from the end of memory
  276. + */
  277. + if (vc_cma_size) {
  278. + if (dma_declare_contiguous(NULL /*&vc_cma_device.dev*/, vc_cma_size,
  279. + vc_cma_base, 0) == 0) {
  280. + } else {
  281. + LOG_ERR("vc_cma: dma_declare_contiguous(%x,%x) failed",
  282. + vc_cma_size, (unsigned int)vc_cma_base);
  283. + vc_cma_size = 0;
  284. + }
  285. + }
  286. + vc_cma_chunks = vc_cma_size / VC_CMA_CHUNK_SIZE;
  287. +}
  288. +
  289. +/****************************************************************************
  290. +*
  291. +* vc_cma_open
  292. +*
  293. +***************************************************************************/
  294. +
  295. +static int vc_cma_open(struct inode *inode, struct file *file)
  296. +{
  297. + (void)inode;
  298. + (void)file;
  299. +
  300. + return 0;
  301. +}
  302. +
  303. +/****************************************************************************
  304. +*
  305. +* vc_cma_release
  306. +*
  307. +***************************************************************************/
  308. +
  309. +static int vc_cma_release(struct inode *inode, struct file *file)
  310. +{
  311. + (void)inode;
  312. + (void)file;
  313. +
  314. + vc_cma_set_reserve(0, current->tgid);
  315. +
  316. + return 0;
  317. +}
  318. +
  319. +/****************************************************************************
  320. +*
  321. +* vc_cma_ioctl
  322. +*
  323. +***************************************************************************/
  324. +
  325. +static long vc_cma_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  326. +{
  327. + int rc = 0;
  328. +
  329. + (void)cmd;
  330. + (void)arg;
  331. +
  332. + switch (cmd) {
  333. + case VC_CMA_IOC_RESERVE:
  334. + rc = vc_cma_set_reserve((unsigned int)arg, current->tgid);
  335. + if (rc >= 0)
  336. + rc = 0;
  337. + break;
  338. + default:
  339. + LOG_ERR("vc-cma: Unknown ioctl %x", cmd);
  340. + return -ENOTTY;
  341. + }
  342. +
  343. + return rc;
  344. +}
  345. +
  346. +/****************************************************************************
  347. +*
  348. +* File Operations for the driver.
  349. +*
  350. +***************************************************************************/
  351. +
  352. +static const struct file_operations vc_cma_fops = {
  353. + .owner = THIS_MODULE,
  354. + .open = vc_cma_open,
  355. + .release = vc_cma_release,
  356. + .unlocked_ioctl = vc_cma_ioctl,
  357. +};
  358. +
  359. +/****************************************************************************
  360. +*
  361. +* vc_cma_proc_open
  362. +*
  363. +***************************************************************************/
  364. +
  365. +static int vc_cma_show_info(struct seq_file *m, void *v)
  366. +{
  367. + int i;
  368. +
  369. + seq_printf(m, "Videocore CMA:\n");
  370. + seq_printf(m, " Base : %08x\n", (unsigned int)vc_cma_base);
  371. + seq_printf(m, " Length : %08x\n", vc_cma_size);
  372. + seq_printf(m, " Initial : %08x\n", vc_cma_initial);
  373. + seq_printf(m, " Chunk size : %08x\n", VC_CMA_CHUNK_SIZE);
  374. + seq_printf(m, " Chunks : %4d (%d bytes)\n",
  375. + (int)vc_cma_chunks,
  376. + (int)(vc_cma_chunks * VC_CMA_CHUNK_SIZE));
  377. + seq_printf(m, " Used : %4d (%d bytes)\n",
  378. + (int)vc_cma_chunks_used,
  379. + (int)(vc_cma_chunks_used * VC_CMA_CHUNK_SIZE));
  380. + seq_printf(m, " Reserved : %4d (%d bytes)\n",
  381. + (unsigned int)vc_cma_chunks_reserved,
  382. + (int)(vc_cma_chunks_reserved * VC_CMA_CHUNK_SIZE));
  383. +
  384. + for (i = 0; i < vc_cma_reserve_count; i++) {
  385. + struct vc_cma_reserve_user *user = &vc_cma_reserve_users[i];
  386. + seq_printf(m, " PID %5d: %d bytes\n", user->pid,
  387. + user->reserve);
  388. + }
  389. +
  390. + seq_printf(m, "\n");
  391. +
  392. + return 0;
  393. +}
  394. +
  395. +static int vc_cma_proc_open(struct inode *inode, struct file *file)
  396. +{
  397. + return single_open(file, vc_cma_show_info, NULL);
  398. +}
  399. +
  400. +/****************************************************************************
  401. +*
  402. +* vc_cma_proc_write
  403. +*
  404. +***************************************************************************/
  405. +
  406. +static int vc_cma_proc_write(struct file *file,
  407. + const char __user *buffer,
  408. + size_t size, loff_t *ppos)
  409. +{
  410. + int rc = -EFAULT;
  411. + char input_str[20];
  412. +
  413. + memset(input_str, 0, sizeof(input_str));
  414. +
  415. + if (size > sizeof(input_str)) {
  416. + LOG_ERR("%s: input string length too long", __func__);
  417. + goto out;
  418. + }
  419. +
  420. + if (copy_from_user(input_str, buffer, size - 1)) {
  421. + LOG_ERR("%s: failed to get input string", __func__);
  422. + goto out;
  423. + }
  424. +#define ALLOC_STR "alloc"
  425. +#define FREE_STR "free"
  426. +#define DEBUG_STR "debug"
  427. +#define RESERVE_STR "reserve"
  428. + if (strncmp(input_str, ALLOC_STR, strlen(ALLOC_STR)) == 0) {
  429. + int size;
  430. + char *p = input_str + strlen(ALLOC_STR);
  431. +
  432. + while (*p == ' ')
  433. + p++;
  434. + size = memparse(p, NULL);
  435. + LOG_ERR("/proc/vc-cma: alloc %d", size);
  436. + if (size)
  437. + send_vc_msg(VC_CMA_MSG_REQUEST_FREE,
  438. + size / VC_CMA_CHUNK_SIZE, 0);
  439. + else
  440. + LOG_ERR("invalid size '%s'", p);
  441. + rc = size;
  442. + } else if (strncmp(input_str, FREE_STR, strlen(FREE_STR)) == 0) {
  443. + int size;
  444. + char *p = input_str + strlen(FREE_STR);
  445. +
  446. + while (*p == ' ')
  447. + p++;
  448. + size = memparse(p, NULL);
  449. + LOG_ERR("/proc/vc-cma: free %d", size);
  450. + if (size)
  451. + send_vc_msg(VC_CMA_MSG_REQUEST_ALLOC,
  452. + size / VC_CMA_CHUNK_SIZE, 0);
  453. + else
  454. + LOG_ERR("invalid size '%s'", p);
  455. + rc = size;
  456. + } else if (strncmp(input_str, DEBUG_STR, strlen(DEBUG_STR)) == 0) {
  457. + char *p = input_str + strlen(DEBUG_STR);
  458. + while (*p == ' ')
  459. + p++;
  460. + if ((strcmp(p, "on") == 0) || (strcmp(p, "1") == 0))
  461. + vc_cma_debug = 1;
  462. + else if ((strcmp(p, "off") == 0) || (strcmp(p, "0") == 0))
  463. + vc_cma_debug = 0;
  464. + LOG_ERR("/proc/vc-cma: debug %s", vc_cma_debug ? "on" : "off");
  465. + rc = size;
  466. + } else if (strncmp(input_str, RESERVE_STR, strlen(RESERVE_STR)) == 0) {
  467. + int size;
  468. + int reserved;
  469. + char *p = input_str + strlen(RESERVE_STR);
  470. + while (*p == ' ')
  471. + p++;
  472. + size = memparse(p, NULL);
  473. +
  474. + reserved = vc_cma_set_reserve(size, current->tgid);
  475. + rc = (reserved >= 0) ? size : reserved;
  476. + }
  477. +
  478. +out:
  479. + return rc;
  480. +}
  481. +
  482. +/****************************************************************************
  483. +*
  484. +* File Operations for /proc interface.
  485. +*
  486. +***************************************************************************/
  487. +
  488. +static const struct file_operations vc_cma_proc_fops = {
  489. + .open = vc_cma_proc_open,
  490. + .read = seq_read,
  491. + .write = vc_cma_proc_write,
  492. + .llseek = seq_lseek,
  493. + .release = single_release
  494. +};
  495. +
  496. +static int vc_cma_set_reserve(unsigned int reserve, unsigned int pid)
  497. +{
  498. + struct vc_cma_reserve_user *user = NULL;
  499. + int delta = 0;
  500. + int i;
  501. +
  502. + if (down_interruptible(&vc_cma_reserve_mutex))
  503. + return -ERESTARTSYS;
  504. +
  505. + for (i = 0; i < vc_cma_reserve_count; i++) {
  506. + if (pid == vc_cma_reserve_users[i].pid) {
  507. + user = &vc_cma_reserve_users[i];
  508. + delta = reserve - user->reserve;
  509. + if (reserve)
  510. + user->reserve = reserve;
  511. + else {
  512. + /* Remove this entry by copying downwards */
  513. + while ((i + 1) < vc_cma_reserve_count) {
  514. + user[0].pid = user[1].pid;
  515. + user[0].reserve = user[1].reserve;
  516. + user++;
  517. + i++;
  518. + }
  519. + vc_cma_reserve_count--;
  520. + user = NULL;
  521. + }
  522. + break;
  523. + }
  524. + }
  525. +
  526. + if (reserve && !user) {
  527. + if (vc_cma_reserve_count == VC_CMA_RESERVE_COUNT_MAX) {
  528. + LOG_ERR("vc-cma: Too many reservations - "
  529. + "increase CMA_RESERVE_COUNT_MAX");
  530. + up(&vc_cma_reserve_mutex);
  531. + return -EBUSY;
  532. + }
  533. + user = &vc_cma_reserve_users[vc_cma_reserve_count];
  534. + user->pid = pid;
  535. + user->reserve = reserve;
  536. + delta = reserve;
  537. + vc_cma_reserve_count++;
  538. + }
  539. +
  540. + vc_cma_reserve_total += delta;
  541. +
  542. + send_vc_msg(VC_CMA_MSG_RESERVE,
  543. + vc_cma_reserve_total & 0xffff, vc_cma_reserve_total >> 16);
  544. +
  545. + send_worker_msg((VCHIQ_HEADER_T *) VC_CMA_MSG_UPDATE_RESERVE);
  546. +
  547. + LOG_DBG("/proc/vc-cma: reserve %d (PID %d) - total %u",
  548. + reserve, pid, vc_cma_reserve_total);
  549. +
  550. + up(&vc_cma_reserve_mutex);
  551. +
  552. + return vc_cma_reserve_total;
  553. +}
  554. +
  555. +static VCHIQ_STATUS_T cma_service_callback(VCHIQ_REASON_T reason,
  556. + VCHIQ_HEADER_T * header,
  557. + VCHIQ_SERVICE_HANDLE_T service,
  558. + void *bulk_userdata)
  559. +{
  560. + switch (reason) {
  561. + case VCHIQ_MESSAGE_AVAILABLE:
  562. + if (!send_worker_msg(header))
  563. + return VCHIQ_RETRY;
  564. + break;
  565. + case VCHIQ_SERVICE_CLOSED:
  566. + LOG_DBG("CMA service closed");
  567. + break;
  568. + default:
  569. + LOG_ERR("Unexpected CMA callback reason %d", reason);
  570. + break;
  571. + }
  572. + return VCHIQ_SUCCESS;
  573. +}
  574. +
  575. +static void send_vc_msg(unsigned short type,
  576. + unsigned short param1, unsigned short param2)
  577. +{
  578. + unsigned short msg[] = { type, param1, param2 };
  579. + VCHIQ_ELEMENT_T elem = { &msg, sizeof(msg) };
  580. + VCHIQ_STATUS_T ret;
  581. + vchiq_use_service(cma_service);
  582. + ret = vchiq_queue_message(cma_service, &elem, 1);
  583. + vchiq_release_service(cma_service);
  584. + if (ret != VCHIQ_SUCCESS)
  585. + LOG_ERR("vchiq_queue_message returned %x", ret);
  586. +}
  587. +
  588. +static bool send_worker_msg(VCHIQ_HEADER_T * msg)
  589. +{
  590. + if (down_interruptible(&vc_cma_worker_queue_push_mutex))
  591. + return false;
  592. + vchiu_queue_push(&cma_msg_queue, msg);
  593. + up(&vc_cma_worker_queue_push_mutex);
  594. + return true;
  595. +}
  596. +
  597. +static int vc_cma_alloc_chunks(int num_chunks, struct cma_msg *reply)
  598. +{
  599. + int i;
  600. + for (i = 0; i < num_chunks; i++) {
  601. + struct page *chunk;
  602. + unsigned int chunk_num;
  603. + uint8_t *chunk_addr;
  604. + size_t chunk_size = PAGES_PER_CHUNK << PAGE_SHIFT;
  605. +
  606. + chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/,
  607. + PAGES_PER_CHUNK,
  608. + VC_CMA_CHUNK_ORDER);
  609. + if (!chunk)
  610. + break;
  611. +
  612. + chunk_addr = page_address(chunk);
  613. + dmac_flush_range(chunk_addr, chunk_addr + chunk_size);
  614. + outer_inv_range(__pa(chunk_addr), __pa(chunk_addr) +
  615. + chunk_size);
  616. +
  617. + chunk_num =
  618. + (page_to_phys(chunk) - vc_cma_base) / VC_CMA_CHUNK_SIZE;
  619. + BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
  620. + VC_CMA_CHUNK_SIZE) != 0);
  621. + if (chunk_num >= vc_cma_chunks) {
  622. + LOG_ERR("%s: ===============================",
  623. + __func__);
  624. + LOG_ERR("%s: chunk phys %x, vc_cma %x-%x - "
  625. + "bad SPARSEMEM configuration?",
  626. + __func__, (unsigned int)page_to_phys(chunk),
  627. + vc_cma_base, vc_cma_base + vc_cma_size - 1);
  628. + LOG_ERR("%s: dev->cma_area = %p\n", __func__,
  629. + (void*)0/*vc_cma_device.dev.cma_area*/);
  630. + LOG_ERR("%s: ===============================",
  631. + __func__);
  632. + break;
  633. + }
  634. + reply->params[i] = chunk_num;
  635. + vc_cma_chunks_used++;
  636. + }
  637. +
  638. + if (i < num_chunks) {
  639. + LOG_ERR("%s: dma_alloc_from_contiguous failed "
  640. + "for %x bytes (alloc %d of %d, %d free)",
  641. + __func__, VC_CMA_CHUNK_SIZE, i,
  642. + num_chunks, vc_cma_chunks - vc_cma_chunks_used);
  643. + num_chunks = i;
  644. + }
  645. +
  646. + LOG_DBG("CMA allocated %d chunks -> %d used",
  647. + num_chunks, vc_cma_chunks_used);
  648. + reply->type = VC_CMA_MSG_ALLOCATED;
  649. +
  650. + {
  651. + VCHIQ_ELEMENT_T elem = {
  652. + reply,
  653. + offsetof(struct cma_msg, params[0]) +
  654. + num_chunks * sizeof(reply->params[0])
  655. + };
  656. + VCHIQ_STATUS_T ret;
  657. + vchiq_use_service(cma_service);
  658. + ret = vchiq_queue_message(cma_service, &elem, 1);
  659. + vchiq_release_service(cma_service);
  660. + if (ret != VCHIQ_SUCCESS)
  661. + LOG_ERR("vchiq_queue_message return " "%x", ret);
  662. + }
  663. +
  664. + return num_chunks;
  665. +}
  666. +
  667. +static int cma_worker_proc(void *param)
  668. +{
  669. + static struct cma_msg reply;
  670. + (void)param;
  671. +
  672. + while (1) {
  673. + VCHIQ_HEADER_T *msg;
  674. + static struct cma_msg msg_copy;
  675. + struct cma_msg *cma_msg = &msg_copy;
  676. + int type, msg_size;
  677. +
  678. + msg = vchiu_queue_pop(&cma_msg_queue);
  679. + if ((unsigned int)msg >= VC_CMA_MSG_MAX) {
  680. + msg_size = msg->size;
  681. + memcpy(&msg_copy, msg->data, msg_size);
  682. + type = cma_msg->type;
  683. + vchiq_release_message(cma_service, msg);
  684. + } else {
  685. + msg_size = 0;
  686. + type = (int)msg;
  687. + if (type == VC_CMA_MSG_QUIT)
  688. + break;
  689. + else if (type == VC_CMA_MSG_UPDATE_RESERVE) {
  690. + msg = NULL;
  691. + cma_msg = NULL;
  692. + } else {
  693. + BUG();
  694. + continue;
  695. + }
  696. + }
  697. +
  698. + switch (type) {
  699. + case VC_CMA_MSG_ALLOC:{
  700. + int num_chunks, free_chunks;
  701. + num_chunks = cma_msg->params[0];
  702. + free_chunks =
  703. + vc_cma_chunks - vc_cma_chunks_used;
  704. + LOG_DBG("CMA_MSG_ALLOC(%d chunks)", num_chunks);
  705. + if (num_chunks > VC_CMA_MAX_PARAMS_PER_MSG) {
  706. + LOG_ERR
  707. + ("CMA_MSG_ALLOC - chunk count (%d) "
  708. + "exceeds VC_CMA_MAX_PARAMS_PER_MSG (%d)",
  709. + num_chunks,
  710. + VC_CMA_MAX_PARAMS_PER_MSG);
  711. + num_chunks = VC_CMA_MAX_PARAMS_PER_MSG;
  712. + }
  713. +
  714. + if (num_chunks > free_chunks) {
  715. + LOG_ERR
  716. + ("CMA_MSG_ALLOC - chunk count (%d) "
  717. + "exceeds free chunks (%d)",
  718. + num_chunks, free_chunks);
  719. + num_chunks = free_chunks;
  720. + }
  721. +
  722. + vc_cma_alloc_chunks(num_chunks, &reply);
  723. + }
  724. + break;
  725. +
  726. + case VC_CMA_MSG_FREE:{
  727. + int chunk_count =
  728. + (msg_size -
  729. + offsetof(struct cma_msg,
  730. + params)) /
  731. + sizeof(cma_msg->params[0]);
  732. + int i;
  733. + BUG_ON(chunk_count <= 0);
  734. +
  735. + LOG_DBG("CMA_MSG_FREE(%d chunks - %x, ...)",
  736. + chunk_count, cma_msg->params[0]);
  737. + for (i = 0; i < chunk_count; i++) {
  738. + int chunk_num = cma_msg->params[i];
  739. + struct page *page = vc_cma_base_page +
  740. + chunk_num * PAGES_PER_CHUNK;
  741. + if (chunk_num >= vc_cma_chunks) {
  742. + LOG_ERR
  743. + ("CMA_MSG_FREE - chunk %d of %d"
  744. + " (value %x) exceeds maximum "
  745. + "(%x)", i, chunk_count,
  746. + chunk_num,
  747. + vc_cma_chunks - 1);
  748. + break;
  749. + }
  750. +
  751. + if (!dma_release_from_contiguous
  752. + (NULL /*&vc_cma_device.dev*/, page,
  753. + PAGES_PER_CHUNK)) {
  754. + LOG_ERR
  755. + ("CMA_MSG_FREE - failed to "
  756. + "release chunk %d (phys %x, "
  757. + "page %x)", chunk_num,
  758. + page_to_phys(page),
  759. + (unsigned int)page);
  760. + }
  761. + vc_cma_chunks_used--;
  762. + }
  763. + LOG_DBG("CMA released %d chunks -> %d used",
  764. + i, vc_cma_chunks_used);
  765. + }
  766. + break;
  767. +
  768. + case VC_CMA_MSG_UPDATE_RESERVE:{
  769. + int chunks_needed =
  770. + ((vc_cma_reserve_total + VC_CMA_CHUNK_SIZE -
  771. + 1)
  772. + / VC_CMA_CHUNK_SIZE) -
  773. + vc_cma_chunks_reserved;
  774. +
  775. + LOG_DBG
  776. + ("CMA_MSG_UPDATE_RESERVE(%d chunks needed)",
  777. + chunks_needed);
  778. +
  779. + /* Cap the reservations to what is available */
  780. + if (chunks_needed > 0) {
  781. + if (chunks_needed >
  782. + (vc_cma_chunks -
  783. + vc_cma_chunks_used))
  784. + chunks_needed =
  785. + (vc_cma_chunks -
  786. + vc_cma_chunks_used);
  787. +
  788. + chunks_needed =
  789. + vc_cma_alloc_chunks(chunks_needed,
  790. + &reply);
  791. + }
  792. +
  793. + LOG_DBG
  794. + ("CMA_MSG_UPDATE_RESERVE(%d chunks allocated)",
  795. + chunks_needed);
  796. + vc_cma_chunks_reserved += chunks_needed;
  797. + }
  798. + break;
  799. +
  800. + default:
  801. + LOG_ERR("unexpected msg type %d", type);
  802. + break;
  803. + }
  804. + }
  805. +
  806. + LOG_DBG("quitting...");
  807. + return 0;
  808. +}
  809. +
  810. +/****************************************************************************
  811. +*
  812. +* vc_cma_connected_init
  813. +*
  814. +* This function is called once the videocore has been connected.
  815. +*
  816. +***************************************************************************/
  817. +
  818. +static void vc_cma_connected_init(void)
  819. +{
  820. + VCHIQ_SERVICE_PARAMS_T service_params;
  821. +
  822. + LOG_DBG("vc_cma_connected_init");
  823. +
  824. + if (!vchiu_queue_init(&cma_msg_queue, 16)) {
  825. + LOG_ERR("could not create CMA msg queue");
  826. + goto fail_queue;
  827. + }
  828. +
  829. + if (vchiq_initialise(&cma_instance) != VCHIQ_SUCCESS)
  830. + goto fail_vchiq_init;
  831. +
  832. + vchiq_connect(cma_instance);
  833. +
  834. + service_params.fourcc = VC_CMA_FOURCC;
  835. + service_params.callback = cma_service_callback;
  836. + service_params.userdata = NULL;
  837. + service_params.version = VC_CMA_VERSION;
  838. + service_params.version_min = VC_CMA_VERSION;
  839. +
  840. + if (vchiq_open_service(cma_instance, &service_params,
  841. + &cma_service) != VCHIQ_SUCCESS) {
  842. + LOG_ERR("failed to open service - already in use?");
  843. + goto fail_vchiq_open;
  844. + }
  845. +
  846. + vchiq_release_service(cma_service);
  847. +
  848. + cma_worker = kthread_create(cma_worker_proc, NULL, "cma_worker");
  849. + if (!cma_worker) {
  850. + LOG_ERR("could not create CMA worker thread");
  851. + goto fail_worker;
  852. + }
  853. + set_user_nice(cma_worker, -20);
  854. + wake_up_process(cma_worker);
  855. +
  856. + return;
  857. +
  858. +fail_worker:
  859. + vchiq_close_service(cma_service);
  860. +fail_vchiq_open:
  861. + vchiq_shutdown(cma_instance);
  862. +fail_vchiq_init:
  863. + vchiu_queue_delete(&cma_msg_queue);
  864. +fail_queue:
  865. + return;
  866. +}
  867. +
  868. +void
  869. +loud_error_header(void)
  870. +{
  871. + if (in_loud_error)
  872. + return;
  873. +
  874. + LOG_ERR("============================================================"
  875. + "================");
  876. + LOG_ERR("============================================================"
  877. + "================");
  878. + LOG_ERR("=====");
  879. +
  880. + in_loud_error = 1;
  881. +}
  882. +
  883. +void
  884. +loud_error_footer(void)
  885. +{
  886. + if (!in_loud_error)
  887. + return;
  888. +
  889. + LOG_ERR("=====");
  890. + LOG_ERR("============================================================"
  891. + "================");
  892. + LOG_ERR("============================================================"
  893. + "================");
  894. +
  895. + in_loud_error = 0;
  896. +}
  897. +
  898. +#if 1
  899. +static int check_cma_config(void) { return 1; }
  900. +#else
  901. +static int
  902. +read_vc_debug_var(VC_MEM_ACCESS_HANDLE_T handle,
  903. + const char *symbol,
  904. + void *buf, size_t bufsize)
  905. +{
  906. + VC_MEM_ADDR_T vcMemAddr;
  907. + size_t vcMemSize;
  908. + uint8_t *mapAddr;
  909. + off_t vcMapAddr;
  910. +
  911. + if (!LookupVideoCoreSymbol(handle, symbol,
  912. + &vcMemAddr,
  913. + &vcMemSize)) {
  914. + loud_error_header();
  915. + loud_error(
  916. + "failed to find VC symbol \"%s\".",
  917. + symbol);
  918. + loud_error_footer();
  919. + return 0;
  920. + }
  921. +
  922. + if (vcMemSize != bufsize) {
  923. + loud_error_header();
  924. + loud_error(
  925. + "VC symbol \"%s\" is the wrong size.",
  926. + symbol);
  927. + loud_error_footer();
  928. + return 0;
  929. + }
  930. +
  931. + vcMapAddr = (off_t)vcMemAddr & VC_MEM_TO_ARM_ADDR_MASK;
  932. + vcMapAddr += mm_vc_mem_phys_addr;
  933. + mapAddr = ioremap_nocache(vcMapAddr, vcMemSize);
  934. + if (mapAddr == 0) {
  935. + loud_error_header();
  936. + loud_error(
  937. + "failed to ioremap \"%s\" @ 0x%x "
  938. + "(phys: 0x%x, size: %u).",
  939. + symbol,
  940. + (unsigned int)vcMapAddr,
  941. + (unsigned int)vcMemAddr,
  942. + (unsigned int)vcMemSize);
  943. + loud_error_footer();
  944. + return 0;
  945. + }
  946. +
  947. + memcpy(buf, mapAddr, bufsize);
  948. + iounmap(mapAddr);
  949. +
  950. + return 1;
  951. +}
  952. +
  953. +
  954. +static int
  955. +check_cma_config(void)
  956. +{
  957. + VC_MEM_ACCESS_HANDLE_T mem_hndl;
  958. + VC_MEM_ADDR_T mempool_start;
  959. + VC_MEM_ADDR_T mempool_end;
  960. + VC_MEM_ADDR_T mempool_offline_start;
  961. + VC_MEM_ADDR_T mempool_offline_end;
  962. + VC_MEM_ADDR_T cam_alloc_base;
  963. + VC_MEM_ADDR_T cam_alloc_size;
  964. + VC_MEM_ADDR_T cam_alloc_end;
  965. + int success = 0;
  966. +
  967. + if (OpenVideoCoreMemory(&mem_hndl) != 0)
  968. + goto out;
  969. +
  970. + /* Read the relevant VideoCore variables */
  971. + if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_START",
  972. + &mempool_start,
  973. + sizeof(mempool_start)))
  974. + goto close;
  975. +
  976. + if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_END",
  977. + &mempool_end,
  978. + sizeof(mempool_end)))
  979. + goto close;
  980. +
  981. + if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_START",
  982. + &mempool_offline_start,
  983. + sizeof(mempool_offline_start)))
  984. + goto close;
  985. +
  986. + if (!read_vc_debug_var(mem_hndl, "__MEMPOOL_OFFLINE_END",
  987. + &mempool_offline_end,
  988. + sizeof(mempool_offline_end)))
  989. + goto close;
  990. +
  991. + if (!read_vc_debug_var(mem_hndl, "cam_alloc_base",
  992. + &cam_alloc_base,
  993. + sizeof(cam_alloc_base)))
  994. + goto close;
  995. +
  996. + if (!read_vc_debug_var(mem_hndl, "cam_alloc_size",
  997. + &cam_alloc_size,
  998. + sizeof(cam_alloc_size)))
  999. + goto close;
  1000. +
  1001. + cam_alloc_end = cam_alloc_base + cam_alloc_size;
  1002. +
  1003. + success = 1;
  1004. +
  1005. + /* Now the sanity checks */
  1006. + if (!mempool_offline_start)
  1007. + mempool_offline_start = mempool_start;
  1008. + if (!mempool_offline_end)
  1009. + mempool_offline_end = mempool_end;
  1010. +
  1011. + if (VCADDR_TO_PHYSADDR(mempool_offline_start) != vc_cma_base) {
  1012. + loud_error_header();
  1013. + loud_error(
  1014. + "__MEMPOOL_OFFLINE_START(%x -> %lx) doesn't match "
  1015. + "vc_cma_base(%x)",
  1016. + mempool_offline_start,
  1017. + VCADDR_TO_PHYSADDR(mempool_offline_start),
  1018. + vc_cma_base);
  1019. + success = 0;
  1020. + }
  1021. +
  1022. + if (VCADDR_TO_PHYSADDR(mempool_offline_end) !=
  1023. + (vc_cma_base + vc_cma_size)) {
  1024. + loud_error_header();
  1025. + loud_error(
  1026. + "__MEMPOOL_OFFLINE_END(%x -> %lx) doesn't match "
  1027. + "vc_cma_base(%x) + vc_cma_size(%x) = %x",
  1028. + mempool_offline_start,
  1029. + VCADDR_TO_PHYSADDR(mempool_offline_end),
  1030. + vc_cma_base, vc_cma_size, vc_cma_base + vc_cma_size);
  1031. + success = 0;
  1032. + }
  1033. +
  1034. + if (mempool_end < mempool_start) {
  1035. + loud_error_header();
  1036. + loud_error(
  1037. + "__MEMPOOL_END(%x) must not be before "
  1038. + "__MEMPOOL_START(%x)",
  1039. + mempool_end,
  1040. + mempool_start);
  1041. + success = 0;
  1042. + }
  1043. +
  1044. + if (mempool_offline_end < mempool_offline_start) {
  1045. + loud_error_header();
  1046. + loud_error(
  1047. + "__MEMPOOL_OFFLINE_END(%x) must not be before "
  1048. + "__MEMPOOL_OFFLINE_START(%x)",
  1049. + mempool_offline_end,
  1050. + mempool_offline_start);
  1051. + success = 0;
  1052. + }
  1053. +
  1054. + if (mempool_offline_start < mempool_start) {
  1055. + loud_error_header();
  1056. + loud_error(
  1057. + "__MEMPOOL_OFFLINE_START(%x) must not be before "
  1058. + "__MEMPOOL_START(%x)",
  1059. + mempool_offline_start,
  1060. + mempool_start);
  1061. + success = 0;
  1062. + }
  1063. +
  1064. + if (mempool_offline_end > mempool_end) {
  1065. + loud_error_header();
  1066. + loud_error(
  1067. + "__MEMPOOL_OFFLINE_END(%x) must not be after "
  1068. + "__MEMPOOL_END(%x)",
  1069. + mempool_offline_end,
  1070. + mempool_end);
  1071. + success = 0;
  1072. + }
  1073. +
  1074. + if ((cam_alloc_base < mempool_end) &&
  1075. + (cam_alloc_end > mempool_start)) {
  1076. + loud_error_header();
  1077. + loud_error(
  1078. + "cam_alloc pool(%x-%x) overlaps "
  1079. + "mempool(%x-%x)",
  1080. + cam_alloc_base, cam_alloc_end,
  1081. + mempool_start, mempool_end);
  1082. + success = 0;
  1083. + }
  1084. +
  1085. + loud_error_footer();
  1086. +
  1087. +close:
  1088. + CloseVideoCoreMemory(mem_hndl);
  1089. +
  1090. +out:
  1091. + return success;
  1092. +}
  1093. +#endif
  1094. +
  1095. +static int vc_cma_init(void)
  1096. +{
  1097. + int rc = -EFAULT;
  1098. + struct device *dev;
  1099. +
  1100. + if (!check_cma_config())
  1101. + goto out_release;
  1102. +
  1103. + printk(KERN_INFO "vc-cma: Videocore CMA driver\n");
  1104. + printk(KERN_INFO "vc-cma: vc_cma_base = 0x%08x\n", vc_cma_base);
  1105. + printk(KERN_INFO "vc-cma: vc_cma_size = 0x%08x (%u MiB)\n",
  1106. + vc_cma_size, vc_cma_size / (1024 * 1024));
  1107. + printk(KERN_INFO "vc-cma: vc_cma_initial = 0x%08x (%u MiB)\n",
  1108. + vc_cma_initial, vc_cma_initial / (1024 * 1024));
  1109. +
  1110. + vc_cma_base_page = phys_to_page(vc_cma_base);
  1111. +
  1112. + if (vc_cma_chunks) {
  1113. + int chunks_needed = vc_cma_initial / VC_CMA_CHUNK_SIZE;
  1114. +
  1115. + for (vc_cma_chunks_used = 0;
  1116. + vc_cma_chunks_used < chunks_needed; vc_cma_chunks_used++) {
  1117. + struct page *chunk;
  1118. + chunk = dma_alloc_from_contiguous(NULL /*&vc_cma_device.dev*/,
  1119. + PAGES_PER_CHUNK,
  1120. + VC_CMA_CHUNK_ORDER);
  1121. + if (!chunk)
  1122. + break;
  1123. + BUG_ON(((page_to_phys(chunk) - vc_cma_base) %
  1124. + VC_CMA_CHUNK_SIZE) != 0);
  1125. + }
  1126. + if (vc_cma_chunks_used != chunks_needed) {
  1127. + LOG_ERR("%s: dma_alloc_from_contiguous failed (%d "
  1128. + "bytes, allocation %d of %d)",
  1129. + __func__, VC_CMA_CHUNK_SIZE,
  1130. + vc_cma_chunks_used, chunks_needed);
  1131. + goto out_release;
  1132. + }
  1133. +
  1134. + vchiq_add_connected_callback(vc_cma_connected_init);
  1135. + }
  1136. +
  1137. + rc = alloc_chrdev_region(&vc_cma_devnum, 0, 1, DRIVER_NAME);
  1138. + if (rc < 0) {
  1139. + LOG_ERR("%s: alloc_chrdev_region failed (rc=%d)", __func__, rc);
  1140. + goto out_release;
  1141. + }
  1142. +
  1143. + cdev_init(&vc_cma_cdev, &vc_cma_fops);
  1144. + rc = cdev_add(&vc_cma_cdev, vc_cma_devnum, 1);
  1145. + if (rc != 0) {
  1146. + LOG_ERR("%s: cdev_add failed (rc=%d)", __func__, rc);
  1147. + goto out_unregister;
  1148. + }
  1149. +
  1150. + vc_cma_class = class_create(THIS_MODULE, DRIVER_NAME);
  1151. + if (IS_ERR(vc_cma_class)) {
  1152. + rc = PTR_ERR(vc_cma_class);
  1153. + LOG_ERR("%s: class_create failed (rc=%d)", __func__, rc);
  1154. + goto out_cdev_del;
  1155. + }
  1156. +
  1157. + dev = device_create(vc_cma_class, NULL, vc_cma_devnum, NULL,
  1158. + DRIVER_NAME);
  1159. + if (IS_ERR(dev)) {
  1160. + rc = PTR_ERR(dev);
  1161. + LOG_ERR("%s: device_create failed (rc=%d)", __func__, rc);
  1162. + goto out_class_destroy;
  1163. + }
  1164. +
  1165. + vc_cma_proc_entry = proc_create(DRIVER_NAME, 0444, NULL, &vc_cma_proc_fops);
  1166. + if (vc_cma_proc_entry == NULL) {
  1167. + rc = -EFAULT;
  1168. + LOG_ERR("%s: proc_create failed", __func__);
  1169. + goto out_device_destroy;
  1170. + }
  1171. +
  1172. + vc_cma_inited = 1;
  1173. + return 0;
  1174. +
  1175. +out_device_destroy:
  1176. + device_destroy(vc_cma_class, vc_cma_devnum);
  1177. +
  1178. +out_class_destroy:
  1179. + class_destroy(vc_cma_class);
  1180. + vc_cma_class = NULL;
  1181. +
  1182. +out_cdev_del:
  1183. + cdev_del(&vc_cma_cdev);
  1184. +
  1185. +out_unregister:
  1186. + unregister_chrdev_region(vc_cma_devnum, 1);
  1187. +
  1188. +out_release:
  1189. + /* It is tempting to try to clean up by calling
  1190. + dma_release_from_contiguous for all allocated chunks, but it isn't
  1191. + a very safe thing to do. If vc_cma_initial is non-zero it is because
  1192. + VideoCore is already using that memory, so giving it back to Linux
  1193. + is likely to be fatal.
  1194. + */
  1195. + return -1;
  1196. +}
  1197. +
  1198. +/****************************************************************************
  1199. +*
  1200. +* vc_cma_exit
  1201. +*
  1202. +***************************************************************************/
  1203. +
  1204. +static void __exit vc_cma_exit(void)
  1205. +{
  1206. + LOG_DBG("%s: called", __func__);
  1207. +
  1208. + if (vc_cma_inited) {
  1209. + remove_proc_entry(DRIVER_NAME, NULL);
  1210. + device_destroy(vc_cma_class, vc_cma_devnum);
  1211. + class_destroy(vc_cma_class);
  1212. + cdev_del(&vc_cma_cdev);
  1213. + unregister_chrdev_region(vc_cma_devnum, 1);
  1214. + }
  1215. +}
  1216. +
  1217. +module_init(vc_cma_init);
  1218. +module_exit(vc_cma_exit);
  1219. +MODULE_LICENSE("GPL");
  1220. +MODULE_AUTHOR("Broadcom Corporation");
  1221. --- a/drivers/misc/Makefile
  1222. +++ b/drivers/misc/Makefile
  1223. @@ -51,7 +51,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/
  1224. obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
  1225. obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
  1226. obj-$(CONFIG_SRAM) += sram.o
  1227. -obj-y += vc04_services/
  1228. +obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/
  1229. obj-y += mic/
  1230. obj-$(CONFIG_GENWQE) += genwqe/
  1231. obj-$(CONFIG_ECHO) += echo/
  1232. --- /dev/null
  1233. +++ b/include/linux/broadcom/vc_cma.h
  1234. @@ -0,0 +1,29 @@
  1235. +/*****************************************************************************
  1236. +* Copyright 2012 Broadcom Corporation. All rights reserved.
  1237. +*
  1238. +* Unless you and Broadcom execute a separate written software license
  1239. +* agreement governing use of this software, this software is licensed to you
  1240. +* under the terms of the GNU General Public License version 2, available at
  1241. +* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
  1242. +*
  1243. +* Notwithstanding the above, under no circumstances may you combine this
  1244. +* software in any way with any other Broadcom software provided under a
  1245. +* license other than the GPL, without Broadcom's express prior written
  1246. +* consent.
  1247. +*****************************************************************************/
  1248. +
  1249. +#if !defined( VC_CMA_H )
  1250. +#define VC_CMA_H
  1251. +
  1252. +#include <linux/ioctl.h>
  1253. +
  1254. +#define VC_CMA_IOC_MAGIC 0xc5
  1255. +
  1256. +#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0)
  1257. +
  1258. +#ifdef __KERNEL__
  1259. +extern void __init vc_cma_early_init(void);
  1260. +extern void __init vc_cma_reserve(void);
  1261. +#endif
  1262. +
  1263. +#endif /* VC_CMA_H */