int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo, struct scatterlist *sglist, u32 sgcount) { int i = 0; u32 byteAvailToWrite; u32 byteAvailToRead; u32 totalBytesToWrite = 0; struct scatterlist *sg; volatile u32 nextWriteLocation; u64 prevIndices = 0; unsigned long flags; DPRINT_ENTER(VMBUS); for_each_sg(sglist, sg, sgcount, i) { totalBytesToWrite += sg->length; } totalBytesToWrite += sizeof(u64); spin_lock_irqsave(&OutRingInfo->ring_lock, flags); GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); /* DumpRingInfo(OutRingInfo, "BEFORE "); */ /* If there is only room for the packet, assume it is full. */ /* Otherwise, the next time around, we think the ring buffer */ /* is empty since the read index == write index */ if (byteAvailToWrite <= totalBytesToWrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer " "(needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); DPRINT_EXIT(VMBUS); return -1; } /* Write to the ring buffer */ nextWriteLocation = GetNextWriteLocation(OutRingInfo); for_each_sg(sglist, sg, sgcount, i) { nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, sg_virt(sg), sg->length); }
/*++ Name: RingBufferRead() Description: Read and advance the read index --*/ int RingBufferRead( RING_BUFFER_INFO* InRingInfo, PVOID Buffer, UINT32 BufferLen, UINT32 Offset ) { UINT32 bytesAvailToWrite; UINT32 bytesAvailToRead; UINT32 nextReadLocation=0; UINT64 prevIndices=0; ASSERT(BufferLen > 0); SpinlockAcquire(InRingInfo->RingLock); GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen); //DumpRingInfo(InRingInfo, "BEFORE "); // Make sure there is something to read if (bytesAvailToRead < BufferLen ) { DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); SpinlockRelease(InRingInfo->RingLock); return -1; } nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset); nextReadLocation = CopyFromRingBuffer(InRingInfo, Buffer, BufferLen, nextReadLocation); nextReadLocation = CopyFromRingBuffer(InRingInfo, &prevIndices, sizeof(UINT64), nextReadLocation); // Make sure all reads are done before we update the read index since // the writer may start writing to the read area once the read index is updated MemoryFence(); // Update the read index SetNextReadLocation(InRingInfo, nextReadLocation); //DumpRingInfo(InRingInfo, "AFTER "); SpinlockRelease(InRingInfo->RingLock); return 0; }
int RingBufferWrite(RING_BUFFER_INFO *OutRingInfo, struct scatterlist *sglist, u32 sgcount) { int i=0; u32 byteAvailToWrite; u32 byteAvailToRead; u32 totalBytesToWrite=0; struct scatterlist *sg; volatile u32 nextWriteLocation; u64 prevIndices=0; unsigned long flags; DPRINT_ENTER(VMBUS); for_each_sg(sglist, sg, sgcount, i) { totalBytesToWrite += sg->length; } totalBytesToWrite += sizeof(u64); spin_lock_irqsave(&OutRingInfo->ring_lock, flags); GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); if (byteAvailToWrite <= totalBytesToWrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); spin_unlock_irqrestore(&OutRingInfo->ring_lock, flags); DPRINT_EXIT(VMBUS); return -1; } nextWriteLocation = GetNextWriteLocation(OutRingInfo); for_each_sg(sglist, sg, sgcount, i) { nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, sg_virt(sg), sg->length); }
/*++ Name: DumpRingInfo() Description: Dump out to console the ring buffer info --*/ void DumpRingInfo(RING_BUFFER_INFO *RingInfo, char *Prefix) { u32 bytesAvailToWrite; u32 bytesAvailToRead; GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>", Prefix, RingInfo, RingInfo->RingBuffer->Buffer, bytesAvailToWrite, bytesAvailToRead, RingInfo->RingBuffer->ReadIndex, RingInfo->RingBuffer->WriteIndex); }
/*++ Name: RingBufferGetDebugInfo() Description: Get various debug metrics for the specified ring buffer --*/ void RingBufferGetDebugInfo(RING_BUFFER_INFO *RingInfo, RING_BUFFER_DEBUG_INFO *DebugInfo) { u32 bytesAvailToWrite; u32 bytesAvailToRead; if (RingInfo->RingBuffer) { GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); DebugInfo->BytesAvailToRead = bytesAvailToRead; DebugInfo->BytesAvailToWrite = bytesAvailToWrite; DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; } }
/*++ Name: RingBufferGetDebugInfo() Description: Get various debug metrics for the specified ring buffer --*/ void RingBufferGetDebugInfo(struct hv_ring_buffer_info *RingInfo, struct hv_ring_buffer_debug_info *debug_info) { u32 bytesAvailToWrite; u32 bytesAvailToRead; if (RingInfo->RingBuffer) { GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite); debug_info->BytesAvailToRead = bytesAvailToRead; debug_info->BytesAvailToWrite = bytesAvailToWrite; debug_info->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex; debug_info->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex; debug_info->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask; } }
/*++ Name: RingBufferPeek() Description: Read without advancing the read index --*/ int RingBufferPeek( RING_BUFFER_INFO* InRingInfo, void* Buffer, UINT32 BufferLen ) { UINT32 bytesAvailToWrite; UINT32 bytesAvailToRead; UINT32 nextReadLocation=0; SpinlockAcquire(InRingInfo->RingLock); GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite); // Make sure there is something to read if (bytesAvailToRead < BufferLen ) { //DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen); SpinlockRelease(InRingInfo->RingLock); return -1; } // Convert to byte offset nextReadLocation = GetNextReadLocation(InRingInfo); nextReadLocation = CopyFromRingBuffer(InRingInfo, Buffer, BufferLen, nextReadLocation); SpinlockRelease(InRingInfo->RingLock); return 0; }
int RingBufferCheck(RING_BUFFER_INFO *rbi) { #if 1 UINT32 ri, wi, len; // Capture the read/write indices before they changed ri = rbi->RingBuffer->ReadIndex; wi = rbi->RingBuffer->WriteIndex; len = (ri <= wi) ? (wi - ri) : (rbi->RingDataSize - (ri - wi)); if (len < sizeof(VMPACKET_DESCRIPTOR)) return 0; _PREFETCHT0(rbi->RingBuffer->Buffer + ri); #if 0 if (ri <= wi) { /* no wrap */ while (len > 0) { _PREFETCHT0(rbi->RingBuffer->Buffer + ri); len -= 128; ri += 128; } } else { /* wrap */ while (ri < rbi->RingDataSize) { _PREFETCHT0(rbi->RingBuffer->Buffer + ri); len -= 128; ri += 128; } ri = 0; while (len > 0) { _PREFETCHT0(rbi->RingBuffer->Buffer + ri); len -= 128; ri += 128; } } #endif return 1; #else UINT32 toRead = 0; UINT32 toWrite; UINT32 addr; int i; GetRingBufferAvailBytes(rbi, &toRead, &toWrite); if (toRead < sizeof(VMPACKET_DESCRIPTOR)) return 0; else { r = rbi->Ringbuffer; rdindx = r->ReadIndex; addr = r->Buffer + rdindx; toRead += (addr & 0x~07f); addr &= ~0x7f; if (toRead > r->size - rdindx) { end = buf + size; for(;addr < end; ) { _PREFETCHT0(addr & ~0x7f); addr += 128; } } else { _PREFETCH0(addr & ~0x7f); } return 1; } #endif }
/*++ Name: RingBufferWrite() Description: Write to the ring buffer --*/ int RingBufferWrite( RING_BUFFER_INFO* OutRingInfo, SG_BUFFER_LIST SgBuffers[], UINT32 SgBufferCount ) { int i=0; UINT32 byteAvailToWrite; UINT32 byteAvailToRead; UINT32 totalBytesToWrite=0; volatile UINT32 nextWriteLocation; UINT64 prevIndices=0; DPRINT_ENTER(VMBUS); for (i=0; i < SgBufferCount; i++) { totalBytesToWrite += SgBuffers[i].Length; } totalBytesToWrite += sizeof(UINT64); SpinlockAcquire(OutRingInfo->RingLock); GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite); DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite); //DumpRingInfo(OutRingInfo, "BEFORE "); // If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer // is empty since the read index == write index if (byteAvailToWrite <= totalBytesToWrite) { DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite); SpinlockRelease(OutRingInfo->RingLock); DPRINT_EXIT(VMBUS); return -1; } // Write to the ring buffer nextWriteLocation = GetNextWriteLocation(OutRingInfo); for (i=0; i < SgBufferCount; i++) { nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, SgBuffers[i].Data, SgBuffers[i].Length); } // Set previous packet start prevIndices = GetRingBufferIndices(OutRingInfo); nextWriteLocation = CopyToRingBuffer(OutRingInfo, nextWriteLocation, &prevIndices, sizeof(UINT64)); // Make sure we flush all writes before updating the writeIndex MemoryFence(); // Now, update the write location SetNextWriteLocation(OutRingInfo, nextWriteLocation); //DumpRingInfo(OutRingInfo, "AFTER "); SpinlockRelease(OutRingInfo->RingLock); DPRINT_EXIT(VMBUS); return 0; }