/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2 · C · 417 lines · 247 code · 79 blank · 91 comment · 20 complexity · 4595f6b1f0bf7d5e2988204c4c680c86 MD5 · raw file

  1. /* cyanblkdev_queue.h - Antioch Linux Block Driver queue source file
  2. ## ===========================
  3. ## Copyright (C) 2010 Cypress Semiconductor
  4. ##
  5. ## This program is free software; you can redistribute it and/or
  6. ## modify it under the terms of the GNU General Public License
  7. ## as published by the Free Software Foundation; either version 2
  8. ## of the License, or (at your option) any later version.
  9. ##
  10. ## This program is distributed in the hope that it will be useful,
  11. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ## GNU General Public License for more details.
  14. ##
  15. ## You should have received a copy of the GNU General Public License
  16. ## along with this program; if not, write to the Free Software
  17. ## Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18. ## Boston, MA 02110-1301, USA.
  19. ## ===========================
  20. */
  21. /*
  22. * Request queue handling for Antioch block device driver.
  23. * Based on the mmc queue handling code by Russell King in the
  24. * linux 2.6.10 kernel.
  25. */
  26. /*
  27. * linux/drivers/mmc/mmc_queue.c
  28. *
  29. * Copyright (C) 2003 Russell King, All Rights Reserved.
  30. *
  31. * This program is free software; you can redistribute it and/or modify
  32. * it under the terms of the GNU General Public License version 2 as
  33. * published by the Free Software Foundation.
  34. *
  35. */
  36. #include <linux/module.h>
  37. #include <linux/blkdev.h>
  38. #include "cyasblkdev_queue.h"
  39. #define CYASBLKDEV_QUEUE_EXIT (1 << 0)
  40. #define CYASBLKDEV_QUEUE_SUSPENDED (1 << 1)
  41. #define CY_AS_USE_ASYNC_API
  42. /* print flags by name */
  43. const char *rq_flag_bit_names[] = {
  44. "REQ_RW", /* not set, read. set, write */
  45. "REQ_FAILFAST", /* no low level driver retries */
  46. "REQ_SORTED", /* elevator knows about this request */
  47. "REQ_SOFTBARRIER", /* may not be passed by ioscheduler */
  48. "REQ_HARDBARRIER", /* may not be passed by drive either */
  49. "REQ_FUA", /* forced unit access */
  50. "REQ_NOMERGE", /* don't touch this for merging */
  51. "REQ_STARTED", /* drive already may have started this one */
  52. "REQ_DONTPREP", /* don't call prep for this one */
  53. "REQ_QUEUED", /* uses queueing */
  54. "REQ_ELVPRIV", /* elevator private data attached */
  55. "REQ_FAILED", /* set if the request failed */
  56. "REQ_QUIET", /* don't worry about errors */
  57. "REQ_PREEMPT", /* set for "ide_preempt" requests */
  58. "REQ_ORDERED_COLOR",/* is before or after barrier */
  59. "REQ_RW_SYNC", /* request is sync (O_DIRECT) */
  60. "REQ_ALLOCED", /* request came from our alloc pool */
  61. "REQ_RW_META", /* metadata io request */
  62. "REQ_COPY_USER", /* contains copies of user pages */
  63. "REQ_NR_BITS", /* stops here */
  64. };
  65. void verbose_rq_flags(int flags)
  66. {
  67. int i;
  68. uint32_t j;
  69. j = 1;
  70. for (i = 0; i < 32; i++) {
  71. if (flags & j)
  72. DBGPRN("<1>%s", rq_flag_bit_names[i]);
  73. j = j << 1;
  74. }
  75. }
  76. /*
  77. * Prepare a -BLK_DEV request. Essentially, this means passing the
  78. * preparation off to the media driver. The media driver will
  79. * create request to CyAsDev.
  80. */
  81. static int cyasblkdev_prep_request(
  82. struct request_queue *q, struct request *req)
  83. {
  84. DBGPRN_FUNC_NAME;
  85. /* we only like normal block requests.*/
  86. if (req->cmd_type != REQ_TYPE_FS && !(req->cmd_flags & REQ_DISCARD)) {
  87. #ifndef WESTBRIDGE_NDEBUG
  88. cy_as_hal_print_message("%s:%x bad request received\n",
  89. __func__, current->pid);
  90. #endif
  91. blk_dump_rq_flags(req, "cyasblkdev bad request");
  92. return BLKPREP_KILL;
  93. }
  94. req->cmd_flags |= REQ_DONTPREP;
  95. return BLKPREP_OK;
  96. }
  97. /* queue worker thread */
  98. static int cyasblkdev_queue_thread(void *d)
  99. {
  100. DECLARE_WAITQUEUE(wait, current);
  101. struct cyasblkdev_queue *bq = d;
  102. struct request_queue *q = bq->queue;
  103. u32 qth_pid;
  104. DBGPRN_FUNC_NAME;
  105. /*
  106. * set iothread to ensure that we aren't put to sleep by
  107. * the process freezing. we handle suspension ourselves.
  108. */
  109. daemonize("cyasblkdev_queue_thread");
  110. /* signal to queue_init() so it could contnue */
  111. complete(&bq->thread_complete);
  112. down(&bq->thread_sem);
  113. add_wait_queue(&bq->thread_wq, &wait);
  114. qth_pid = current->pid;
  115. #ifndef WESTBRIDGE_NDEBUG
  116. cy_as_hal_print_message(
  117. "%s:%x started, bq:%p, q:%p\n", __func__, qth_pid, bq, q);
  118. #endif
  119. do {
  120. struct request *req = NULL;
  121. /* the thread wants to be woken up by signals as well */
  122. set_current_state(TASK_INTERRUPTIBLE);
  123. spin_lock_irq(q->queue_lock);
  124. #ifndef WESTBRIDGE_NDEBUG
  125. cy_as_hal_print_message(
  126. "%s: for bq->queue is null\n", __func__);
  127. #endif
  128. if (!bq->req) {
  129. /* chk if queue is plugged */
  130. if (!blk_queue_plugged(q)) {
  131. bq->req = req = blk_fetch_request(q);
  132. #ifndef WESTBRIDGE_NDEBUG
  133. cy_as_hal_print_message(
  134. "%s: blk_fetch_request:%x\n",
  135. __func__, (uint32_t)req);
  136. #endif
  137. } else {
  138. #ifndef WESTBRIDGE_NDEBUG
  139. cy_as_hal_print_message(
  140. "%s: queue plugged, "
  141. "skip blk_fetch()\n", __func__);
  142. #endif
  143. }
  144. }
  145. spin_unlock_irq(q->queue_lock);
  146. #ifndef WESTBRIDGE_NDEBUG
  147. cy_as_hal_print_message(
  148. "%s: checking if request queue is null\n", __func__);
  149. #endif
  150. if (!req) {
  151. if (bq->flags & CYASBLKDEV_QUEUE_EXIT) {
  152. #ifndef WESTBRIDGE_NDEBUG
  153. cy_as_hal_print_message(
  154. "%s:got QUEUE_EXIT flag\n", __func__);
  155. #endif
  156. break;
  157. }
  158. #ifndef WESTBRIDGE_NDEBUG
  159. cy_as_hal_print_message(
  160. "%s: request queue is null, goto sleep, "
  161. "thread_sem->count=%d\n",
  162. __func__, bq->thread_sem.count);
  163. if (spin_is_locked(q->queue_lock)) {
  164. cy_as_hal_print_message("%s: queue_lock "
  165. "is locked, need to release\n", __func__);
  166. spin_unlock(q->queue_lock);
  167. if (spin_is_locked(q->queue_lock))
  168. cy_as_hal_print_message(
  169. "%s: unlock did not work\n",
  170. __func__);
  171. } else {
  172. cy_as_hal_print_message(
  173. "%s: checked lock, is not locked\n",
  174. __func__);
  175. }
  176. #endif
  177. up(&bq->thread_sem);
  178. /* yields to the next rdytorun proc,
  179. * then goes back to sleep*/
  180. schedule();
  181. down(&bq->thread_sem);
  182. #ifndef WESTBRIDGE_NDEBUG
  183. cy_as_hal_print_message(
  184. "%s: wake_up,continue\n",
  185. __func__);
  186. #endif
  187. continue;
  188. }
  189. /* new req received, issue it to the driver */
  190. set_current_state(TASK_RUNNING);
  191. #ifndef WESTBRIDGE_NDEBUG
  192. cy_as_hal_print_message(
  193. "%s: issued a RQ:%x\n",
  194. __func__, (uint32_t)req);
  195. #endif
  196. bq->issue_fn(bq, req);
  197. #ifndef WESTBRIDGE_NDEBUG
  198. cy_as_hal_print_message(
  199. "%s: bq->issue_fn() returned\n",
  200. __func__);
  201. #endif
  202. } while (1);
  203. set_current_state(TASK_RUNNING);
  204. remove_wait_queue(&bq->thread_wq, &wait);
  205. up(&bq->thread_sem);
  206. complete_and_exit(&bq->thread_complete, 0);
  207. #ifndef WESTBRIDGE_NDEBUG
  208. cy_as_hal_print_message("%s: is finished\n", __func__);
  209. #endif
  210. return 0;
  211. }
  212. /*
  213. * Generic request handler. it is called for any queue on a
  214. * particular host. When the host is not busy, we look for a request
  215. * on any queue on this host, and attempt to issue it. This may
  216. * not be the queue we were asked to process.
  217. */
  218. static void cyasblkdev_request(struct request_queue *q)
  219. {
  220. struct cyasblkdev_queue *bq = q->queuedata;
  221. DBGPRN_FUNC_NAME;
  222. #ifndef WESTBRIDGE_NDEBUG
  223. cy_as_hal_print_message(
  224. "%s new request on cyasblkdev_queue_t bq:=%x\n",
  225. __func__, (uint32_t)bq);
  226. #endif
  227. if (!bq->req) {
  228. #ifndef WESTBRIDGE_NDEBUG
  229. cy_as_hal_print_message("%s wake_up(&bq->thread_wq)\n",
  230. __func__);
  231. #endif
  232. /* wake up cyasblkdev_queue worker thread*/
  233. wake_up(&bq->thread_wq);
  234. } else {
  235. #ifndef WESTBRIDGE_NDEBUG
  236. cy_as_hal_print_message("%s: don't wake Q_thr, bq->req:%x\n",
  237. __func__, (uint32_t)bq->req);
  238. #endif
  239. }
  240. }
  241. /*
  242. * cyasblkdev_init_queue - initialise a queue structure.
  243. * @bq: cyasblkdev queue
  244. * @dev: CyAsDeviceHandle to attach this queue
  245. * @lock: queue lock
  246. *
  247. * Initialise a cyasblkdev_request queue.
  248. */
  249. /* MAX NUMBER OF SECTORS PER REQUEST **/
  250. #define Q_MAX_SECTORS 128
  251. /* MAX NUMBER OF PHYS SEGMENTS (entries in the SG list)*/
  252. #define Q_MAX_SGS 16
  253. int cyasblkdev_init_queue(struct cyasblkdev_queue *bq, spinlock_t *lock)
  254. {
  255. int ret;
  256. DBGPRN_FUNC_NAME;
  257. /* 1st param is a function that wakes up the queue thread */
  258. bq->queue = blk_init_queue(cyasblkdev_request, lock);
  259. if (!bq->queue)
  260. return -ENOMEM;
  261. blk_queue_prep_rq(bq->queue, cyasblkdev_prep_request);
  262. blk_queue_bounce_limit(bq->queue, BLK_BOUNCE_ANY);
  263. blk_queue_max_hw_sectors(bq->queue, Q_MAX_SECTORS);
  264. /* As of now, we have the HAL/driver support to
  265. * merge scattered segments and handle them simultaneously.
  266. * so, setting the max_phys_segments to 8. */
  267. /*blk_queue_max_phys_segments(bq->queue, Q_MAX_SGS);
  268. blk_queue_max_hw_segments(bq->queue, Q_MAX_SGS);*/
  269. blk_queue_max_segments(bq->queue, Q_MAX_SGS);
  270. /* should be < then HAL can handle */
  271. blk_queue_max_segment_size(bq->queue, 512*Q_MAX_SECTORS);
  272. bq->queue->queuedata = bq;
  273. bq->req = NULL;
  274. init_completion(&bq->thread_complete);
  275. init_waitqueue_head(&bq->thread_wq);
  276. sema_init(&bq->thread_sem, 1);
  277. ret = kernel_thread(cyasblkdev_queue_thread, bq, CLONE_KERNEL);
  278. if (ret >= 0) {
  279. /* wait until the thread is spawned */
  280. wait_for_completion(&bq->thread_complete);
  281. /* reinitialize the completion */
  282. init_completion(&bq->thread_complete);
  283. ret = 0;
  284. goto out;
  285. }
  286. out:
  287. return ret;
  288. }
  289. EXPORT_SYMBOL(cyasblkdev_init_queue);
  290. /*called from blk_put() */
  291. void cyasblkdev_cleanup_queue(struct cyasblkdev_queue *bq)
  292. {
  293. DBGPRN_FUNC_NAME;
  294. bq->flags |= CYASBLKDEV_QUEUE_EXIT;
  295. wake_up(&bq->thread_wq);
  296. wait_for_completion(&bq->thread_complete);
  297. blk_cleanup_queue(bq->queue);
  298. }
  299. EXPORT_SYMBOL(cyasblkdev_cleanup_queue);
  300. /**
  301. * cyasblkdev_queue_suspend - suspend a CyAsBlkDev request queue
  302. * @bq: CyAsBlkDev queue to suspend
  303. *
  304. * Stop the block request queue, and wait for our thread to
  305. * complete any outstanding requests. This ensures that we
  306. * won't suspend while a request is being processed.
  307. */
  308. void cyasblkdev_queue_suspend(struct cyasblkdev_queue *bq)
  309. {
  310. struct request_queue *q = bq->queue;
  311. unsigned long flags;
  312. DBGPRN_FUNC_NAME;
  313. if (!(bq->flags & CYASBLKDEV_QUEUE_SUSPENDED)) {
  314. bq->flags |= CYASBLKDEV_QUEUE_SUSPENDED;
  315. spin_lock_irqsave(q->queue_lock, flags);
  316. blk_stop_queue(q);
  317. spin_unlock_irqrestore(q->queue_lock, flags);
  318. down(&bq->thread_sem);
  319. }
  320. }
  321. EXPORT_SYMBOL(cyasblkdev_queue_suspend);
  322. /*cyasblkdev_queue_resume - resume a previously suspended
  323. * CyAsBlkDev request queue @bq: CyAsBlkDev queue to resume */
  324. void cyasblkdev_queue_resume(struct cyasblkdev_queue *bq)
  325. {
  326. struct request_queue *q = bq->queue;
  327. unsigned long flags;
  328. DBGPRN_FUNC_NAME;
  329. if (bq->flags & CYASBLKDEV_QUEUE_SUSPENDED) {
  330. bq->flags &= ~CYASBLKDEV_QUEUE_SUSPENDED;
  331. up(&bq->thread_sem);
  332. spin_lock_irqsave(q->queue_lock, flags);
  333. blk_start_queue(q);
  334. spin_unlock_irqrestore(q->queue_lock, flags);
  335. }
  336. }
  337. EXPORT_SYMBOL(cyasblkdev_queue_resume);
  338. /*[]*/