2 * This file contains NDIS driver VirtIO callbacks
4 * Copyright (c) 2008-2017 Red Hat, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and / or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of their contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include "ndis56common.h"
31 /////////////////////////////////////////////////////////////////////////////////////
33 // ReadVirtIODeviceRegister\WriteVirtIODeviceRegister
34 // NDIS specific implementation of the IO and memory space read\write
36 // The lower 64k of memory is never mapped so we can use the same routines
37 // for both port I/O and memory access and use the address alone to decide
38 // which space to use.
39 /////////////////////////////////////////////////////////////////////////////////////
41 #define PORT_MASK 0xFFFF
43 static u32
ReadVirtIODeviceRegister(ULONG_PTR ulRegister
)
47 if (ulRegister
& ~PORT_MASK
) {
48 NdisReadRegisterUlong(ulRegister
, &ulValue
);
50 NdisRawReadPortUlong(ulRegister
, &ulValue
);
53 DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__
, (ULONG
)ulRegister
, ulValue
));
57 static void WriteVirtIODeviceRegister(ULONG_PTR ulRegister
, u32 ulValue
)
59 DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__
, (ULONG
)ulRegister
, ulValue
));
61 if (ulRegister
& ~PORT_MASK
) {
62 NdisWriteRegisterUlong((PULONG
)ulRegister
, ulValue
);
64 NdisRawWritePortUlong(ulRegister
, ulValue
);
68 static u8
ReadVirtIODeviceByte(ULONG_PTR ulRegister
)
72 if (ulRegister
& ~PORT_MASK
) {
73 NdisReadRegisterUchar(ulRegister
, &bValue
);
75 NdisRawReadPortUchar(ulRegister
, &bValue
);
78 DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__
, (ULONG
)ulRegister
, bValue
));
82 static void WriteVirtIODeviceByte(ULONG_PTR ulRegister
, u8 bValue
)
84 DPrintf(6, ("[%s]R[%x]=%x", __FUNCTION__
, (ULONG
)ulRegister
, bValue
));
86 if (ulRegister
& ~PORT_MASK
) {
87 NdisWriteRegisterUchar((PUCHAR
)ulRegister
, bValue
);
89 NdisRawWritePortUchar(ulRegister
, bValue
);
93 static u16
ReadVirtIODeviceWord(ULONG_PTR ulRegister
)
97 if (ulRegister
& ~PORT_MASK
) {
98 NdisReadRegisterUshort(ulRegister
, &wValue
);
100 NdisRawReadPortUshort(ulRegister
, &wValue
);
103 DPrintf(6, ("[%s]R[%x]=%x\n", __FUNCTION__
, (ULONG
)ulRegister
, wValue
));
107 static void WriteVirtIODeviceWord(ULONG_PTR ulRegister
, u16 wValue
)
110 if (ulRegister
& ~PORT_MASK
) {
111 NdisWriteRegisterUshort((PUSHORT
)ulRegister
, wValue
);
113 NdisRawWritePortUshort(ulRegister
, wValue
);
116 // test only to cause long TX waiting queue of NDIS packets
117 // to recognize it and request for reset via Hang handler
118 static int nCounterToFail
= 0;
119 static const int StartFail
= 200, StopFail
= 600;
120 BOOLEAN bFail
= FALSE
;
121 DPrintf(6, ("%s> R[%x] = %x\n", __FUNCTION__
, (ULONG
)ulRegister
, wValue
));
122 if ((ulRegister
& 0x1F) == 0x10)
125 bFail
= nCounterToFail
>= StartFail
&& nCounterToFail
< StopFail
;
127 if (!bFail
) NdisRawWritePortUshort(ulRegister
, wValue
);
130 DPrintf(0, ("%s> FAILING R[%x] = %x\n", __FUNCTION__
, (ULONG
)ulRegister
, wValue
));
135 static void *mem_alloc_contiguous_pages(void *context
, size_t size
)
137 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
141 /* find the first unused memory range of the requested size */
142 for (i
= 0; i
< MAX_NUM_OF_QUEUES
; i
++) {
143 if (pContext
->SharedMemoryRanges
[i
].pBase
!= NULL
&&
144 pContext
->SharedMemoryRanges
[i
].bUsed
== FALSE
&&
145 pContext
->SharedMemoryRanges
[i
].uLength
== (ULONG
)size
) {
146 retVal
= pContext
->SharedMemoryRanges
[i
].pBase
;
147 pContext
->SharedMemoryRanges
[i
].bUsed
= TRUE
;
153 /* find the first null memory range descriptor and allocate */
154 for (i
= 0; i
< MAX_NUM_OF_QUEUES
; i
++) {
155 if (pContext
->SharedMemoryRanges
[i
].pBase
== NULL
) {
159 if (i
< MAX_NUM_OF_QUEUES
) {
160 NdisMAllocateSharedMemory(
161 pContext
->MiniportHandle
,
164 &pContext
->SharedMemoryRanges
[i
].pBase
,
165 &pContext
->SharedMemoryRanges
[i
].BasePA
);
166 retVal
= pContext
->SharedMemoryRanges
[i
].pBase
;
168 NdisZeroMemory(retVal
, size
);
169 pContext
->SharedMemoryRanges
[i
].uLength
= (ULONG
)size
;
170 pContext
->SharedMemoryRanges
[i
].bUsed
= TRUE
;
176 DPrintf(6, ("[%s] returning %p, size %x\n", __FUNCTION__
, retVal
, (ULONG
)size
));
178 DPrintf(0, ("[%s] failed to allocate size %x\n", __FUNCTION__
, (ULONG
)size
));
183 static void mem_free_contiguous_pages(void *context
, void *virt
)
185 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
188 for (i
= 0; i
< MAX_NUM_OF_QUEUES
; i
++) {
189 if (pContext
->SharedMemoryRanges
[i
].pBase
== virt
) {
190 pContext
->SharedMemoryRanges
[i
].bUsed
= FALSE
;
195 if (i
< MAX_NUM_OF_QUEUES
) {
196 DPrintf(6, ("[%s] freed %p at index %d\n", __FUNCTION__
, virt
, i
));
198 DPrintf(0, ("[%s] failed to free %p\n", __FUNCTION__
, virt
));
202 static ULONGLONG
mem_get_physical_address(void *context
, void *virt
)
204 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
205 ULONG_PTR uAddr
= (ULONG_PTR
)virt
;
208 for (i
= 0; i
< MAX_NUM_OF_QUEUES
; i
++) {
209 ULONG_PTR uBase
= (ULONG_PTR
)pContext
->SharedMemoryRanges
[i
].pBase
;
210 if (uAddr
>= uBase
&& uAddr
< (uBase
+ pContext
->SharedMemoryRanges
[i
].uLength
)) {
211 ULONGLONG retVal
= pContext
->SharedMemoryRanges
[i
].BasePA
.QuadPart
+ (uAddr
- uBase
);
213 DPrintf(6, ("[%s] translated %p to %I64X\n", __FUNCTION__
, virt
, retVal
));
218 DPrintf(0, ("[%s] failed to translate %p\n", __FUNCTION__
, virt
));
222 static void *mem_alloc_nonpaged_block(void *context
, size_t size
)
226 if (NdisAllocateMemoryWithTag(
229 PARANDIS_MEMORY_TAG
) != NDIS_STATUS_SUCCESS
) {
234 NdisZeroMemory(retVal
, size
);
235 DPrintf(6, ("[%s] returning %p, len %x\n", __FUNCTION__
, retVal
, (ULONG
)size
));
237 DPrintf(0, ("[%s] failed to allocate size %x\n", __FUNCTION__
, (ULONG
)size
));
242 static void mem_free_nonpaged_block(void *context
, void *addr
)
244 UNREFERENCED_PARAMETER(context
);
246 NdisFreeMemory(addr
, 0, 0);
247 DPrintf(6, ("[%s] freed %p\n", __FUNCTION__
, addr
));
250 static int PCIReadConfig(PPARANDIS_ADAPTER pContext
,
257 read
= NdisReadPciSlotInformation(
258 pContext
->MiniportHandle
,
264 if (read
== length
) {
265 DPrintf(6, ("[%s] read %d bytes at %d\n", __FUNCTION__
, read
, where
));
268 DPrintf(0, ("[%s] failed to read %d bytes at %d\n", __FUNCTION__
, read
, where
));
273 static int pci_read_config_byte(void *context
, int where
, u8
*bVal
)
275 return PCIReadConfig((PPARANDIS_ADAPTER
)context
, where
, bVal
, sizeof(*bVal
));
278 static int pci_read_config_word(void *context
, int where
, u16
*wVal
)
280 return PCIReadConfig((PPARANDIS_ADAPTER
)context
, where
, wVal
, sizeof(*wVal
));
283 static int pci_read_config_dword(void *context
, int where
, u32
*dwVal
)
285 return PCIReadConfig((PPARANDIS_ADAPTER
)context
, where
, dwVal
, sizeof(*dwVal
));
288 static size_t pci_get_resource_len(void *context
, int bar
)
290 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
292 if (bar
< PCI_TYPE0_ADDRESSES
) {
293 return pContext
->AdapterResources
.PciBars
[bar
].uLength
;
296 DPrintf(0, ("[%s] queried invalid BAR %d\n", __FUNCTION__
, bar
));
300 static void *pci_map_address_range(void *context
, int bar
, size_t offset
, size_t maxlen
)
302 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
304 if (bar
< PCI_TYPE0_ADDRESSES
) {
305 tBusResource
*pRes
= &pContext
->AdapterResources
.PciBars
[bar
];
306 if (pRes
->pBase
== NULL
) {
307 /* BAR not mapped yet */
308 if (pRes
->bPortSpace
) {
309 if (NDIS_STATUS_SUCCESS
== NdisMRegisterIoPortRange(
311 pContext
->MiniportHandle
,
312 pRes
->BasePA
.LowPart
,
314 DPrintf(6, ("[%s] mapped port BAR at %x\n", __FUNCTION__
, pRes
->BasePA
.LowPart
));
317 DPrintf(0, ("[%s] failed to map port BAR at %x\n", __FUNCTION__
, pRes
->BasePA
.LowPart
));
320 if (NDIS_STATUS_SUCCESS
== NdisMMapIoSpace(
322 pContext
->MiniportHandle
,
325 DPrintf(6, ("[%s] mapped memory BAR at %I64x\n", __FUNCTION__
, pRes
->BasePA
.QuadPart
));
328 DPrintf(0, ("[%s] failed to map memory BAR at %I64x\n", __FUNCTION__
, pRes
->BasePA
.QuadPart
));
332 if (pRes
->pBase
!= NULL
&& offset
< pRes
->uLength
) {
333 if (pRes
->bPortSpace
) {
334 /* use physical address for port I/O */
335 return (PUCHAR
)(ULONG_PTR
)pRes
->BasePA
.LowPart
+ offset
;
337 /* use virtual address for memory I/O */
338 return (PUCHAR
)pRes
->pBase
+ offset
;
341 DPrintf(0, ("[%s] failed to get map BAR %d, offset %x\n", __FUNCTION__
, bar
, offset
));
344 DPrintf(0, ("[%s] queried invalid BAR %d\n", __FUNCTION__
, bar
));
350 static u16
vdev_get_msix_vector(void *context
, int queue
)
352 PARANDIS_ADAPTER
*pContext
= (PARANDIS_ADAPTER
*)context
;
353 u16 vector
= VIRTIO_MSI_NO_VECTOR
;
355 /* we don't run on MSI support so this will never be true */
356 if (pContext
->bUsingMSIX
&& queue
>= 0) {
357 vector
= (u16
)pContext
->AdapterResources
.Vector
;
363 static void vdev_sleep(void *context
, unsigned int msecs
)
365 UNREFERENCED_PARAMETER(context
);
367 NdisMSleep(1000 * msecs
);
370 VirtIOSystemOps ParaNdisSystemOps
= {
371 /* .vdev_read_byte = */ ReadVirtIODeviceByte
,
372 /* .vdev_read_word = */ ReadVirtIODeviceWord
,
373 /* .vdev_read_dword = */ ReadVirtIODeviceRegister
,
374 /* .vdev_write_byte = */ WriteVirtIODeviceByte
,
375 /* .vdev_write_word = */ WriteVirtIODeviceWord
,
376 /* .vdev_write_dword = */ WriteVirtIODeviceRegister
,
377 /* .mem_alloc_contiguous_pages = */ mem_alloc_contiguous_pages
,
378 /* .mem_free_contiguous_pages = */ mem_free_contiguous_pages
,
379 /* .mem_get_physical_address = */ mem_get_physical_address
,
380 /* .mem_alloc_nonpaged_block = */ mem_alloc_nonpaged_block
,
381 /* .mem_free_nonpaged_block = */ mem_free_nonpaged_block
,
382 /* .pci_read_config_byte = */ pci_read_config_byte
,
383 /* .pci_read_config_word = */ pci_read_config_word
,
384 /* .pci_read_config_dword = */ pci_read_config_dword
,
385 /* .pci_get_resource_len = */ pci_get_resource_len
,
386 /* .pci_map_address_range = */ pci_map_address_range
,
387 /* .vdev_get_msix_vector = */ vdev_get_msix_vector
,
388 /*.vdev_sleep = */ vdev_sleep
,