pRxNetDescriptor CParaNdisRX::CreateRxDescriptorOnInit() { //For RX packets we allocate following pages // 1 page for virtio header and indirect buffers array // X pages needed to fit maximal length buffer of data // The assumption is virtio header and indirect buffers array fit 1 page ULONG ulNumPages = m_Context->MaxPacketSize.nMaxDataSizeHwRx / PAGE_SIZE + 2; pRxNetDescriptor p = (pRxNetDescriptor)ParaNdis_AllocateMemory(m_Context, sizeof(*p)); if (p == NULL) return NULL; NdisZeroMemory(p, sizeof(*p)); p->BufferSGArray = (struct VirtIOBufferDescriptor *) ParaNdis_AllocateMemory(m_Context, sizeof(*p->BufferSGArray) * ulNumPages); if (p->BufferSGArray == NULL) goto error_exit; p->PhysicalPages = (tCompletePhysicalAddress *) ParaNdis_AllocateMemory(m_Context, sizeof(*p->PhysicalPages) * ulNumPages); if (p->PhysicalPages == NULL) goto error_exit; for (p->PagesAllocated = 0; p->PagesAllocated < ulNumPages; p->PagesAllocated++) { p->PhysicalPages[p->PagesAllocated].size = PAGE_SIZE; if (!InitialAllocatePhysicalMemory(&p->PhysicalPages[p->PagesAllocated])) goto error_exit; p->BufferSGArray[p->PagesAllocated].physAddr = p->PhysicalPages[p->PagesAllocated].Physical; p->BufferSGArray[p->PagesAllocated].length = PAGE_SIZE; } //First page is for virtio header, size needs to be adjusted correspondingly p->BufferSGArray[0].length = m_Context->nVirtioHeaderSize; //Pre-cache indirect area addresses p->IndirectArea.Physical.QuadPart = p->PhysicalPages[0].Physical.QuadPart + m_Context->nVirtioHeaderSize; p->IndirectArea.Virtual = RtlOffsetToPointer(p->PhysicalPages[0].Virtual, m_Context->nVirtioHeaderSize); p->IndirectArea.size = PAGE_SIZE - m_Context->nVirtioHeaderSize; if (!ParaNdis_BindRxBufferToPacket(m_Context, p)) goto error_exit; return p; error_exit: ParaNdis_FreeRxBufferDescriptor(m_Context, p); return NULL; }
pRxNetDescriptor CParaNdisRX::CreateRxDescriptorOnInit() { //For RX packets we allocate following pages // 1 page for virtio header and indirect buffers array // X pages needed to fit maximal length buffer of data // The assumption is virtio header and indirect buffers array fit 1 page ULONG ulNumPages = m_Context->MaxPacketSize.nMaxDataSizeHwRx / PAGE_SIZE + 2; pRxNetDescriptor p = (pRxNetDescriptor)ParaNdis_AllocateMemory(m_Context, sizeof(*p)); if (p == NULL) return NULL; NdisZeroMemory(p, sizeof(*p)); p->BufferSGArray = (struct VirtIOBufferDescriptor *) ParaNdis_AllocateMemory(m_Context, sizeof(*p->BufferSGArray) * ulNumPages); if (p->BufferSGArray == NULL) goto error_exit; p->PhysicalPages = (tCompletePhysicalAddress *) ParaNdis_AllocateMemory(m_Context, sizeof(*p->PhysicalPages) * ulNumPages); if (p->PhysicalPages == NULL) goto error_exit; p->BufferSGLength = 0; while (ulNumPages > 0) { // Allocate the first page separately, the rest can be one contiguous block ULONG ulPagesToAlloc = (p->BufferSGLength == 0 ? 1 : ulNumPages); while (!ParaNdis_InitialAllocatePhysicalMemory( m_Context, PAGE_SIZE * ulPagesToAlloc, &p->PhysicalPages[p->BufferSGLength])) { // Retry with half the pages if (ulPagesToAlloc == 1) goto error_exit; else ulPagesToAlloc /= 2; } p->BufferSGArray[p->BufferSGLength].physAddr = p->PhysicalPages[p->BufferSGLength].Physical; p->BufferSGArray[p->BufferSGLength].length = p->PhysicalPages[p->BufferSGLength].size; ulNumPages -= ulPagesToAlloc; p->BufferSGLength++; } //First page is for virtio header, size needs to be adjusted correspondingly p->BufferSGArray[0].length = m_Context->nVirtioHeaderSize; ULONG indirectAreaOffset = ALIGN_UP(m_Context->nVirtioHeaderSize, ULONGLONG); //Pre-cache indirect area addresses p->IndirectArea.Physical.QuadPart = p->PhysicalPages[0].Physical.QuadPart + indirectAreaOffset; p->IndirectArea.Virtual = RtlOffsetToPointer(p->PhysicalPages[0].Virtual, indirectAreaOffset); p->IndirectArea.size = PAGE_SIZE - indirectAreaOffset; if (!ParaNdis_BindRxBufferToPacket(m_Context, p)) goto error_exit; return p; error_exit: ParaNdis_FreeRxBufferDescriptor(m_Context, p); return NULL; }