mirror of
https://github.com/apache/nuttx.git
synced 2026-06-07 09:18:00 +08:00
pcie: add framework
Squashed commits: 1. x86_64: qemu: implement pci-e functions and enumerate pci-e devices on boot 2. virt: add qemu pci-testdev driver 3. pcie: types array should be null terminated 4. pcie: enable don't take flags, hardcoded enabling flags 5. pcie: checking bar > 4 for 64bit bars are sufficient 6. pcie: qemu: remove not used header 7. pcie: qemu: return -EINVAL if buffer argument is NULL 8. pcie: make pcie enumerate routine as common instead of architecture dependent 9. pcie: cosmetic changes to fit check tools 10. pcie: create MSI/MSIX related marcos and simplify the msi/msix routines
This commit is contained in:
committed by
Xiang Xiao
parent
204f4a18a0
commit
18f97bf2f8
@@ -2,3 +2,11 @@
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
#
|
||||
config QEMU_PCIE
|
||||
bool "Initialize and enumerate PCI-E Bus"
|
||||
default n
|
||||
select PCIE
|
||||
|
||||
---help---
|
||||
Enables initialization and scaning of standard x86-64 pcie bus.
|
||||
|
||||
@@ -66,6 +66,8 @@ extern "C"
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void qemu_pcie_init(void);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -26,4 +26,8 @@ ifeq ($(CONFIG_BOARDCTL),y)
|
||||
CSRCS += qemu_appinit.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_QEMU_PCIE),y)
|
||||
CSRCS += qemu_pcie.c
|
||||
endif
|
||||
|
||||
include $(TOPDIR)/boards/Board.mk
|
||||
|
||||
@@ -66,6 +66,12 @@ void x86_64_boardinitialize(void)
|
||||
uart_putreg(CONFIG_16550_UART1_BASE, UART_MCR_OFFSET, UART_MCR_OUT2);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_QEMU_PCIE
|
||||
/* Initialization of system */
|
||||
|
||||
qemu_pcie_init();
|
||||
#endif
|
||||
|
||||
/* Configure on-board LEDs if LED support has been selected. */
|
||||
|
||||
#ifdef CONFIG_ARCH_LEDS
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
/****************************************************************************
|
||||
* boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* The MSI and MSI-X vector setup function are taken from Jailhouse inmate
|
||||
* library
|
||||
*
|
||||
* Jailhouse, a Linux-based partitioning hypervisor
|
||||
*
|
||||
* Copyright (c) Siemens AG, 2014
|
||||
*
|
||||
* Authors:
|
||||
* Jan Kiszka <jan.kiszka@siemens.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Alternatively, you can use or redistribute this file under the following
|
||||
* BSD license:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/pcie/pcie.h>
|
||||
|
||||
#include "qemu_pcie_readwrite.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions Definitions
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_cfg_write(FAR struct pcie_dev_s *dev, uintptr_t addr,
|
||||
FAR const void *buffer, unsigned int size);
|
||||
|
||||
static int qemu_pci_cfg_read(FAR struct pcie_dev_s *dev, uintptr_t addr,
|
||||
FAR void *buffer, unsigned int size);
|
||||
|
||||
static int qemu_pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t addr,
|
||||
unsigned long length);
|
||||
|
||||
static int qemu_pci_map_bar64(FAR struct pcie_dev_s *dev, uint64_t addr,
|
||||
unsigned long length);
|
||||
|
||||
static int qemu_pci_msix_register(FAR struct pcie_dev_s *dev,
|
||||
uint32_t vector, uint32_t index);
|
||||
|
||||
static int qemu_pci_msi_register(FAR struct pcie_dev_s *dev,
|
||||
uint16_t vector);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
struct pcie_bus_ops_s qemu_pcie_bus_ops =
|
||||
{
|
||||
.pci_cfg_write = qemu_pci_cfg_write,
|
||||
.pci_cfg_read = qemu_pci_cfg_read,
|
||||
.pci_map_bar = qemu_pci_map_bar,
|
||||
.pci_map_bar64 = qemu_pci_map_bar64,
|
||||
.pci_msix_register = qemu_pci_msix_register,
|
||||
.pci_msi_register = qemu_pci_msi_register,
|
||||
};
|
||||
|
||||
struct pcie_bus_s qemu_pcie_bus =
|
||||
{
|
||||
.ops = &qemu_pcie_bus_ops,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_cfg_write
|
||||
*
|
||||
* Description:
|
||||
* Write 8, 16, 32, 64 bits data to PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* bdf - Device private data
|
||||
* buffer - A pointer to the read-only buffer of data to be written
|
||||
* size - The number of bytes to send from the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_cfg_write(FAR struct pcie_dev_s *dev, uintptr_t addr,
|
||||
FAR const void *buffer, unsigned int size)
|
||||
{
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
return __qemu_pci_cfg_write(dev->bdf, addr, buffer, size);
|
||||
case 8:
|
||||
return __qemu_pci_cfg_write(dev->bdf, addr, buffer, size);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_cfg_read
|
||||
*
|
||||
* Description:
|
||||
* Read 8, 16, 32, 64 bits data from PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device private data
|
||||
* buffer - A pointer to a buffer to receive the data from the device
|
||||
* size - The requested number of bytes to be read
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_cfg_read(FAR struct pcie_dev_s *dev, uintptr_t addr,
|
||||
FAR void *buffer, unsigned int size)
|
||||
{
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
return __qemu_pci_cfg_read(dev->bdf, addr, buffer, size);
|
||||
case 8:
|
||||
return __qemu_pci_cfg_read64(dev->bdf, addr, buffer, size);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_map_bar
|
||||
*
|
||||
* Description:
|
||||
* Map address in a 32 bits bar in the memory address space
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device private data
|
||||
* bar - Bar number
|
||||
* length - Map length, multiple of PAGE_SIZE
|
||||
* ret - Bar Content
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t addr,
|
||||
unsigned long length)
|
||||
{
|
||||
up_map_region((void *)((uintptr_t)addr), length,
|
||||
X86_PAGE_WR | X86_PAGE_PRESENT | X86_PAGE_NOCACHE | X86_PAGE_GLOBAL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_map_bar64
|
||||
*
|
||||
* Description:
|
||||
* Map address in a 64 bits bar in the memory address space
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device private data
|
||||
* bar - Bar number
|
||||
* length - Map length, multiple of PAGE_SIZE
|
||||
* ret - Bar Content
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_map_bar64(FAR struct pcie_dev_s *dev, uint64_t addr,
|
||||
unsigned long length)
|
||||
{
|
||||
up_map_region((void *)((uintptr_t)addr), length,
|
||||
X86_PAGE_WR | X86_PAGE_PRESENT | X86_PAGE_NOCACHE | X86_PAGE_GLOBAL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_msix_register
|
||||
*
|
||||
* Description:
|
||||
* Map a device MSI-X vector to a platform IRQ vector
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device
|
||||
* vector - IRQ number of the platform
|
||||
* index - Device MSI-X vector number
|
||||
*
|
||||
* Returned Value:
|
||||
* <0: Mapping failed
|
||||
* 0: Mapping succeed
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_msix_register(FAR struct pcie_dev_s *dev,
|
||||
uint32_t vector, uint32_t index)
|
||||
{
|
||||
unsigned int bar;
|
||||
uint16_t message_control;
|
||||
uint32_t table_bar_ind;
|
||||
uint32_t table_addr_32;
|
||||
uint64_t msix_table_addr = 0;
|
||||
|
||||
int cap = pci_find_cap(dev, PCI_CAP_MSIX);
|
||||
if (cap < 0)
|
||||
return -EINVAL;
|
||||
|
||||
__qemu_pci_cfg_read(dev->bdf, cap + PCI_MSIX_MCR,
|
||||
&message_control, PCI_MSIX_MCR_SIZE);
|
||||
|
||||
/* bounds check */
|
||||
|
||||
if (index > (message_control & PCI_MSIX_MCR_TBL_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
__qemu_pci_cfg_read(dev->bdf, cap + PCI_MSIX_TBL,
|
||||
&table_bar_ind, PCI_MSIX_TBL_SIZE);
|
||||
|
||||
bar = (table_bar_ind & PCI_MSIX_BIR_MASK);
|
||||
|
||||
if (!pci_get_bar(dev, bar, &table_addr_32))
|
||||
{
|
||||
/* 32 bit bar */
|
||||
|
||||
msix_table_addr = table_addr_32;
|
||||
}
|
||||
else
|
||||
{
|
||||
pci_get_bar64(dev, bar, &msix_table_addr);
|
||||
}
|
||||
|
||||
msix_table_addr &= ~0xf;
|
||||
msix_table_addr += table_bar_ind & ~PCI_MSIX_BIR_MASK;
|
||||
|
||||
/* enable and mask */
|
||||
|
||||
message_control |= (PCI_MSIX_MCR_EN | PCI_MSIX_MCR_FMASK);
|
||||
__qemu_pci_cfg_write(dev->bdf, cap + PCI_MSIX_MCR,
|
||||
&message_control, PCI_MSIX_MCR_SIZE);
|
||||
|
||||
msix_table_addr += PCI_MSIX_TBL_ENTRY_SIZE * index;
|
||||
mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_LO_ADDR),
|
||||
0xfee00000 | up_apic_cpu_id() << PCI_MSIX_APIC_ID_OFFSET);
|
||||
mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_HI_ADDR),
|
||||
0);
|
||||
mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_MSG_DATA),
|
||||
vector);
|
||||
mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_VEC_CTL),
|
||||
0);
|
||||
|
||||
/* enable and unmask */
|
||||
|
||||
message_control &= ~PCI_MSIX_MCR_FMASK;
|
||||
|
||||
__qemu_pci_cfg_write(dev->bdf, cap + PCI_MSIX_MCR,
|
||||
&message_control, PCI_MSIX_MCR_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pci_msi_register
|
||||
*
|
||||
* Description:
|
||||
* Map device MSI vectors to a platform IRQ vector
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device
|
||||
* vector - IRQ number of the platform
|
||||
*
|
||||
* Returned Value:
|
||||
* <0: Mapping failed
|
||||
* 0: Mapping succeed
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int qemu_pci_msi_register(FAR struct pcie_dev_s *dev, uint16_t vector)
|
||||
{
|
||||
uint16_t ctl;
|
||||
uint16_t data;
|
||||
|
||||
int cap = pci_find_cap(dev, PCI_CAP_MSI);
|
||||
if (cap < 0)
|
||||
return -1;
|
||||
|
||||
uint32_t dest = 0xfee00000 | (up_apic_cpu_id() << PCI_MSI_APIC_ID_OFFSET);
|
||||
__qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MAR, &dest, PCI_MSI_MAR_SIZE);
|
||||
|
||||
__qemu_pci_cfg_read(dev->bdf, cap + PCI_MSI_MCR, &ctl, PCI_MSI_MCR_SIZE);
|
||||
if ((ctl & PCI_MSI_MCR_64) == PCI_MSI_MCR_64)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
__qemu_pci_cfg_write(dev->bdf,
|
||||
cap + PCI_MSI_MAR64_HI, &tmp,
|
||||
PCI_MSI_MAR64_HI_SIZE);
|
||||
data = cap + PCI_MSI_MDR64;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = cap + PCI_MSI_MDR;
|
||||
}
|
||||
|
||||
__qemu_pci_cfg_write(dev->bdf, data, &vector, PCI_MSI_MDR_SIZE);
|
||||
|
||||
__qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MCR, &vector,
|
||||
PCI_MSI_MCR_SIZE);
|
||||
|
||||
uint16_t tmp = PCI_MSI_MCR_EN;
|
||||
|
||||
__qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MCR, &tmp, PCI_MSI_MCR_SIZE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qemu_pcie_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize the PCI-E bus *
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void qemu_pcie_init(void)
|
||||
{
|
||||
pcie_initialize(&qemu_pcie_bus);
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/****************************************************************************
|
||||
* boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* The PCI-E Definitions and part of the access routines are taken from
|
||||
* Jailhouse inmate library
|
||||
*
|
||||
* Jailhouse, a Linux-based partitioning hypervisor
|
||||
*
|
||||
* Copyright (c) Siemens AG, 2014
|
||||
*
|
||||
* Authors:
|
||||
* Jan Kiszka <jan.kiszka@siemens.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Alternatively, you can use or redistribute this file under the following
|
||||
* BSD license:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H
|
||||
#define __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/pcie/pcie.h>
|
||||
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "up_arch.h"
|
||||
#include "up_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define PCI_REG_ADDR_PORT 0xcf8
|
||||
#define PCI_REG_DATA_PORT 0xcfc
|
||||
|
||||
#define PCI_CONE (1 << 31)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __qemu_pci_cfg_write
|
||||
*
|
||||
* Description:
|
||||
* Write 8, 16, 32 bits data to PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* bfd - Device private data
|
||||
* buffer - A pointer to the read-only buffer of data to be written
|
||||
* size - The number of bytes to send from the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int __qemu_pci_cfg_write(uint16_t bfd, uintptr_t addr,
|
||||
FAR const void *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
outl(PCI_CONE | ((uint32_t)bfd << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
outb(*(uint8_t *)(buffer), PCI_REG_DATA_PORT + (addr & 0x3));
|
||||
break;
|
||||
case 2:
|
||||
outw(*(uint16_t *)(buffer), PCI_REG_DATA_PORT + (addr & 0x3));
|
||||
break;
|
||||
case 4:
|
||||
outl(*(uint32_t *)(buffer), PCI_REG_DATA_PORT);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __qemu_pci_cfg_write64
|
||||
*
|
||||
* Description:
|
||||
* Write 64 bits data to PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* bfd - Device private data
|
||||
* buffer - A pointer to the read-only buffer of data to be written
|
||||
* size - The number of bytes to send from the buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int __qemu_pci_cfg_write64(uint16_t bfd, uintptr_t addr,
|
||||
FAR const void *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __qemu_pci_cfg_write(bfd, addr + 4, buffer + 4, 4);
|
||||
ret |= __qemu_pci_cfg_write(bfd, addr, buffer, 4);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __qemu_pci_cfg_read
|
||||
*
|
||||
* Description:
|
||||
* Read 8, 16, 32 bits data from PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device private data
|
||||
* buffer - A pointer to a buffer to receive the data from the device
|
||||
* size - The requested number of bytes to be read
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int __qemu_pci_cfg_read(uint16_t bfd, uintptr_t addr,
|
||||
FAR void *buffer, unsigned int size)
|
||||
{
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
outl(PCI_CONE | ((uint32_t)bfd << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT);
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
*(uint8_t *)(buffer) = inb(PCI_REG_DATA_PORT + (addr & 0x3));
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)(buffer) = inw(PCI_REG_DATA_PORT + (addr & 0x3));
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t *)(buffer) = inl(PCI_REG_DATA_PORT);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __qemu_pci_cfg_read
|
||||
*
|
||||
* Description:
|
||||
* Read 64 bits data from PCI-E configuration space of device
|
||||
* specified by dev
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device private data
|
||||
* buffer - A pointer to a buffer to receive the data from the device
|
||||
* size - The requested number of bytes to be read
|
||||
*
|
||||
* Returned Value:
|
||||
* 0: success, <0: A negated errno
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline int __qemu_pci_cfg_read64(uint16_t bfd,
|
||||
uintptr_t addr,
|
||||
FAR void *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!buffer)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __qemu_pci_cfg_read(bfd, addr + 4, buffer + 4, 4);
|
||||
ret |= __qemu_pci_cfg_read(bfd, addr, buffer, 4);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H */
|
||||
Reference in New Issue
Block a user