2015-04-11 07:44:37 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2009-2011, 2013-2014 Wind River Systems, Inc.
|
|
|
|
*
|
2015-10-07 00:00:37 +08:00
|
|
|
* Licensed 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
|
2015-04-11 07:44:37 +08:00
|
|
|
*
|
2015-10-07 00:00:37 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-04-11 07:44:37 +08:00
|
|
|
*
|
2015-10-07 00:00:37 +08:00
|
|
|
* 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.
|
2015-04-11 07:44:37 +08:00
|
|
|
*/
|
|
|
|
|
2015-12-04 23:09:39 +08:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief PCI bus support
|
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
*
|
|
|
|
* This module implements the PCI H/W access functions.
|
2015-07-02 05:22:39 +08:00
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
|
|
|
#include <nanokernel.h>
|
2015-05-29 01:56:47 +08:00
|
|
|
#include <arch/cpu.h>
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-04-23 18:21:51 +08:00
|
|
|
#include <pci/pci_mgr.h>
|
2015-04-11 07:44:37 +08:00
|
|
|
#include <string.h>
|
|
|
|
#include <board.h>
|
|
|
|
|
|
|
|
#if (PCI_CTRL_ADDR_REG == 0)
|
|
|
|
#error "PCI_CTRL_ADDR_REG cannot be zero"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if (PCI_CTRL_DATA_REG == 0)
|
|
|
|
#error "PCI_CTRL_DATA_REG cannot be zero"
|
|
|
|
#endif
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Read a PCI controller register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param reg PCI register to read
|
|
|
|
* @param data where to put the data
|
|
|
|
* @param size size of the data to read (8/16/32 bits)
|
|
|
|
*
|
2015-07-02 05:22:39 +08:00
|
|
|
* This routine reads the specified register from the PCI controller and
|
|
|
|
* places the data into the provided buffer.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return N/A
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
static void pci_ctrl_read(uint32_t reg, uint32_t *data, uint32_t size)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
/* read based on the size requested */
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
/* long (32 bits) */
|
|
|
|
case SYS_PCI_ACCESS_32BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
*data = sys_in32(reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
/* word (16 bits) */
|
|
|
|
case SYS_PCI_ACCESS_16BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
*data = sys_in16(reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
/* byte (8 bits) */
|
|
|
|
case SYS_PCI_ACCESS_8BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
*data = sys_in8(reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Write a PCI controller register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param reg PCI register to write
|
|
|
|
* @param data data to write
|
|
|
|
* @param size size of the data to write (8/16/32 bits)
|
|
|
|
*
|
2015-07-02 05:22:39 +08:00
|
|
|
* This routine writes the provided data to the specified register in the PCI
|
|
|
|
* controller.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return N/A
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
static void pci_ctrl_write(uint32_t reg, uint32_t data, uint32_t size)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
/* write based on the size requested */
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
/* long (32 bits) */
|
|
|
|
case SYS_PCI_ACCESS_32BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
sys_out32(data, reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
/* word (16 bits) */
|
|
|
|
case SYS_PCI_ACCESS_16BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
sys_out16(data, reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
/* byte (8 bits) */
|
|
|
|
case SYS_PCI_ACCESS_8BIT:
|
2015-09-10 23:37:53 +08:00
|
|
|
sys_out8(data, reg);
|
2015-04-11 07:44:37 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Read the PCI controller data register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param controller controller number
|
|
|
|
* @param offset is the offset within the data region
|
|
|
|
* @param data is the returned data
|
|
|
|
* @param size is the size of the data to read
|
|
|
|
*
|
2015-07-02 05:22:39 +08:00
|
|
|
* This routine reads the data register of the specified PCI controller.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return 0 or -1
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
static int pci_ctrl_data_read(uint32_t controller, uint32_t offset,
|
2015-10-21 00:42:33 +08:00
|
|
|
uint32_t *data, uint32_t size)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
/* we only support one controller */
|
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
if (controller != DEFAULT_PCI_CONTROLLER) {
|
2015-04-11 07:44:37 +08:00
|
|
|
return (-1);
|
2015-10-21 00:42:33 +08:00
|
|
|
}
|
2015-04-11 07:44:37 +08:00
|
|
|
|
|
|
|
pci_ctrl_read(PCI_CTRL_DATA_REG + offset, data, size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Write the PCI controller data register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param controller the controller number
|
|
|
|
* @param offset is the offset within the address register
|
|
|
|
* @param data is the data to write
|
|
|
|
* @param size is the size of the data
|
|
|
|
*
|
2015-07-02 05:22:39 +08:00
|
|
|
* This routine writes the provided data to the data register of the
|
|
|
|
* specified PCI controller.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return 0 or -1
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
static int pci_ctrl_data_write(uint32_t controller, uint32_t offset,
|
|
|
|
uint32_t data, uint32_t size)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
/* we only support one controller */
|
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
if (controller != DEFAULT_PCI_CONTROLLER) {
|
2015-04-11 07:44:37 +08:00
|
|
|
return (-1);
|
2015-10-21 00:42:33 +08:00
|
|
|
}
|
2015-04-11 07:44:37 +08:00
|
|
|
|
|
|
|
pci_ctrl_write(PCI_CTRL_DATA_REG + offset, data, size);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Write the PCI controller address register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param controller is the controller number
|
|
|
|
* @param offset is the offset within the address register
|
|
|
|
* @param data is the data to write
|
|
|
|
* @param size is the size of the data
|
|
|
|
*
|
2015-07-02 05:22:39 +08:00
|
|
|
* This routine writes the provided data to the address register of the
|
|
|
|
* specified PCI controller.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return 0 or -1
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
static int pci_ctrl_addr_write(uint32_t controller, uint32_t offset,
|
|
|
|
uint32_t data, uint32_t size)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
/* we only support one controller */
|
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
if (controller != DEFAULT_PCI_CONTROLLER) {
|
2015-04-11 07:44:37 +08:00
|
|
|
return (-1);
|
2015-10-21 00:42:33 +08:00
|
|
|
}
|
2015-04-11 07:44:37 +08:00
|
|
|
|
|
|
|
pci_ctrl_write(PCI_CTRL_ADDR_REG + offset, data, size);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Read a PCI register from a device
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
* This routine reads data from a PCI device's configuration space. The
|
|
|
|
* device and register to read is specified by the address parameter ("addr")
|
|
|
|
* and must be set appropriately by the caller. The address is defined by
|
|
|
|
* the structure type pci_addr_t and contains the following members:
|
|
|
|
*
|
|
|
|
* bus: PCI bus number (0-255)
|
|
|
|
* device: PCI device number (0-31)
|
|
|
|
* func: device function number (0-7)
|
|
|
|
* reg: device 32-bit register number to read (0-63)
|
|
|
|
* offset: offset within 32-bit register to read (0-3)
|
|
|
|
*
|
|
|
|
* The size parameter specifies the number of bytes to read from the PCI
|
|
|
|
* configuration space, valid values are 1, 2, and 4 bytes. A 32-bit value
|
|
|
|
* is always returned but it will contain only the number of bytes specified
|
|
|
|
* by the size parameter.
|
|
|
|
*
|
|
|
|
* If multiple PCI controllers are present in the system, the controller id
|
|
|
|
* can be specified in the "controller" parameter. If only one controller
|
|
|
|
* is present, the id DEFAULT_PCI_CONTROLLER can be used to denote this
|
|
|
|
* controller.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* union pci_addr_reg addr;
|
|
|
|
* uint32_t status;
|
|
|
|
*
|
|
|
|
* addr.field.bus = 0; /@ PCI bus zero @/
|
|
|
|
* addr.field.device = 1; /@ PCI device one @/
|
|
|
|
* addr.field.func = 0; /@ PCI function zero @/
|
|
|
|
* addr.field.reg = 4; /@ PCI register 4 @/
|
|
|
|
* addr.field.offset = 0; /@ PCI register offset @/
|
|
|
|
*
|
|
|
|
* pci_read (DEFAULT_PCI_CONTROLLER, addr, sizeof(uint16_t), &status);
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* NOTE:
|
|
|
|
* Reading of PCI data must be performed as an atomic operation. It is up to
|
|
|
|
* the caller to enforce this.
|
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param controller is the PCI controller number to use
|
|
|
|
* @param addr is the PCI address to read
|
|
|
|
* @param size is the size of the data in bytes
|
|
|
|
* @param data is a pointer to the data read from the device
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return N/A
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
void pci_read(uint32_t controller, union pci_addr_reg addr,
|
|
|
|
uint32_t size, uint32_t *data)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
uint32_t access_size;
|
|
|
|
uint32_t access_offset;
|
|
|
|
|
|
|
|
/* validate the access size */
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
case 1:
|
|
|
|
access_size = SYS_PCI_ACCESS_8BIT;
|
|
|
|
access_offset = addr.field.offset;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
access_size = SYS_PCI_ACCESS_16BIT;
|
|
|
|
access_offset = addr.field.offset;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
default:
|
|
|
|
access_size = SYS_PCI_ACCESS_32BIT;
|
|
|
|
access_offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ensure enable has been set */
|
|
|
|
|
|
|
|
addr.field.enable = 1;
|
|
|
|
|
|
|
|
/* clear the offset for the address register */
|
|
|
|
|
|
|
|
addr.field.offset = 0;
|
|
|
|
|
|
|
|
/* read the data from the PCI controller */
|
|
|
|
|
|
|
|
pci_ctrl_addr_write(
|
|
|
|
controller, PCI_NO_OFFSET, addr.value, SYS_PCI_ACCESS_32BIT);
|
|
|
|
|
|
|
|
pci_ctrl_data_read(controller, access_offset, data, access_size);
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Write a to a PCI register
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
* This routine writes data to a PCI device's configuration space. The
|
|
|
|
* device and register to write is specified by the address parameter ("addr")
|
|
|
|
* and must be set appropriately by the caller. The address is defined by
|
|
|
|
* the structure type pci_addr_t and contains the following members:
|
|
|
|
*
|
|
|
|
* bus: PCI bus number (0-255)
|
|
|
|
* device: PCI device number (0-31)
|
|
|
|
* func: device function number (0-7)
|
|
|
|
* reg: device register number to read (0-63)
|
|
|
|
* offset: offset within 32-bit register to write (0-3)
|
|
|
|
*
|
|
|
|
* The size parameter specifies the number of bytes to write to the PCI
|
|
|
|
* configuration space, valid values are 1, 2, and 4 bytes. A 32-bit value
|
|
|
|
* is always provided but only the number of bytes specified by the size
|
|
|
|
* parameter will be written to the device.
|
|
|
|
*
|
|
|
|
* If multiple PCI controllers are present in the system, the controller id
|
|
|
|
* can be specified in the "controller" parameter. If only one controller
|
|
|
|
* is present, the id DEFAULT_PCI_CONTROLLER can be used to denote this
|
|
|
|
* controller.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* pci_addr_t addr;
|
|
|
|
* uint32_t bar0 = 0xE0000000;
|
|
|
|
*
|
|
|
|
* addr.field.bus = 0; /@ PCI bus zero @/
|
|
|
|
* addr.field.device = 1; /@ PCI device one @/
|
|
|
|
* addr.field.func = 0; /@ PCI function zero @/
|
|
|
|
* addr.field.reg = 16; /@ PCI register 16 @/
|
|
|
|
* addr.field.offset = 0; /@ PCI register offset @/
|
|
|
|
*
|
|
|
|
* pci_write (DEFAULT_PCI_CONTROLLER, addr, sizeof(uint32_t), bar0);
|
|
|
|
*
|
|
|
|
* NOTE:
|
|
|
|
* Writing of PCI data must be performed as an atomic operation. It is up to
|
|
|
|
* the caller to enforce this.
|
|
|
|
*
|
2015-10-21 00:42:33 +08:00
|
|
|
* @param controller is the PCI controller to use
|
|
|
|
* @param addr is the PCI addres to read
|
|
|
|
* @param size is the size in bytes to write
|
|
|
|
* @param data is the data to write
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return N/A
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
2015-10-21 00:42:33 +08:00
|
|
|
void pci_write(uint32_t controller, union pci_addr_reg addr,
|
|
|
|
uint32_t size, uint32_t data)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
uint32_t access_size;
|
|
|
|
uint32_t access_offset;
|
|
|
|
|
|
|
|
/* validate the access size */
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
case 1:
|
|
|
|
access_size = SYS_PCI_ACCESS_8BIT;
|
|
|
|
access_offset = addr.field.offset;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
access_size = SYS_PCI_ACCESS_16BIT;
|
|
|
|
access_offset = addr.field.offset;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
default:
|
|
|
|
access_size = SYS_PCI_ACCESS_32BIT;
|
|
|
|
access_offset = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ensure enable has been set */
|
|
|
|
|
|
|
|
addr.field.enable = 1;
|
|
|
|
|
|
|
|
/* clear the offset for the address register */
|
|
|
|
|
|
|
|
addr.field.offset = 0;
|
|
|
|
|
|
|
|
/* write the data to the PCI controller */
|
|
|
|
|
|
|
|
pci_ctrl_addr_write(
|
|
|
|
controller, PCI_NO_OFFSET, addr.value, SYS_PCI_ACCESS_32BIT);
|
|
|
|
pci_ctrl_data_write(controller, access_offset, data, access_size);
|
|
|
|
}
|
|
|
|
|
2015-07-02 05:22:39 +08:00
|
|
|
/**
|
|
|
|
*
|
2015-07-02 05:51:40 +08:00
|
|
|
* @brief Get the PCI header for a device
|
2015-07-02 05:22:39 +08:00
|
|
|
*
|
|
|
|
* This routine reads the PCI header for the specified device and puts the
|
|
|
|
* result in the supplied header structure.
|
|
|
|
*
|
2015-07-02 05:29:04 +08:00
|
|
|
* @return N/A
|
2015-07-02 05:22:39 +08:00
|
|
|
*/
|
2015-04-11 07:44:37 +08:00
|
|
|
|
pci: Provide a simpler yet powerful PCI enumeration API
This fixes many issues around PCI enumeration from old API:
- a static internal table was fed with scanning results, thus eating
memory, and worse: due to the limit of its size, scanning for new
classes was impossible unless growing statically the size of this
table --> more memory eaten! Not to mention PCI enumeration is done
once at boot time for driver initialization and that's all, so this
table is hanging around for nothing afterwards.
- one needs first to scan a class, then maybe he will be able to find
his device via pci_dev_find. Where all could be done at once.
- pci_dev_find was not trustworthy due again to the internal table. Now
if the device is not found, one will know it really went through all
the possbilities.
- still let the possibility for hard-coded BARs value on driver side
(thus no PCI scan required). However this is greatly advised not to do
so as BARs might change over a firmware/BIOS update.
Comparison:
old pci_dev_scan: could only filter out via class mask.
new pci_dev_scan: can filter out via a class, a vendor and device ID
(it could easily do the same for Function and BAR index as these are
usually fixed and informed through datasheet)
old pci_dev_scan: was limited in its findings by the size of the
internal result table.
new pci_dev_scan: can proceed through all the buses and devices every
time (there are optimizations to avoid useless work of course)
old results did not tell about the function or BAR index.
new one tells, and the structure has not bloated.
old internal code: was storing a big table of results
new internal code: is only storing a small lookup structure and an
array of Bus:Dev pairs for each PCI class for optimizations purpose.
(though, if needed, we could disable this through some #ifdef)
Usage:
- Have a local struct dev_info
- Fill it with what you want to look for, currently: only class and
vendor_id/device_id. Function and BAR index could be added if needed.
- Call pci_bus_scan_init(): this will reset the internal lookup
structure.
- Call pci_dev_scan(<a pointer to your dev_info>): at first call, the
internal lookup structure will pick up the informations from dev_info
and will try to find out what has been requested. It will return 1 on
success, or 0. On 1, your dev_info structure will be updated with the
found informations. If more devices can be found against the same
lookup informations, just call again pci_dev_scan(<a pointer to your
dev_info>) as long as it returns 1. When 0 is hit, it will mean you
found all.
Change-Id: Ibc2a16c4485ee3fed7ef4946af0ece032ae406e4
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2015-05-20 19:30:35 +08:00
|
|
|
void pci_header_get(uint32_t controller,
|
2015-10-21 00:42:33 +08:00
|
|
|
union pci_addr_reg pci_ctrl_addr,
|
|
|
|
union pci_dev *pci_dev_header)
|
2015-04-11 07:44:37 +08:00
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
/* clear out the header */
|
|
|
|
|
2016-02-23 18:04:50 +08:00
|
|
|
memset(pci_dev_header, 0, sizeof(*pci_dev_header));
|
2015-04-11 07:44:37 +08:00
|
|
|
|
|
|
|
/* fill in the PCI header from the device */
|
|
|
|
|
|
|
|
for (i = 0; i < PCI_HEADER_WORDS; i++) {
|
|
|
|
pci_ctrl_addr.field.reg = i;
|
|
|
|
pci_read(controller,
|
|
|
|
pci_ctrl_addr,
|
|
|
|
sizeof(uint32_t),
|
|
|
|
&pci_dev_header->words.word[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|