Exemplo n.º 1
1
static struct virtqueue * FindVirtualQueue(VirtIODevice *dev, ULONG index, USHORT vector)
{
    struct virtqueue *pq = NULL;
    PVOID p;
    ULONG size, allocSize;
    VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize);
    if (allocSize)
    {
        PHYSICAL_ADDRESS HighestAcceptable;
        HighestAcceptable.QuadPart = 0xFFFFFFFFFF;
        p = MmAllocateContiguousMemory(allocSize, HighestAcceptable);
        if (p)
        {
            pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE);

            if (vector != VIRTIO_MSI_NO_VECTOR)
            {
                WriteVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR, vector);
                vector = ReadVirtIODeviceWord(dev->addr + VIRTIO_MSI_QUEUE_VECTOR);
            }
        }
    }
    return pq;
}
static NDIS_STATUS SetInterruptMessage(PARANDIS_ADAPTER *pContext, UINT queueIndex)
{
    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
    ULONG val;
    ULONG  messageIndex = queueIndex < pContext->pMSIXInfoTable->MessageCount ?
        queueIndex : (pContext->pMSIXInfoTable->MessageCount - 1);
    PULONG pMessage = NULL;
    switch (queueIndex)
    {
    case 0: // Rx queue interrupt:
        WriteVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_PCI_QUEUE_SEL, (u16)queueIndex);
        WriteVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_QUEUE_VECTOR, (u16)messageIndex);
        val = ReadVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_QUEUE_VECTOR);
        pMessage = &pContext->ulRxMessage;
        break;
    case 1: // Tx queue interrupt:
        WriteVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_PCI_QUEUE_SEL, (u16)queueIndex);
        WriteVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_QUEUE_VECTOR, (u16)messageIndex);
        val = ReadVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_QUEUE_VECTOR);
        pMessage = &pContext->ulTxMessage;
        break;
    case 2: // config interrupt
        WriteVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_CONFIG_VECTOR, (u16)messageIndex);
        val = ReadVirtIODeviceWord(pContext->IODevice.addr + VIRTIO_MSI_CONFIG_VECTOR);
        pMessage = &pContext->ulControlMessage;
        break;
    default:
        val = (ULONG)-1;
        break;
    }

    if (val != messageIndex)
    {
        DPrintf(0, ("[%s] ERROR: Wrong MSI-X message for q%d(w%X,r%X)!\n", __FUNCTION__, queueIndex, messageIndex, val));
        status = NDIS_STATUS_DEVICE_FAILED;
    }
    if (pMessage) *pMessage = messageIndex;
    return status;
}
NDIS_STATUS CParaNdisAbstractPath::SetupMessageIndex(u16 queueCardinal)
{
    u16 val;

    WriteVirtIODeviceWord(m_Context->IODevice->addr + VIRTIO_PCI_QUEUE_SEL, (u16)queueCardinal);
    WriteVirtIODeviceWord(m_Context->IODevice->addr + VIRTIO_MSI_QUEUE_VECTOR, (u16)queueCardinal);
    val = ReadVirtIODeviceWord(m_Context->IODevice->addr + VIRTIO_MSI_QUEUE_VECTOR);
    if (val != queueCardinal)
    {
        DPrintf(0, ("[%s] - read/write mismatch, %u vs %u\n", val, queueCardinal));
        return NDIS_STATUS_DEVICE_FAILED;
    }

    m_messageIndex = queueCardinal;
    return NDIS_STATUS_SUCCESS;
}
Exemplo n.º 4
0
NTSTATUS
VIOSerialEvtDevicePrepareHardware(
    IN WDFDEVICE Device,
    IN WDFCMRESLIST ResourcesRaw,
    IN WDFCMRESLIST ResourcesTranslated)
{
    int nListSize = 0;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor;
    int i = 0;
    PPORTS_DEVICE pContext = GetPortsDevice(Device);
    bool bPortFound = FALSE;
    NTSTATUS status = STATUS_SUCCESS;
    UINT nr_ports, max_queues, size_to_allocate;
    BOOLEAN MessageSignaled = FALSE;
    USHORT Interrupts = 0;
    u32 u32HostFeatures;
    u32 u32GuestFeatures = 0;

    UNREFERENCED_PARAMETER(ResourcesRaw);
    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__);

    max_queues = 64; // 2 for each of max 32 ports
    size_to_allocate = VirtIODeviceSizeRequired((USHORT)max_queues);

    pContext->pIODevice = (VirtIODevice *)ExAllocatePoolWithTag(
                                 NonPagedPool,
                                 size_to_allocate,
                                 VIOSERIAL_DRIVER_MEMORY_TAG);
    if (NULL == pContext->pIODevice)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    nListSize = WdfCmResourceListGetCount(ResourcesTranslated);

    for (i = 0; i < nListSize; i++)
    {
        if(pResDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i))
        {
            switch(pResDescriptor->Type)
            {
                case CmResourceTypePort :
                    pContext->bPortMapped = (pResDescriptor->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE;
                    pContext->PortBasePA = pResDescriptor->u.Port.Start;
                    pContext->uPortLength = pResDescriptor->u.Port.Length;
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IO Port Info  [%08I64X-%08I64X]\n",
                                 pResDescriptor->u.Port.Start.QuadPart,
                                 pResDescriptor->u.Port.Start.QuadPart +
                                 pResDescriptor->u.Port.Length);

                    if (pContext->bPortMapped )
                    {
                        pContext->pPortBase = MmMapIoSpace(pContext->PortBasePA,
                                                           pContext->uPortLength,
                                                           MmNonCached);

                        if (!pContext->pPortBase) {
                            TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> Failed to map IO port!\n", __FUNCTION__);
                            return STATUS_INSUFFICIENT_RESOURCES;
                        }
                    }
                    else
                    {
                        pContext->pPortBase = (PVOID)(ULONG_PTR)pContext->PortBasePA.QuadPart;
                    }

                    bPortFound = TRUE;

                    break;
                case CmResourceTypeInterrupt:
                    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT,
                        "Interrupt Level: 0x%08x, Vector: 0x%08x\n",
                        pResDescriptor->u.Interrupt.Level,
                        pResDescriptor->u.Interrupt.Vector);
                    Interrupts += 1;
                    MessageSignaled = !!(pResDescriptor->Flags &
                        (CM_RESOURCE_INTERRUPT_LATCHED | CM_RESOURCE_INTERRUPT_MESSAGE));
                    break;
            }
        }
    }

    if(!bPortFound)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> %s", __FUNCTION__, "IO port wasn't found!\n");
        return STATUS_DEVICE_CONFIGURATION_ERROR;
    }

    VirtIODeviceInitialize(pContext->pIODevice, (ULONG_PTR)pContext->pPortBase, size_to_allocate);
    VirtIODeviceSetMSIXUsed(pContext->pIODevice, MessageSignaled);
    VirtIODeviceReset(pContext->pIODevice);
    VirtIODeviceAddStatus(pContext->pIODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE);

    if (MessageSignaled)
    {
        WriteVirtIODeviceWord(
            pContext->pIODevice->addr + VIRTIO_MSI_CONFIG_VECTOR, Interrupts);
        Interrupts = ReadVirtIODeviceWord(
            pContext->pIODevice->addr + VIRTIO_MSI_CONFIG_VECTOR);
    }
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
        "MessageSignaled: %d Interrupts: %x.\n",
        MessageSignaled, Interrupts);

    pContext->consoleConfig.max_nr_ports = 1;

    u32HostFeatures = VirtIODeviceReadHostFeatures(pContext->pIODevice);

    if(pContext->isHostMultiport = VirtIOIsFeatureEnabled(u32HostFeatures, VIRTIO_CONSOLE_F_MULTIPORT))
    {
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "We have multiport host\n");
        VirtIOFeatureEnable(u32GuestFeatures, VIRTIO_CONSOLE_F_MULTIPORT);
        VirtIODeviceGet(pContext->pIODevice,
                                 FIELD_OFFSET(CONSOLE_CONFIG, max_nr_ports),
                                 &pContext->consoleConfig.max_nr_ports,
                                 sizeof(pContext->consoleConfig.max_nr_ports));
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                                "VirtIOConsoleConfig->max_nr_ports %d\n", pContext->consoleConfig.max_nr_ports);
        if (pContext->consoleConfig.max_nr_ports > pContext->pIODevice->maxQueues / 2)
        {
           pContext->consoleConfig.max_nr_ports = pContext->pIODevice->maxQueues / 2;
           TraceEvents(TRACE_LEVEL_WARNING, DBG_PNP,
                                "VirtIOConsoleConfig->max_nr_ports limited to %d\n", pContext->consoleConfig.max_nr_ports);
        }
    }
    VirtIODeviceWriteGuestFeatures(pContext->pIODevice, u32GuestFeatures);

    if(pContext->isHostMultiport)
    {
        WDF_OBJECT_ATTRIBUTES  attributes;
        WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
        attributes.ParentObject = Device;
        status = WdfSpinLockCreate(
                                &attributes,
                                &pContext->CVqLock
                                );
        if (!NT_SUCCESS(status))
        {
           TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
                "WdfSpinLockCreate failed 0x%x\n", status);
           return status;
        }
    }
    else
    {
//FIXME
//        VIOSerialAddPort(Device, 0);
    }

    nr_ports = pContext->consoleConfig.max_nr_ports;
    pContext->in_vqs = (struct virtqueue**)ExAllocatePoolWithTag(
                                 NonPagedPool,
                                 nr_ports * sizeof(struct virtqueue*),
                                 VIOSERIAL_DRIVER_MEMORY_TAG);

    if(pContext->in_vqs == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,"ExAllocatePoolWithTag failed\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    memset(pContext->in_vqs, 0, nr_ports * sizeof(struct virtqueue*));
    pContext->out_vqs = (struct virtqueue**)ExAllocatePoolWithTag(
                                 NonPagedPool,
                                 nr_ports * sizeof(struct virtqueue*),
                                 VIOSERIAL_DRIVER_MEMORY_TAG
                                 );

    if(pContext->out_vqs == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "ExAllocatePoolWithTag failed\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    memset(pContext->out_vqs, 0, nr_ports * sizeof(struct virtqueue*));

    pContext->DeviceOK = TRUE;
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__);
    return status;
}