PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/hv/ring_buffer.c

http://github.com/CyanogenMod/cm-kernel
C | 619 lines | 277 code | 112 blank | 230 comment | 9 complexity | f811c18e3bc03238025cfa5126ac3a81 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.0
  1. /*
  2. *
  3. * Copyright (c) 2009, Microsoft Corporation.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms and conditions of the GNU General Public License,
  7. * version 2, as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  16. * Place - Suite 330, Boston, MA 02111-1307 USA.
  17. *
  18. * Authors:
  19. * Haiyang Zhang <haiyangz@microsoft.com>
  20. * Hank Janssen <hjanssen@microsoft.com>
  21. *
  22. */
  23. #include <linux/kernel.h>
  24. #include <linux/mm.h>
  25. #include "osd.h"
  26. #include "logging.h"
  27. #include "ring_buffer.h"
  28. /* #defines */
  29. /* Amount of space to write to */
  30. #define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r)) ? ((z) - ((w) - (r))) : ((r) - (w))
  31. /*++
  32. Name:
  33. GetRingBufferAvailBytes()
  34. Description:
  35. Get number of bytes available to read and to write to
  36. for the specified ring buffer
  37. --*/
  38. static inline void
  39. GetRingBufferAvailBytes(struct hv_ring_buffer_info *rbi, u32 *read, u32 *write)
  40. {
  41. u32 read_loc, write_loc;
  42. /* Capture the read/write indices before they changed */
  43. read_loc = rbi->RingBuffer->ReadIndex;
  44. write_loc = rbi->RingBuffer->WriteIndex;
  45. *write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
  46. *read = rbi->RingDataSize - *write;
  47. }
  48. /*++
  49. Name:
  50. GetNextWriteLocation()
  51. Description:
  52. Get the next write location for the specified ring buffer
  53. --*/
  54. static inline u32
  55. GetNextWriteLocation(struct hv_ring_buffer_info *RingInfo)
  56. {
  57. u32 next = RingInfo->RingBuffer->WriteIndex;
  58. /* ASSERT(next < RingInfo->RingDataSize); */
  59. return next;
  60. }
  61. /*++
  62. Name:
  63. SetNextWriteLocation()
  64. Description:
  65. Set the next write location for the specified ring buffer
  66. --*/
  67. static inline void
  68. SetNextWriteLocation(struct hv_ring_buffer_info *RingInfo,
  69. u32 NextWriteLocation)
  70. {
  71. RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
  72. }
  73. /*++
  74. Name:
  75. GetNextReadLocation()
  76. Description:
  77. Get the next read location for the specified ring buffer
  78. --*/
  79. static inline u32
  80. GetNextReadLocation(struct hv_ring_buffer_info *RingInfo)
  81. {
  82. u32 next = RingInfo->RingBuffer->ReadIndex;
  83. /* ASSERT(next < RingInfo->RingDataSize); */
  84. return next;
  85. }
  86. /*++
  87. Name:
  88. GetNextReadLocationWithOffset()
  89. Description:
  90. Get the next read location + offset for the specified ring buffer.
  91. This allows the caller to skip
  92. --*/
  93. static inline u32
  94. GetNextReadLocationWithOffset(struct hv_ring_buffer_info *RingInfo, u32 Offset)
  95. {
  96. u32 next = RingInfo->RingBuffer->ReadIndex;
  97. /* ASSERT(next < RingInfo->RingDataSize); */
  98. next += Offset;
  99. next %= RingInfo->RingDataSize;
  100. return next;
  101. }
  102. /*++
  103. Name:
  104. SetNextReadLocation()
  105. Description:
  106. Set the next read location for the specified ring buffer
  107. --*/
  108. static inline void
  109. SetNextReadLocation(struct hv_ring_buffer_info *RingInfo, u32 NextReadLocation)
  110. {
  111. RingInfo->RingBuffer->ReadIndex = NextReadLocation;
  112. }
  113. /*++
  114. Name:
  115. GetRingBuffer()
  116. Description:
  117. Get the start of the ring buffer
  118. --*/
  119. static inline void *
  120. GetRingBuffer(struct hv_ring_buffer_info *RingInfo)
  121. {
  122. return (void *)RingInfo->RingBuffer->Buffer;
  123. }
  124. /*++
  125. Name:
  126. GetRingBufferSize()
  127. Description:
  128. Get the size of the ring buffer
  129. --*/
  130. static inline u32
  131. GetRingBufferSize(struct hv_ring_buffer_info *RingInfo)
  132. {
  133. return RingInfo->RingDataSize;
  134. }
  135. /*++
  136. Name:
  137. GetRingBufferIndices()
  138. Description:
  139. Get the read and write indices as u64 of the specified ring buffer
  140. --*/
  141. static inline u64
  142. GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo)
  143. {
  144. return (u64)RingInfo->RingBuffer->WriteIndex << 32;
  145. }
  146. /*++
  147. Name:
  148. DumpRingInfo()
  149. Description:
  150. Dump out to console the ring buffer info
  151. --*/
  152. void DumpRingInfo(struct hv_ring_buffer_info *RingInfo, char *Prefix)
  153. {
  154. u32 bytesAvailToWrite;
  155. u32 bytesAvailToRead;
  156. GetRingBufferAvailBytes(RingInfo,
  157. &bytesAvailToRead,
  158. &bytesAvailToWrite);
  159. DPRINT(VMBUS,
  160. DEBUG_RING_LVL,
  161. "%s <<ringinfo %p buffer %p avail write %u "
  162. "avail read %u read idx %u write idx %u>>",
  163. Prefix,
  164. RingInfo,
  165. RingInfo->RingBuffer->Buffer,
  166. bytesAvailToWrite,
  167. bytesAvailToRead,
  168. RingInfo->RingBuffer->ReadIndex,
  169. RingInfo->RingBuffer->WriteIndex);
  170. }
  171. /* Internal routines */
  172. static u32
  173. CopyToRingBuffer(
  174. struct hv_ring_buffer_info *RingInfo,
  175. u32 StartWriteOffset,
  176. void *Src,
  177. u32 SrcLen);
  178. static u32
  179. CopyFromRingBuffer(
  180. struct hv_ring_buffer_info *RingInfo,
  181. void *Dest,
  182. u32 DestLen,
  183. u32 StartReadOffset);
  184. /*++
  185. Name:
  186. RingBufferGetDebugInfo()
  187. Description:
  188. Get various debug metrics for the specified ring buffer
  189. --*/
  190. void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo,
  191. struct hv_ring_buffer_debug_info *debug_info)
  192. {
  193. u32 bytesAvailToWrite;
  194. u32 bytesAvailToRead;
  195. if (RingInfo->RingBuffer) {
  196. GetRingBufferAvailBytes(RingInfo,
  197. &bytesAvailToRead,
  198. &bytesAvailToWrite);
  199. debug_info->BytesAvailToRead = bytesAvailToRead;
  200. debug_info->BytesAvailToWrite = bytesAvailToWrite;
  201. debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
  202. debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
  203. debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
  204. }
  205. }
  206. /*++
  207. Name:
  208. GetRingBufferInterruptMask()
  209. Description:
  210. Get the interrupt mask for the specified ring buffer
  211. --*/
  212. u32 GetRingBufferInterruptMask(struct hv_ring_buffer_info *rbi)
  213. {
  214. return rbi->RingBuffer->InterruptMask;
  215. }
  216. /*++
  217. Name:
  218. RingBufferInit()
  219. Description:
  220. Initialize the ring buffer
  221. --*/
  222. int RingBufferInit(struct hv_ring_buffer_info *RingInfo, void *Buffer, u32 BufferLen)
  223. {
  224. if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
  225. return -EINVAL;
  226. memset(RingInfo, 0, sizeof(struct hv_ring_buffer_info));
  227. RingInfo->RingBuffer = (struct hv_ring_buffer *)Buffer;
  228. RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
  229. RingInfo->RingSize = BufferLen;
  230. RingInfo->RingDataSize = BufferLen - sizeof(struct hv_ring_buffer);
  231. spin_lock_init(&RingInfo->ring_lock);
  232. return 0;
  233. }
  234. /*++
  235. Name:
  236. RingBufferCleanup()
  237. Description:
  238. Cleanup the ring buffer
  239. --*/
  240. void RingBufferCleanup(struct hv_ring_buffer_info *RingInfo)
  241. {
  242. }
  243. /*++
  244. Name:
  245. RingBufferWrite()
  246. Description:
  247. Write to the ring buffer
  248. --*/
  249. int RingBufferWrite(struct hv_ring_buffer_info *OutRingInfo,
  250. struct scatterlist *sglist, u32 sgcount)
  251. {
  252. int i = 0;
  253. u32 byteAvailToWrite;
  254. u32 byteAvailToRead;
  255. u32 totalBytesToWrite = 0;
  256. struct scatterlist *sg;
  257. volatile u32 nextWriteLocation;
  258. u64 prevIndices = 0;
  259. unsigned long flags;
  260. for_each_sg(sglist, sg, sgcount, i)
  261. {
  262. totalBytesToWrite += sg->length;
  263. }
  264. totalBytesToWrite += sizeof(u64);
  265. spin_lock_irqsave(&OutRingInfo->ring_lock, flags);
  266. GetRingBufferAvailBytes(OutRingInfo,
  267. &byteAvailToRead,
  268. &byteAvailToWrite);
  269. DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
  270. /* DumpRingInfo(OutRingInfo, "BEFORE "); */
  271. /* If there is only room for the packet, assume it is full. */
  272. /* Otherwise, the next time around, we think the ring buffer */
  273. /* is empty since the read index == write index */
  274. if (byteAvailToWrite <= totalBytesToWrite) {
  275. DPRINT_DBG(VMBUS,
  276. "No more space left on outbound ring buffer "
  277. "(needed %u, avail %u)",
  278. totalBytesToWrite,
  279. byteAvailToWrite);
  280. spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
  281. return -1;
  282. }
  283. /* Write to the ring buffer */
  284. nextWriteLocation = GetNextWriteLocation(OutRingInfo);
  285. for_each_sg(sglist, sg, sgcount, i)
  286. {
  287. nextWriteLocation = CopyToRingBuffer(OutRingInfo,
  288. nextWriteLocation,
  289. sg_virt(sg),
  290. sg->length);
  291. }
  292. /* Set previous packet start */
  293. prevIndices = GetRingBufferIndices(OutRingInfo);
  294. nextWriteLocation = CopyToRingBuffer(OutRingInfo,
  295. nextWriteLocation,
  296. &prevIndices,
  297. sizeof(u64));
  298. /* Make sure we flush all writes before updating the writeIndex */
  299. mb();
  300. /* Now, update the write location */
  301. SetNextWriteLocation(OutRingInfo, nextWriteLocation);
  302. /* DumpRingInfo(OutRingInfo, "AFTER "); */
  303. spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags);
  304. return 0;
  305. }
  306. /*++
  307. Name:
  308. RingBufferPeek()
  309. Description:
  310. Read without advancing the read index
  311. --*/
  312. int RingBufferPeek(struct hv_ring_buffer_info *InRingInfo, void *Buffer, u32 BufferLen)
  313. {
  314. u32 bytesAvailToWrite;
  315. u32 bytesAvailToRead;
  316. u32 nextReadLocation = 0;
  317. unsigned long flags;
  318. spin_lock_irqsave(&InRingInfo->ring_lock, flags);
  319. GetRingBufferAvailBytes(InRingInfo,
  320. &bytesAvailToRead,
  321. &bytesAvailToWrite);
  322. /* Make sure there is something to read */
  323. if (bytesAvailToRead < BufferLen) {
  324. /* DPRINT_DBG(VMBUS,
  325. "got callback but not enough to read "
  326. "<avail to read %d read size %d>!!",
  327. bytesAvailToRead,
  328. BufferLen); */
  329. spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
  330. return -1;
  331. }
  332. /* Convert to byte offset */
  333. nextReadLocation = GetNextReadLocation(InRingInfo);
  334. nextReadLocation = CopyFromRingBuffer(InRingInfo,
  335. Buffer,
  336. BufferLen,
  337. nextReadLocation);
  338. spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
  339. return 0;
  340. }
  341. /*++
  342. Name:
  343. RingBufferRead()
  344. Description:
  345. Read and advance the read index
  346. --*/
  347. int RingBufferRead(struct hv_ring_buffer_info *InRingInfo, void *Buffer,
  348. u32 BufferLen, u32 Offset)
  349. {
  350. u32 bytesAvailToWrite;
  351. u32 bytesAvailToRead;
  352. u32 nextReadLocation = 0;
  353. u64 prevIndices = 0;
  354. unsigned long flags;
  355. if (BufferLen <= 0)
  356. return -EINVAL;
  357. spin_lock_irqsave(&InRingInfo->ring_lock, flags);
  358. GetRingBufferAvailBytes(InRingInfo,
  359. &bytesAvailToRead,
  360. &bytesAvailToWrite);
  361. DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
  362. /* DumpRingInfo(InRingInfo, "BEFORE "); */
  363. /* Make sure there is something to read */
  364. if (bytesAvailToRead < BufferLen) {
  365. DPRINT_DBG(VMBUS,
  366. "got callback but not enough to read "
  367. "<avail to read %d read size %d>!!",
  368. bytesAvailToRead,
  369. BufferLen);
  370. spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
  371. return -1;
  372. }
  373. nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
  374. nextReadLocation = CopyFromRingBuffer(InRingInfo,
  375. Buffer,
  376. BufferLen,
  377. nextReadLocation);
  378. nextReadLocation = CopyFromRingBuffer(InRingInfo,
  379. &prevIndices,
  380. sizeof(u64),
  381. nextReadLocation);
  382. /* Make sure all reads are done before we update the read index since */
  383. /* the writer may start writing to the read area once the read index */
  384. /*is updated */
  385. mb();
  386. /* Update the read index */
  387. SetNextReadLocation(InRingInfo, nextReadLocation);
  388. /* DumpRingInfo(InRingInfo, "AFTER "); */
  389. spin_unlock_irqrestore(&InRingInfo->ring_lock, flags);
  390. return 0;
  391. }
  392. /*++
  393. Name:
  394. CopyToRingBuffer()
  395. Description:
  396. Helper routine to copy from source to ring buffer.
  397. Assume there is enough room. Handles wrap-around in dest case only!!
  398. --*/
  399. static u32
  400. CopyToRingBuffer(
  401. struct hv_ring_buffer_info *RingInfo,
  402. u32 StartWriteOffset,
  403. void *Src,
  404. u32 SrcLen)
  405. {
  406. void *ringBuffer = GetRingBuffer(RingInfo);
  407. u32 ringBufferSize = GetRingBufferSize(RingInfo);
  408. u32 fragLen;
  409. /* wrap-around detected! */
  410. if (SrcLen > ringBufferSize - StartWriteOffset) {
  411. DPRINT_DBG(VMBUS, "wrap-around detected!");
  412. fragLen = ringBufferSize - StartWriteOffset;
  413. memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
  414. memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
  415. } else
  416. memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
  417. StartWriteOffset += SrcLen;
  418. StartWriteOffset %= ringBufferSize;
  419. return StartWriteOffset;
  420. }
  421. /*++
  422. Name:
  423. CopyFromRingBuffer()
  424. Description:
  425. Helper routine to copy to source from ring buffer.
  426. Assume there is enough room. Handles wrap-around in src case only!!
  427. --*/
  428. static u32
  429. CopyFromRingBuffer(
  430. struct hv_ring_buffer_info *RingInfo,
  431. void *Dest,
  432. u32 DestLen,
  433. u32 StartReadOffset)
  434. {
  435. void *ringBuffer = GetRingBuffer(RingInfo);
  436. u32 ringBufferSize = GetRingBufferSize(RingInfo);
  437. u32 fragLen;
  438. /* wrap-around detected at the src */
  439. if (DestLen > ringBufferSize - StartReadOffset) {
  440. DPRINT_DBG(VMBUS, "src wrap-around detected!");
  441. fragLen = ringBufferSize - StartReadOffset;
  442. memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
  443. memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
  444. } else
  445. memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
  446. StartReadOffset += DestLen;
  447. StartReadOffset %= ringBufferSize;
  448. return StartReadOffset;
  449. }
  450. /* eof */