cmdq_driver.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. #include "cmdq_driver.h"
  2. #include "cmdq_struct.h"
  3. #include "cmdq_core.h"
  4. #include "cmdq_mutex.h"
  5. #include "cmdq_reg.h"
  6. #include "cmdq_mdp.h"
  7. #include "cmdq_device.h"
  8. #include "cmdq_platform.h"
  9. #ifdef CMDQ_SECURE_PATH_SUPPORT
  10. #include "cmdq_sec.h"
  11. #endif
  12. /* #include "camera_isp.h" */
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/pm.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/seq_file.h>
  19. #include <linux/fs.h>
  20. #include <linux/cdev.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/uaccess.h>
  23. #include <linux/errno.h>
  24. #include <linux/slab.h>
  25. #include <linux/spinlock.h>
  26. #include <linux/sched.h>
  27. #include <linux/pm.h>
  28. #include <linux/suspend.h>
  29. #ifdef CONFIG_HAS_EARLYSUSPEND
  30. #include <linux/earlysuspend.h>
  31. #endif
  32. /* #include <mach/mt_irq.h> */
  33. #ifdef CONFIG_HAS_SBSUSPEND
  34. #include <linux/sbsuspend.h>
  35. #endif
  36. #ifdef CMDQ_OF_SUPPORT
  37. /**
  38. * @device tree porting note
  39. * alps/kernel-3.10/arch/arm64/boot/dts/{platform}.dts
  40. * - use of_device_id to match driver and device
  41. * - use io_map to map and get VA of HW's rgister
  42. **/
  43. static const struct of_device_id cmdq_of_ids[] = {
  44. {.compatible = "mediatek,mt8173-gce",},
  45. {.compatible = "mediatek,mt8163-gce",},
  46. {}
  47. };
  48. #endif
  49. static dev_t gCmdqDevNo;
  50. static struct cdev *gCmdqCDev;
  51. static struct class *gCMDQClass;
  52. static ssize_t cmdq_driver_dummy_write(struct device *dev,
  53. struct device_attribute *attr, const char *buf, size_t size)
  54. {
  55. return -EACCES;
  56. }
  57. static DEVICE_ATTR(status, S_IRUSR | S_IWUSR, cmdqCorePrintStatus, cmdq_driver_dummy_write);
  58. static DEVICE_ATTR(error, S_IRUSR | S_IWUSR, cmdqCorePrintError, cmdq_driver_dummy_write);
  59. static DEVICE_ATTR(record, S_IRUSR | S_IWUSR, cmdqCorePrintRecord, cmdq_driver_dummy_write);
  60. static DEVICE_ATTR(log_level, S_IRUSR | S_IWUSR, cmdqCorePrintLogLevel, cmdqCoreWriteLogLevel);
  61. static DEVICE_ATTR(profile_enable, S_IRUSR | S_IWUSR, cmdqCorePrintProfileEnable,
  62. cmdqCoreWriteProfileEnable);
  63. static int cmdq_proc_status_open(struct inode *inode, struct file *file)
  64. {
  65. return single_open(file, cmdqCorePrintStatusSeq, inode->i_private);
  66. }
  67. static int cmdq_proc_error_open(struct inode *inode, struct file *file)
  68. {
  69. return single_open(file, cmdqCorePrintErrorSeq, inode->i_private);
  70. }
  71. static int cmdq_proc_record_open(struct inode *inode, struct file *file)
  72. {
  73. return single_open(file, cmdqCorePrintRecordSeq, inode->i_private);
  74. }
  75. static const struct file_operations cmdqDebugStatusOp = {
  76. .owner = THIS_MODULE,
  77. .open = cmdq_proc_status_open,
  78. .read = seq_read,
  79. .llseek = seq_lseek,
  80. .release = single_release,
  81. };
  82. static const struct file_operations cmdqDebugErrorOp = {
  83. .owner = THIS_MODULE,
  84. .open = cmdq_proc_error_open,
  85. .read = seq_read,
  86. .llseek = seq_lseek,
  87. .release = single_release,
  88. };
  89. static const struct file_operations cmdqDebugRecordOp = {
  90. .owner = THIS_MODULE,
  91. .open = cmdq_proc_record_open,
  92. .read = seq_read,
  93. .llseek = seq_lseek,
  94. .release = single_release,
  95. };
  96. static const struct file_operations cmdqDebugLevelOp = {
  97. .owner = THIS_MODULE,
  98. .read = cmdq_read_debug_level_proc,
  99. .write = cmdq_write_debug_level_proc
  100. };
  101. static int cmdq_open(struct inode *pInode, struct file *pFile)
  102. {
  103. struct cmdqFileNodeStruct *pNode;
  104. CMDQ_VERBOSE("CMDQ driver open fd=%p begin\n", pFile);
  105. pFile->private_data = kzalloc(sizeof(struct cmdqFileNodeStruct), GFP_KERNEL);
  106. if (NULL == pFile->private_data) {
  107. CMDQ_ERR("Can't allocate memory for CMDQ file node\n");
  108. return -ENOMEM;
  109. }
  110. pNode = (struct cmdqFileNodeStruct *)pFile->private_data;
  111. pNode->userPID = current->pid;
  112. pNode->userTGID = current->tgid;
  113. INIT_LIST_HEAD(&(pNode->taskList));
  114. pNode->mutexFlag = 0;
  115. spin_lock_init(&pNode->nodeLock);
  116. CMDQ_VERBOSE("CMDQ driver open end\n");
  117. return 0;
  118. }
  119. static int cmdq_release(struct inode *pInode, struct file *pFile)
  120. {
  121. struct cmdqFileNodeStruct *pNode;
  122. unsigned long flags;
  123. int32_t index;
  124. CMDQ_VERBOSE("CMDQ driver release fd=%p begin\n", pFile);
  125. pNode = (struct cmdqFileNodeStruct *)pFile->private_data;
  126. if (NULL == pNode) {
  127. CMDQ_ERR("CMDQ file node NULL\n");
  128. return -EFAULT;
  129. }
  130. spin_lock_irqsave(&pNode->nodeLock, flags);
  131. if (pNode->mutexFlag) {
  132. for (index = DISP_MUTEX_MDP_FIRST;
  133. index < DISP_MUTEX_MDP_FIRST + DISP_MUTEX_MDP_COUNT; index++) {
  134. if ((1 << index) & pNode->mutexFlag)
  135. cmdqMutexRelease(index);
  136. }
  137. pNode->mutexFlag = 0;
  138. }
  139. /* note that we did not release CMDQ tasks */
  140. /* issued by this file node, */
  141. /* since their HW operation may be pending. */
  142. spin_unlock_irqrestore(&pNode->nodeLock, flags);
  143. /* scan through tasks that created by this file node and release them */
  144. cmdq_core_release_task_by_file_node((void *)pNode);
  145. if (NULL != pFile->private_data) {
  146. kfree(pFile->private_data);
  147. pFile->private_data = NULL;
  148. }
  149. CMDQ_VERBOSE("CMDQ driver release end\n");
  150. return 0;
  151. }
  152. static int cmdq_driver_create_reg_address_buffer(struct cmdqCommandStruct *pCommand)
  153. {
  154. int status = 0;
  155. uint32_t totalRegCount = 0;
  156. uint32_t *regAddrBuf = NULL;
  157. uint32_t *kernelRegAddr = NULL;
  158. uint32_t kernelRegCount = 0;
  159. const uint32_t userRegCount = pCommand->regRequest.count;
  160. if (0 != pCommand->debugRegDump) {
  161. /* get kernel dump request count */
  162. status = cmdqCoreDebugRegDumpBegin(pCommand->debugRegDump,
  163. &kernelRegCount, &kernelRegAddr);
  164. if (0 != status) {
  165. CMDQ_ERR
  166. ("cmdqCoreDebugRegDumpBegin returns %d, ignore kernel reg dump request\n",
  167. status);
  168. kernelRegCount = 0;
  169. kernelRegAddr = NULL;
  170. }
  171. }
  172. /* how many register to dump? */
  173. totalRegCount = kernelRegCount + userRegCount;
  174. if (0 == totalRegCount) {
  175. /* no need to dump register */
  176. pCommand->regRequest.count = 0;
  177. pCommand->regValue.count = 0;
  178. pCommand->regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)NULL;
  179. pCommand->regValue.regValues = (cmdqU32Ptr_t) (unsigned long)NULL;
  180. } else {
  181. regAddrBuf = kcalloc(totalRegCount, sizeof(uint32_t), GFP_KERNEL);
  182. if (NULL == regAddrBuf)
  183. return -ENOMEM;
  184. /* collect user space dump request */
  185. if (userRegCount) {
  186. if (copy_from_user
  187. (regAddrBuf, CMDQ_U32_PTR(pCommand->regRequest.regAddresses),
  188. userRegCount * sizeof(uint32_t))) {
  189. kfree(regAddrBuf);
  190. return -EFAULT;
  191. }
  192. }
  193. /* collect kernel space dump request, concatnate after user space request */
  194. if (kernelRegCount) {
  195. memcpy(regAddrBuf + userRegCount, kernelRegAddr,
  196. kernelRegCount * sizeof(uint32_t));
  197. }
  198. /* replace address buffer and value address buffer with kzalloc memory */
  199. pCommand->regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)(regAddrBuf);
  200. pCommand->regRequest.count = totalRegCount;
  201. }
  202. return 0;
  203. }
  204. static void cmdq_driver_process_read_address_request(struct cmdqReadAddressStruct *req_user)
  205. {
  206. /* create kernel-space buffer for working */
  207. uint32_t *addrs = NULL;
  208. uint32_t *values = NULL;
  209. dma_addr_t pa = 0;
  210. int i = 0;
  211. CMDQ_LOG("[READ_PA] cmdq_driver_process_read_address_request()\n");
  212. do {
  213. if (NULL == req_user ||
  214. 0 == req_user->count || NULL == CMDQ_U32_PTR(req_user->values)
  215. || NULL == CMDQ_U32_PTR(req_user->dmaAddresses)) {
  216. CMDQ_ERR("[READ_PA] invalid req_user\n");
  217. break;
  218. }
  219. addrs = kcalloc(req_user->count, sizeof(uint32_t), GFP_KERNEL);
  220. if (NULL == addrs) {
  221. CMDQ_ERR("[READ_PA] fail to alloc addr buf\n");
  222. break;
  223. }
  224. values = kcalloc(req_user->count, sizeof(uint32_t), GFP_KERNEL);
  225. if (NULL == values) {
  226. CMDQ_ERR("[READ_PA] fail to alloc value buf\n");
  227. break;
  228. }
  229. /* copy from user */
  230. if (copy_from_user
  231. (addrs, CMDQ_U32_PTR(req_user->dmaAddresses),
  232. req_user->count * sizeof(uint32_t))) {
  233. CMDQ_ERR("[READ_PA] fail to copy user dmaAddresses\n");
  234. break;
  235. }
  236. /* actually read these PA write buffers */
  237. for (i = 0; i < req_user->count; ++i) {
  238. pa = (0xFFFFFFFF & addrs[i]);
  239. CMDQ_LOG("[READ_PA] req read dma address 0x%pa\n", &pa);
  240. values[i] = cmdqCoreReadWriteAddress(pa);
  241. }
  242. /* copy value to user */
  243. if (copy_to_user
  244. (CMDQ_U32_PTR(req_user->values), values, req_user->count * sizeof(uint32_t))) {
  245. CMDQ_ERR("[READ_PA] fail to copy to user value buf\n");
  246. break;
  247. }
  248. } while (0);
  249. kfree(addrs);
  250. kfree(values);
  251. }
  252. static long cmdq_driver_destroy_secure_medadata(struct cmdqCommandStruct *pCommand)
  253. {
  254. if (pCommand->secData.addrMetadatas) {
  255. kfree(CMDQ_U32_PTR(pCommand->secData.addrMetadatas));
  256. pCommand->secData.addrMetadatas = (cmdqU32Ptr_t) (unsigned long)NULL;
  257. }
  258. return 0;
  259. }
  260. static long cmdq_driver_create_secure_medadata(struct cmdqCommandStruct *pCommand)
  261. {
  262. void *pAddrMetadatas = NULL;
  263. const uint32_t length =
  264. (pCommand->secData.addrMetadataCount) * sizeof(cmdqSecAddrMetadataStruct);
  265. /* verify parameter */
  266. if ((false == pCommand->secData.isSecure) && (0 != pCommand->secData.addrMetadataCount)) {
  267. /* normal path with non-zero secure metadata */
  268. CMDQ_ERR
  269. ("[secData]mismatch secData.isSecure(%d) and secData.addrMetadataCount(%d)\n",
  270. pCommand->secData.isSecure, pCommand->secData.addrMetadataCount);
  271. return -EFAULT;
  272. }
  273. /* revise max count field */
  274. pCommand->secData.addrMetadataMaxCount = pCommand->secData.addrMetadataCount;
  275. /* bypass 0 metadata case */
  276. if (0 == pCommand->secData.addrMetadataCount) {
  277. pCommand->secData.addrMetadatas = (cmdqU32Ptr_t) (unsigned long)NULL;
  278. return 0;
  279. }
  280. /* create kernel-space buffer for working */
  281. pAddrMetadatas = kzalloc(length, GFP_KERNEL);
  282. if (NULL == pAddrMetadatas) {
  283. CMDQ_ERR("[secData]kzalloc for addrMetadatas failed, count:%d, alloacted_size:%d\n",
  284. pCommand->secData.addrMetadataCount, length);
  285. return -ENOMEM;
  286. }
  287. /* copy from user */
  288. if (copy_from_user(pAddrMetadatas, CMDQ_U32_PTR(pCommand->secData.addrMetadatas), length)) {
  289. CMDQ_ERR("[secData]fail to copy user addrMetadatas\n");
  290. /* replace buffer first to ensure that */
  291. /* addrMetadatas is valid kernel space buffer address when free it */
  292. pCommand->secData.addrMetadatas = (cmdqU32Ptr_t) (unsigned long)pAddrMetadatas;
  293. /* free secure path metadata */
  294. cmdq_driver_destroy_secure_medadata(pCommand);
  295. return -EFAULT;
  296. }
  297. /* replace buffer */
  298. pCommand->secData.addrMetadatas = (cmdqU32Ptr_t) (unsigned long)pAddrMetadatas;
  299. return 0;
  300. }
  301. static long cmdq_driver_process_command_request(struct cmdqCommandStruct *pCommand)
  302. {
  303. int32_t status = 0;
  304. uint32_t *userRegValue = NULL;
  305. uint32_t userRegCount = 0;
  306. if (pCommand->regRequest.count != pCommand->regValue.count) {
  307. CMDQ_ERR("mismatch regRequest and regValue\n");
  308. return -EFAULT;
  309. }
  310. /* allocate secure medatata */
  311. status = cmdq_driver_create_secure_medadata(pCommand);
  312. if (0 != status)
  313. return status;
  314. /* backup since we are going to replace these */
  315. userRegValue = CMDQ_U32_PTR(pCommand->regValue.regValues);
  316. userRegCount = pCommand->regValue.count;
  317. /* create kernel-space address buffer */
  318. status = cmdq_driver_create_reg_address_buffer(pCommand);
  319. if (0 != status) {
  320. /* free secure path metadata */
  321. cmdq_driver_destroy_secure_medadata(pCommand);
  322. return status;
  323. }
  324. /* create kernel-space value buffer */
  325. pCommand->regValue.regValues = (cmdqU32Ptr_t) (unsigned long)
  326. kzalloc(pCommand->regRequest.count * sizeof(uint32_t), GFP_KERNEL);
  327. pCommand->regValue.count = pCommand->regRequest.count;
  328. if (NULL == CMDQ_U32_PTR(pCommand->regValue.regValues)) {
  329. kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses));
  330. return -ENOMEM;
  331. }
  332. /* scenario id fixup */
  333. if ((CMDQ_SCENARIO_USER_DISP_COLOR == pCommand->scenario)
  334. || (CMDQ_SCENARIO_USER_MDP == pCommand->scenario)) {
  335. CMDQ_VERBOSE("user space request, scenario:%d\n", pCommand->scenario);
  336. } else {
  337. CMDQ_LOG("[WARNING]fix user space request to CMDQ_SCENARIO_USER_SPACE\n");
  338. pCommand->scenario = CMDQ_SCENARIO_USER_SPACE;
  339. }
  340. if (CMDQ_SCENARIO_USER_MDP == pCommand->scenario)
  341. CMDQ_MSG("srcHandle=0x%08x, dstHandle=0x%08x\n",
  342. pCommand->secData.srcHandle, pCommand->secData.dstHandle);
  343. status = cmdqCoreSubmitTask(pCommand);
  344. if (0 > status) {
  345. CMDQ_ERR("Submit user commands for execution failed = %d\n", status);
  346. cmdq_driver_destroy_secure_medadata(pCommand);
  347. kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses));
  348. kfree(CMDQ_U32_PTR(pCommand->regValue.regValues));
  349. return -EFAULT;
  350. }
  351. /* notify kernel space dump callback */
  352. if (0 != pCommand->debugRegDump) {
  353. status = cmdqCoreDebugRegDumpEnd(pCommand->debugRegDump,
  354. pCommand->regRequest.count - userRegCount,
  355. CMDQ_U32_PTR(pCommand->regValue.regValues) +
  356. userRegCount);
  357. if (0 != status)
  358. CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status);
  359. }
  360. /* copy back to user space buffer */
  361. if (userRegValue && userRegCount) {
  362. /* copy results back to user space */
  363. CMDQ_VERBOSE("regValue[0] is %d\n", CMDQ_U32_PTR(pCommand->regValue.regValues)[0]);
  364. if (copy_to_user
  365. (userRegValue, CMDQ_U32_PTR(pCommand->regValue.regValues),
  366. userRegCount * sizeof(uint32_t))) {
  367. CMDQ_ERR("Copy REGVALUE to user space failed\n");
  368. }
  369. }
  370. /* free allocated kernel buffers */
  371. kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses));
  372. kfree(CMDQ_U32_PTR(pCommand->regValue.regValues));
  373. if (pCommand->readAddress.count > 0)
  374. cmdq_driver_process_read_address_request(&pCommand->readAddress);
  375. /* free allocated secure metadata */
  376. cmdq_driver_destroy_secure_medadata(pCommand);
  377. return 0;
  378. }
  379. static long cmdq_ioctl(struct file *pFile, unsigned int code, unsigned long param)
  380. {
  381. int mutex;
  382. struct cmdqCommandStruct command;
  383. struct cmdqJobStruct job;
  384. struct cmdqFileNodeStruct *pNode;
  385. unsigned long flags;
  386. int count[CMDQ_MAX_ENGINE_COUNT];
  387. struct TaskStruct *pTask;
  388. int32_t status;
  389. struct cmdqJobResultStruct jobResult;
  390. uint32_t *userRegValue = NULL;
  391. uint32_t userRegCount = 0;
  392. /* backup value after task release */
  393. uint32_t regCount = 0, regCountUserSpace = 0, regUserToken = 0;
  394. switch (code) {
  395. case CMDQ_IOCTL_LOCK_MUTEX:
  396. mutex = cmdqMutexAcquire();
  397. if (-1 == mutex)
  398. return -IOCTL_RET_LOCK_MUTEX_FAIL;
  399. if (copy_to_user((void *)param, &mutex, sizeof(int))) {
  400. CMDQ_ERR("Copy mutex number to user failed\n");
  401. cmdqMutexRelease(mutex);
  402. return -IOCTL_RET_COPY_MUTEX_NUM_TO_USER_FAIL;
  403. }
  404. /* register mutex into file node data */
  405. pNode = (struct cmdqFileNodeStruct *)pFile->private_data;
  406. if (pNode) {
  407. spin_lock_irqsave(&pNode->nodeLock, flags);
  408. pNode->mutexFlag |= (1 << mutex);
  409. spin_unlock_irqrestore(&pNode->nodeLock, flags);
  410. }
  411. break;
  412. case CMDQ_IOCTL_UNLOCK_MUTEX:
  413. if (copy_from_user(&mutex, (void *)param, sizeof(int))) {
  414. CMDQ_ERR("Copy mutex number from user failed\n");
  415. return -IOCLT_RET_COPY_MUTEX_NUM_FROM_USER_FAIL;
  416. }
  417. status = cmdqMutexRelease(mutex);
  418. if (status < 0)
  419. return -IOCTL_RET_RELEASE_MUTEX_FAIL;
  420. if (-1 != mutex) {
  421. pNode = (struct cmdqFileNodeStruct *)pFile->private_data;
  422. spin_lock_irqsave(&pNode->nodeLock, flags);
  423. pNode->mutexFlag &= ~(1 << mutex);
  424. spin_unlock_irqrestore(&pNode->nodeLock, flags);
  425. }
  426. break;
  427. case CMDQ_IOCTL_EXEC_COMMAND:
  428. if (copy_from_user(&command, (void *)param, sizeof(struct cmdqCommandStruct)))
  429. return -IOCTL_RET_COPY_EXEC_CMD_FROM_USER_FAIL;
  430. if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == command.scenario))
  431. return -IOCTL_RET_IS_SUSPEND_WHEN_EXEC_CMD;
  432. /* insert private_data for resource reclaim */
  433. command.privateData = (cmdqU32Ptr_t) pFile->private_data;
  434. if (cmdq_driver_process_command_request(&command))
  435. return -IOCTL_RET_PROCESS_CMD_REQUEST_FAIL;
  436. break;
  437. case CMDQ_IOCTL_QUERY_USAGE:
  438. if (cmdqCoreQueryUsage(count))
  439. return -IOCLT_RET_QUERY_USAGE_FAIL;
  440. if (copy_to_user((void *)param, count, sizeof(int32_t) * CMDQ_MAX_ENGINE_COUNT)) {
  441. CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE copy_to_user failed\n");
  442. return -IOCTL_RET_COPY_USAGE_TO_USER_FAIL;
  443. }
  444. break;
  445. case CMDQ_IOCTL_ASYNC_JOB_EXEC:
  446. if (copy_from_user(&job, (void *)param, sizeof(struct cmdqJobStruct)))
  447. return -IOCTL_RET_COPY_ASYNC_JOB_EXEC_FROM_USER_FAIL;
  448. if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) {
  449. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC suspended, return\n");
  450. return -IOCTL_RET_IS_SUSPEND_WHEN_ASYNC_JOB_EXEC;
  451. }
  452. /* not support secure path for async ioctl yet */
  453. if (true == job.command.secData.isSecure) {
  454. CMDQ_ERR("not support secure path for CMDQ_IOCTL_ASYNC_JOB_EXEC\n");
  455. return -IOCTL_RET_NOT_SUPPORT_SEC_PATH_FOR_ASYNC_JOB_EXEC;
  456. }
  457. /* backup */
  458. userRegCount = job.command.regRequest.count;
  459. /* insert private_data for resource reclaim */
  460. job.command.privateData = (cmdqU32Ptr_t) (unsigned long)(pFile->private_data);
  461. /* create kernel-space address buffer */
  462. status = cmdq_driver_create_reg_address_buffer(&job.command);
  463. if (0 != status)
  464. return -IOCTL_RET_CREATE_REG_ADDR_BUF_FAIL;
  465. /* scenario id fixup */
  466. if ((CMDQ_SCENARIO_USER_DISP_COLOR == job.command.scenario)
  467. || (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) {
  468. CMDQ_VERBOSE("user space request, scenario:%d\n", job.command.scenario);
  469. } else {
  470. CMDQ_LOG("[WARNING]fix user space request to CMDQ_SCENARIO_USER_SPACE\n");
  471. job.command.scenario = CMDQ_SCENARIO_USER_SPACE;
  472. }
  473. status = cmdqCoreSubmitTaskAsync(&job.command, NULL, 0, &pTask);
  474. /* store user space request count in struct TaskStruct */
  475. /* for later retrieval */
  476. if (pTask) {
  477. pTask->regCountUserSpace = userRegCount;
  478. pTask->regUserToken = job.command.debugRegDump;
  479. }
  480. /* we don't need regAddress anymore, free it now */
  481. kfree(CMDQ_U32_PTR(job.command.regRequest.regAddresses));
  482. job.command.regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)(NULL);
  483. if (status >= 0) {
  484. job.hJob = (unsigned long)pTask;
  485. if (copy_to_user((void *)param, (void *)&job, sizeof(struct cmdqJobStruct))) {
  486. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC copy_to_user failed\n");
  487. return -IOCLT_RET_COPY_ASYNC_JOB_EXEC_TO_USER_FAIL;
  488. }
  489. } else {
  490. job.hJob = (unsigned long)NULL;
  491. return -IOCTL_RET_SUBMIT_TASK_ASYNC_FAILED;
  492. }
  493. break;
  494. case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE:
  495. if (copy_from_user(&jobResult, (void *)param, sizeof(jobResult))) {
  496. CMDQ_ERR("copy_from_user jobResult fail\n");
  497. return -IOCTL_RET_COPY_ASYNC_JOB_WAIT_AND_CLOSE_FROM_USER_FAIL;
  498. }
  499. if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) {
  500. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE suspended, return\n");
  501. return -IOCTL_RET_IS_SUSPEND_WHEN_ASYNC_JOB_WAIT_AND_CLOSE;
  502. }
  503. /* verify job handle */
  504. if (!cmdqIsValidTaskPtr((struct TaskStruct *)(unsigned long)jobResult.hJob)) {
  505. CMDQ_ERR("invalid task ptr = 0x%llx\n", jobResult.hJob);
  506. return -IOCTL_RET_INVALID_TASK_PTR;
  507. }
  508. pTask = (struct TaskStruct *)(unsigned long)jobResult.hJob;
  509. /* utility service, fill the engine flag. */
  510. /* this is required by MDP. */
  511. jobResult.engineFlag = pTask->engineFlag;
  512. /* check if reg buffer suffices */
  513. if (jobResult.regValue.count < pTask->regCountUserSpace) {
  514. jobResult.regValue.count = pTask->regCountUserSpace;
  515. if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) {
  516. CMDQ_ERR("copy_to_user fail, line=%d\n", __LINE__);
  517. return -IOCTL_RET_COPY_JOB_RESULT_TO_USER1_FAIL;
  518. }
  519. CMDQ_ERR("insufficient register buffer\n");
  520. return -IOCTL_RET_NOT_ENOUGH_REGISTER_BUFFER;
  521. }
  522. /* inform client the actual read register count */
  523. jobResult.regValue.count = pTask->regCountUserSpace;
  524. /* update user space before we replace the regValues pointer. */
  525. if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) {
  526. CMDQ_ERR("copy_to_user fail line=%d\n", __LINE__);
  527. return -IOCTL_RET_COPY_JOB_RESULT_TO_USER2_FAIL;
  528. }
  529. /* allocate kernel space result buffer */
  530. /* which contains kernel + user space requests */
  531. userRegValue = CMDQ_U32_PTR(jobResult.regValue.regValues);
  532. jobResult.regValue.regValues =
  533. (cmdqU32Ptr_t) (unsigned
  534. long)(kzalloc(pTask->regCount * sizeof(uint32_t), GFP_KERNEL));
  535. jobResult.regValue.count = pTask->regCount;
  536. if (NULL == CMDQ_U32_PTR(jobResult.regValue.regValues)) {
  537. CMDQ_ERR("no reg value buffer\n");
  538. return -IOCTL_RET_NO_REG_VAL_BUFFER;
  539. }
  540. /* backup value after task release */
  541. regCount = pTask->regCount;
  542. regCountUserSpace = pTask->regCountUserSpace;
  543. regUserToken = pTask->regUserToken;
  544. /* make sure the task is running and wait for it */
  545. status = cmdqCoreWaitResultAndReleaseTask(pTask,
  546. &jobResult.regValue,
  547. msecs_to_jiffies
  548. (CMDQ_DEFAULT_TIMEOUT_MS));
  549. if (status < 0) {
  550. CMDQ_ERR("waitResultAndReleaseTask fail=%d\n", status);
  551. /* free kernel space result buffer */
  552. kfree(CMDQ_U32_PTR(jobResult.regValue.regValues));
  553. return -IOCTL_RET_WAIT_RESULT_AND_RELEASE_TASK_FAIL;
  554. }
  555. /* pTask is released, do not access it any more */
  556. pTask = NULL;
  557. /* notify kernel space dump callback */
  558. if (regCount > regCountUserSpace) {
  559. CMDQ_VERBOSE("kernel space reg dump = %d, %d, %d\n", regCount,
  560. regCountUserSpace, regUserToken);
  561. status = cmdqCoreDebugRegDumpEnd(regUserToken,
  562. regCount - regCountUserSpace,
  563. CMDQ_U32_PTR(jobResult.regValue.regValues +
  564. regCountUserSpace));
  565. if (0 != status)
  566. CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status);
  567. }
  568. /* copy result to user space */
  569. if (copy_to_user
  570. ((void *)userRegValue, (void *)(unsigned long)jobResult.regValue.regValues,
  571. regCountUserSpace * sizeof(uint32_t))) {
  572. CMDQ_ERR("Copy REGVALUE to user space failed\n");
  573. return -IOCLT_RET_COPY_REG_VALUE_TO_USER_FAIL;
  574. }
  575. if (jobResult.readAddress.count > 0)
  576. cmdq_driver_process_read_address_request(&jobResult.readAddress);
  577. /* free kernel space result buffer */
  578. kfree(CMDQ_U32_PTR(jobResult.regValue.regValues));
  579. break;
  580. case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS:
  581. do {
  582. struct cmdqWriteAddressStruct addrReq;
  583. dma_addr_t paStart = 0;
  584. CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS\n");
  585. if (copy_from_user(&addrReq, (void *)param, sizeof(addrReq))) {
  586. CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_from_user failed\n");
  587. return -IOCTL_RET_COPY_ALLOC_WRITE_ADDR_FROM_USER_FAIL;
  588. }
  589. status = cmdqCoreAllocWriteAddress(addrReq.count, &paStart);
  590. if (0 != status) {
  591. CMDQ_ERR
  592. ("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS cmdqCoreAllocWriteAddress() failed\n");
  593. return -IOCTL_RET_ALLOC_WRITE_ADDR_FAIL;
  594. }
  595. addrReq.startPA = (uint32_t) paStart;
  596. CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS get 0x%08x\n", addrReq.startPA);
  597. if (copy_to_user((void *)param, &addrReq, sizeof(addrReq))) {
  598. CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_to_user failed\n");
  599. return -IOCTL_RET_COPY_ALLOC_WRITE_ADDR_TO_USER_FAIL;
  600. }
  601. status = 0;
  602. } while (0);
  603. break;
  604. case CMDQ_IOCTL_FREE_WRITE_ADDRESS:
  605. do {
  606. struct cmdqWriteAddressStruct freeReq;
  607. CMDQ_LOG("CMDQ_IOCTL_FREE_WRITE_ADDRESS\n");
  608. if (copy_from_user(&freeReq, (void *)param, sizeof(freeReq))) {
  609. CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS copy_from_user failed\n");
  610. return -IOCTL_RET_COPY_FREE_WRITE_ADDR_FROM_USER_FAIL;
  611. }
  612. status = cmdqCoreFreeWriteAddress(freeReq.startPA);
  613. if (0 != status)
  614. return -IOCTL_RET_FREE_WRITE_ADDR_FAIL;
  615. status = 0;
  616. } while (0);
  617. break;
  618. case CMDQ_IOCTL_READ_ADDRESS_VALUE:
  619. do {
  620. struct cmdqReadAddressStruct readReq;
  621. CMDQ_LOG("CMDQ_IOCTL_READ_ADDRESS_VALUE\n");
  622. if (copy_from_user(&readReq, (void *)param, sizeof(readReq))) {
  623. CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE copy_from_user failed\n");
  624. return -IOCTL_RET_COPY_READ_ADDR_VAL_FROM_USER_FAIL;
  625. }
  626. /* this will copy result to readReq->values buffer */
  627. cmdq_driver_process_read_address_request(&readReq);
  628. status = 0;
  629. } while (0);
  630. break;
  631. case CMDQ_IOCTL_QUERY_CAP_BITS:
  632. do {
  633. int capBits = 0;
  634. if (cmdq_core_support_wait_and_receive_event_in_same_tick())
  635. capBits |= (1L << CMDQ_CAP_WFE);
  636. else
  637. capBits &= ~(1L << CMDQ_CAP_WFE);
  638. if (copy_to_user((void *)param, &capBits, sizeof(int))) {
  639. CMDQ_ERR("Copy capacity bits to user space failed\n");
  640. return -IOCTL_RET_COPY_CAP_BITS_TO_USER_FAIL;
  641. }
  642. } while (0);
  643. break;
  644. case CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION:
  645. #ifdef CMDQ_SECURE_PATH_SUPPORT
  646. do {
  647. struct cmdqSyncHandleHdcpStruct syncHandle;
  648. if (copy_from_user(&syncHandle, (void *)param, sizeof(syncHandle))) {
  649. CMDQ_ERR
  650. ("CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION copy_from_user failed\n");
  651. return -IOCTL_RET_COPY_HDCP_VERSION_FROM_USER_FAIL;
  652. }
  653. status = cmdq_sec_sync_handle_hdcp_unlock(syncHandle);
  654. if (0 != status)
  655. CMDQ_ERR("cmdq_sec_sync_handle_hdcp_unlock returns %d\n", status);
  656. } while (0);
  657. #else
  658. CMDQ_ERR("SVP not supported\n");
  659. return -IOCTL_RET_SVP_NOT_SUPPORT;
  660. #endif
  661. break;
  662. default:
  663. CMDQ_ERR("unrecognized ioctl 0x%08x\n", code);
  664. CMDQ_ERR("CMDQ_IOCTL_LOCK_MUTEX:0x%08lx sizeof(int) = %ld\n",
  665. CMDQ_IOCTL_LOCK_MUTEX, sizeof(int));
  666. CMDQ_ERR("CMDQ_IOCTL_UNLOCK_MUTEX:0x%08lx sizeof(int) = %ld\n",
  667. CMDQ_IOCTL_UNLOCK_MUTEX, sizeof(int));
  668. CMDQ_ERR("CMDQ_IOCTL_EXEC_COMMAND:0x%08lx sizeof(struct cmdqCommandStruct) = %ld\n",
  669. CMDQ_IOCTL_EXEC_COMMAND, sizeof(struct cmdqCommandStruct));
  670. CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE:0x%08lx sizeof(struct cmdqUsageInfoStruct) = %ld\n",
  671. CMDQ_IOCTL_QUERY_USAGE, sizeof(struct cmdqUsageInfoStruct));
  672. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC:0x%08lx sizeof(struct cmdqJobStruct) = %ld\n",
  673. CMDQ_IOCTL_ASYNC_JOB_EXEC, sizeof(struct cmdqJobStruct));
  674. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE:0x%08lx sizeof(struct cmdqJobResultStruct) = %ld\n",
  675. CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE, sizeof(struct cmdqJobResultStruct));
  676. CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n",
  677. CMDQ_IOCTL_ALLOC_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct));
  678. CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n",
  679. CMDQ_IOCTL_FREE_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct));
  680. CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE:0x%08lx sizeof(struct cmdqReadAddressStruct) = %ld\n",
  681. CMDQ_IOCTL_READ_ADDRESS_VALUE, sizeof(struct cmdqReadAddressStruct));
  682. CMDQ_ERR("CMDQ_IOCTL_QUERY_CAP_BITS:0x%08lx sizeof(int) = %ld\n",
  683. CMDQ_IOCTL_QUERY_CAP_BITS, sizeof(int));
  684. CMDQ_ERR("CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION:0x%08lx sizeof(struct cmdqSyncHandleHdcpStruct) = %ld\n",
  685. CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION, sizeof(struct cmdqSyncHandleHdcpStruct));
  686. return -IOCTL_RET_UNRECOGNIZED_IOCTL;
  687. }
  688. return IOCTL_RET_SUCCESS;
  689. }
  690. static long cmdq_ioctl_compat(struct file *pFile, unsigned int code, unsigned long param)
  691. {
  692. #ifdef CONFIG_COMPAT
  693. switch (code) {
  694. case CMDQ_IOCTL_QUERY_USAGE:
  695. case CMDQ_IOCTL_EXEC_COMMAND:
  696. case CMDQ_IOCTL_ASYNC_JOB_EXEC:
  697. case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE:
  698. case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS:
  699. case CMDQ_IOCTL_FREE_WRITE_ADDRESS:
  700. case CMDQ_IOCTL_READ_ADDRESS_VALUE:
  701. case CMDQ_IOCTL_QUERY_CAP_BITS:
  702. /* All ioctl structures should be the same size in 32-bit and 64-bit linux. */
  703. return cmdq_ioctl(pFile, code, param);
  704. case CMDQ_IOCTL_LOCK_MUTEX:
  705. CMDQ_ERR("[COMPAT]deprecated ioctl 0x%08x\n", code);
  706. return -IOCTL_RET_DEPRECATE_LOCK_MUTEX;
  707. case CMDQ_IOCTL_UNLOCK_MUTEX:
  708. CMDQ_ERR("[COMPAT]deprecated ioctl 0x%08x\n", code);
  709. return -IOCTL_RET_DEPRECATE_UNLOCK_MUTEX;
  710. default:
  711. CMDQ_ERR("[COMPAT]unrecognized ioctl 0x%08x\n", code);
  712. CMDQ_ERR("CMDQ_IOCTL_LOCK_MUTEX:0x%08lx sizeof(int) = %ld\n",
  713. CMDQ_IOCTL_LOCK_MUTEX, sizeof(int));
  714. CMDQ_ERR("CMDQ_IOCTL_UNLOCK_MUTEX:0x%08lx sizeof(int) = %ld\n",
  715. CMDQ_IOCTL_UNLOCK_MUTEX, sizeof(int));
  716. CMDQ_ERR("CMDQ_IOCTL_EXEC_COMMAND:0x%08lx sizeof(struct cmdqCommandStruct) = %ld\n",
  717. CMDQ_IOCTL_EXEC_COMMAND, sizeof(struct cmdqCommandStruct));
  718. CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE:0x%08lx sizeof(struct cmdqUsageInfoStruct) = %ld\n",
  719. CMDQ_IOCTL_QUERY_USAGE, sizeof(struct cmdqUsageInfoStruct));
  720. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC:0x%08lx sizeof(struct cmdqJobStruct) = %ld\n",
  721. CMDQ_IOCTL_ASYNC_JOB_EXEC, sizeof(struct cmdqJobStruct));
  722. CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE:0x%08lx sizeof(struct cmdqJobResultStruct) = %ld\n",
  723. CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE, sizeof(struct cmdqJobResultStruct));
  724. CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n",
  725. CMDQ_IOCTL_ALLOC_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct));
  726. CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n",
  727. CMDQ_IOCTL_FREE_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct));
  728. CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE:0x%08lx sizeof(struct cmdqReadAddressStruct) = %ld\n",
  729. CMDQ_IOCTL_READ_ADDRESS_VALUE, sizeof(struct cmdqReadAddressStruct));
  730. CMDQ_ERR("CMDQ_IOCTL_QUERY_CAP_BITS:0x%08lx sizeof(int) = %ld\n",
  731. CMDQ_IOCTL_QUERY_CAP_BITS, sizeof(int));
  732. CMDQ_ERR("CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION:0x%08lx sizeof(struct cmdqSyncHandleHdcpStruct) = %ld\n",
  733. CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION, sizeof(struct cmdqSyncHandleHdcpStruct));
  734. return -IOCTL_RET_UNRECOGNIZED_COMPAT_IOCTL;
  735. }
  736. #else
  737. return -IOCTL_RET_CONFIG_COMPAT_NOT_OPEN;
  738. #endif
  739. }
  740. static const struct file_operations cmdqOP = {
  741. .owner = THIS_MODULE,
  742. .open = cmdq_open,
  743. .release = cmdq_release,
  744. .unlocked_ioctl = cmdq_ioctl,
  745. #ifdef CONFIG_COMPAT
  746. .compat_ioctl = cmdq_ioctl_compat,
  747. #endif
  748. };
  749. static int cmdq_pm_notifier_cb(struct notifier_block *nb, unsigned long event, void *ptr)
  750. {
  751. switch (event) {
  752. case PM_SUSPEND_PREPARE: /* Going to suspend the system */
  753. /* The next stage is freeze process. */
  754. /* We will queue all request in suspend callback, */
  755. /* so don't care this stage */
  756. return NOTIFY_DONE; /* don't care this event */
  757. case PM_POST_SUSPEND:
  758. /* processes had resumed in previous stage (system resume callback) */
  759. /* resume CMDQ driver to execute. */
  760. cmdqCoreResumedNotifier();
  761. return NOTIFY_OK; /* process done */
  762. default:
  763. return NOTIFY_DONE;
  764. }
  765. return NOTIFY_DONE;
  766. }
  767. /* Hibernation and suspend events */
  768. static struct notifier_block cmdq_pm_notifier_block = {
  769. .notifier_call = cmdq_pm_notifier_cb,
  770. .priority = 5,
  771. };
  772. static irqreturn_t cmdq_irq_handler(int IRQ, void *pDevice)
  773. {
  774. int index;
  775. uint32_t irqStatus;
  776. bool handled = false; /* we share IRQ bit with CQ-DMA, */
  777. /* so it is possible that this handler */
  778. /* is called but GCE does not have IRQ flag. */
  779. do {
  780. if (cmdq_dev_get_irq_id() == IRQ) {
  781. irqStatus = CMDQ_REG_GET32(CMDQ_CURR_IRQ_STATUS) & 0x0FFFF;
  782. for (index = 0; (irqStatus != 0xFFFF) && index < CMDQ_MAX_THREAD_COUNT;
  783. index++) {
  784. /* STATUS bit set to 0 means IRQ asserted */
  785. if (irqStatus & (1 << index))
  786. continue;
  787. /* so we mark irqStatus to 1 to denote finished processing */
  788. /* and we can early-exit if no more threads being asserted */
  789. irqStatus |= (1 << index);
  790. cmdqCoreHandleIRQ(index);
  791. handled = true;
  792. }
  793. } else if (cmdq_dev_get_irq_secure_id() == IRQ) {
  794. CMDQ_ERR("receive secure IRQ %d in NWD\n", IRQ);
  795. }
  796. } while (0);
  797. if (handled) {
  798. cmdq_core_add_consume_task();
  799. return IRQ_HANDLED;
  800. }
  801. /* allow CQ-DMA to process this IRQ bit */
  802. return IRQ_NONE;
  803. }
  804. #if 0
  805. static irqreturn_t cmdq_sec_irq_handler(int IRQ, void *pDevice)
  806. {
  807. int index;
  808. uint32_t irqStatus;
  809. bool handled = false; /* we share IRQ bit with CQ-DMA, */
  810. /* so it is possible that this handler */
  811. /* is called but GCE does not have IRQ flag. */
  812. do {
  813. if (cmdq_dev_get_irq_id() == IRQ) {
  814. irqStatus = CMDQ_REG_GET32(CMDQ_CURR_IRQ_STATUS) & 0x0FFFF;
  815. for (index = 0; (irqStatus != 0xFFFF) && index < CMDQ_MAX_THREAD_COUNT;
  816. index++) {
  817. /* STATUS bit set to 0 means IRQ asserted */
  818. if (irqStatus & (1 << index))
  819. continue;
  820. /* so we mark irqStatus to 1 to denote finished processing */
  821. /* and we can early-exit if no more threads being asserted */
  822. irqStatus |= (1 << index);
  823. cmdqCoreHandleIRQ(index);
  824. handled = true;
  825. }
  826. } else if (cmdq_dev_get_irq_secure_id() == IRQ) {
  827. CMDQ_ERR("receive secure IRQ %d in NWD\n", IRQ);
  828. }
  829. } while (0);
  830. if (handled) {
  831. cmdq_core_add_consume_task();
  832. return IRQ_HANDLED;
  833. }
  834. /* allow CQ-DMA to process this IRQ bit */
  835. return IRQ_NONE;
  836. }
  837. #endif
  838. static int cmdq_create_debug_entries(void)
  839. {
  840. struct proc_dir_entry *debugDirEntry = NULL;
  841. debugDirEntry = proc_mkdir(CMDQ_DRIVER_DEVICE_NAME "_debug", NULL);
  842. if (debugDirEntry) {
  843. struct proc_dir_entry *entry = NULL;
  844. entry = proc_create("status", 0440, debugDirEntry, &cmdqDebugStatusOp);
  845. entry = proc_create("error", 0440, debugDirEntry, &cmdqDebugErrorOp);
  846. entry = proc_create("record", 0440, debugDirEntry, &cmdqDebugRecordOp);
  847. entry = proc_create("log_level", 0660, debugDirEntry, &cmdqDebugLevelOp);
  848. }
  849. return 0;
  850. }
  851. static int cmdq_probe(struct platform_device *pDevice)
  852. {
  853. int status;
  854. struct device *object;
  855. CMDQ_MSG("CMDQ driver probe begin\n");
  856. /* init cmdq device related data */
  857. cmdq_dev_init(pDevice);
  858. /* init cmdq context */
  859. cmdqCoreInitialize();
  860. status = alloc_chrdev_region(&gCmdqDevNo, 0, 1, CMDQ_DRIVER_DEVICE_NAME);
  861. if (status != 0)
  862. CMDQ_ERR("Get CMDQ device major number(%d) failed(%d)\n", gCmdqDevNo, status);
  863. else
  864. CMDQ_MSG("Get CMDQ device major number(%d) success(%d)\n", gCmdqDevNo, status);
  865. /* ioctl access point (/dev/mtk_cmdq) */
  866. gCmdqCDev = cdev_alloc();
  867. gCmdqCDev->owner = THIS_MODULE;
  868. gCmdqCDev->ops = &cmdqOP;
  869. status = cdev_add(gCmdqCDev, gCmdqDevNo, 1);
  870. gCMDQClass = class_create(THIS_MODULE, CMDQ_DRIVER_DEVICE_NAME);
  871. object = device_create(gCMDQClass, NULL, gCmdqDevNo, NULL, CMDQ_DRIVER_DEVICE_NAME);
  872. CMDQ_LOG("register IRQ:%d\n", cmdq_dev_get_irq_id());
  873. status =
  874. request_irq(cmdq_dev_get_irq_id(), cmdq_irq_handler, IRQF_TRIGGER_LOW,
  875. CMDQ_DRIVER_DEVICE_NAME, gCmdqCDev);
  876. if (status != 0) {
  877. CMDQ_ERR("Register cmdq driver irq handler(%d) failed(%d)\n", gCmdqDevNo, status);
  878. return -EFAULT;
  879. }
  880. #if 0 /* remove register secure IRQ in Normal world . TZ register instead */
  881. /* although secusre CMDQ driver is responsible for handle secure IRQ, */
  882. /* MUST registet secure IRQ to GIC in normal world to ensure it will be initialize correctly */
  883. /* (that's because t-base does not support GIC init IRQ in secure world...) */
  884. CMDQ_LOG("register sec IRQ:%d\n", cmdq_dev_get_irq_secure_id());
  885. status =
  886. request_irq(cmdq_dev_get_irq_secure_id(), cmdq_sec_irq_handler, IRQF_TRIGGER_LOW,
  887. "TEE IRQ", gCmdqCDev);
  888. if (status != 0) {
  889. CMDQ_ERR("Register cmdq driver secure irq handler(%d) failed(%d)\n", gCmdqDevNo,
  890. status);
  891. return -EFAULT;
  892. }
  893. #endif
  894. /* CMDQ_ERR("prepare to create device mtk_cmdq\n"); */
  895. /* global ioctl access point (/proc/mtk_cmdq) */
  896. if (NULL == proc_create(CMDQ_DRIVER_DEVICE_NAME, 0644, NULL, &cmdqOP)) {
  897. CMDQ_ERR("CMDQ procfs node create failed\n");
  898. return -EFAULT;
  899. }
  900. #ifdef CMDQ_OF_SUPPORT
  901. /* CCF - Common Clock Framework */
  902. cmdq_core_get_clk_map(pDevice);
  903. #endif
  904. /* proc debug access point */
  905. cmdq_create_debug_entries();
  906. /* device attributes for debugging */
  907. device_create_file(&pDevice->dev, &dev_attr_status);
  908. device_create_file(&pDevice->dev, &dev_attr_error);
  909. device_create_file(&pDevice->dev, &dev_attr_record);
  910. device_create_file(&pDevice->dev, &dev_attr_log_level);
  911. device_create_file(&pDevice->dev, &dev_attr_profile_enable);
  912. CMDQ_MSG("CMDQ driver probe end\n");
  913. return 0;
  914. }
  915. static int cmdq_remove(struct platform_device *pDevice)
  916. {
  917. disable_irq(cmdq_dev_get_irq_id());
  918. device_remove_file(&pDevice->dev, &dev_attr_status);
  919. device_remove_file(&pDevice->dev, &dev_attr_error);
  920. device_remove_file(&pDevice->dev, &dev_attr_record);
  921. device_remove_file(&pDevice->dev, &dev_attr_log_level);
  922. device_remove_file(&pDevice->dev, &dev_attr_profile_enable);
  923. return 0;
  924. }
  925. #ifdef CONFIG_HAS_EARLYSUSPEND
  926. static void cmdq_earlysuspend(struct early_suspend *h)
  927. {
  928. cmdqCoreEarlySuspend();
  929. }
  930. static void cmdq_lateresume(struct early_suspend *h)
  931. {
  932. cmdqCoreLateResume();
  933. }
  934. #endif
  935. static int cmdq_suspend(struct device *pDevice)
  936. {
  937. return cmdqCoreSuspend();
  938. }
  939. static int cmdq_resume(struct device *pDevice)
  940. {
  941. return cmdqCoreResume();
  942. }
  943. static int cmdq_pm_restore_noirq(struct device *pDevice)
  944. {
  945. return 0;
  946. }
  947. static const struct dev_pm_ops cmdq_pm_ops = {
  948. .suspend = cmdq_suspend,
  949. .resume = cmdq_resume,
  950. .freeze = NULL,
  951. .thaw = NULL,
  952. .poweroff = NULL,
  953. .restore = NULL,
  954. .restore_noirq = cmdq_pm_restore_noirq,
  955. };
  956. static struct platform_driver gCmdqDriver = {
  957. .probe = cmdq_probe,
  958. .remove = cmdq_remove,
  959. .driver = {
  960. .name = CMDQ_DRIVER_DEVICE_NAME,
  961. .owner = THIS_MODULE,
  962. .pm = &cmdq_pm_ops,
  963. #ifdef CMDQ_OF_SUPPORT
  964. .of_match_table = cmdq_of_ids,
  965. #endif
  966. }
  967. };
  968. #ifdef CONFIG_HAS_EARLYSUSPEND
  969. static struct early_suspend cmdq_early_suspend_handler = {
  970. .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1,
  971. .suspend = cmdq_earlysuspend,
  972. .resume = cmdq_lateresume,
  973. };
  974. #endif
  975. static int __init cmdq_init(void)
  976. {
  977. int status;
  978. CMDQ_MSG("CMDQ driver init begin\n");
  979. /* Initialize mutex */
  980. cmdqMutexInitialize();
  981. /* Initialize group callback */
  982. cmdqCoreInitGroupCB();
  983. /* Register MDP callback */
  984. cmdqCoreRegisterCB(CMDQ_GROUP_MDP, cmdqMdpClockOn, cmdqMdpDumpInfo, cmdqMdpResetEng,
  985. cmdqMdpClockOff);
  986. /* Register VENC callback */
  987. cmdqCoreRegisterCB(CMDQ_GROUP_VENC, NULL, cmdqVEncDumpInfo, NULL, NULL);
  988. #ifdef CONFIG_HAS_EARLYSUSPEND
  989. register_early_suspend(&cmdq_early_suspend_handler);
  990. #endif
  991. status = platform_driver_register(&gCmdqDriver);
  992. if (0 != status) {
  993. CMDQ_ERR("Failed to register the CMDQ driver(%d)\n", status);
  994. return -ENODEV;
  995. }
  996. /* register pm notifier */
  997. status = register_pm_notifier(&cmdq_pm_notifier_block);
  998. if (0 != status) {
  999. CMDQ_ERR("Failed to register_pm_notifier(%d)\n", status);
  1000. return -ENODEV;
  1001. }
  1002. CMDQ_MSG("CMDQ driver init end\n");
  1003. return 0;
  1004. }
  1005. static void __exit cmdq_exit(void)
  1006. {
  1007. int32_t status;
  1008. CMDQ_MSG("CMDQ driver exit begin\n");
  1009. device_destroy(gCMDQClass, gCmdqDevNo);
  1010. class_destroy(gCMDQClass);
  1011. cdev_del(gCmdqCDev);
  1012. gCmdqCDev = NULL;
  1013. unregister_chrdev_region(gCmdqDevNo, 1);
  1014. platform_driver_unregister(&gCmdqDriver);
  1015. #ifdef CONFIG_HAS_EARLYSUSPEND
  1016. unregister_early_suspend(&cmdq_early_suspend_handler);
  1017. #endif
  1018. /* register pm notifier */
  1019. status = unregister_pm_notifier(&cmdq_pm_notifier_block);
  1020. if (0 != status)
  1021. CMDQ_ERR("Failed to unregister_pm_notifier(%d)\n", status);
  1022. /* Unregister MDP callback */
  1023. cmdqCoreRegisterCB(CMDQ_GROUP_MDP, NULL, NULL, NULL, NULL);
  1024. /* Unregister VENC callback */
  1025. cmdqCoreRegisterCB(CMDQ_GROUP_VENC, NULL, NULL, NULL, NULL);
  1026. /* De-Initialize group callback */
  1027. cmdqCoreDeinitGroupCB();
  1028. /* De-Initialize cmdq core */
  1029. cmdqCoreDeInitialize();
  1030. /* De-Initialize cmdq dev related data */
  1031. cmdq_dev_deinit();
  1032. /* De-Initialize mutex */
  1033. cmdqMutexDeInitialize();
  1034. CMDQ_MSG("CMDQ driver exit end\n");
  1035. }
  1036. static int __init cmdq_driver_init_secure_path(void)
  1037. {
  1038. #ifdef CMDQ_SECURE_PATH_SUPPORT
  1039. cmdq_sec_init_secure_path();
  1040. #endif
  1041. return 0;
  1042. }
  1043. subsys_initcall(cmdq_init);
  1044. late_initcall(cmdq_driver_init_secure_path);
  1045. module_exit(cmdq_exit);
  1046. MODULE_DESCRIPTION("MTK CMDQ driver");
  1047. MODULE_AUTHOR("Pablo<pablo.sun@mediatek.com>");
  1048. MODULE_LICENSE("GPL");