2014-12-09 22:32:59 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * 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.
|
|
|
|
* * Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this
|
|
|
|
* software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* 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 REGENTS 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.
|
|
|
|
*/
|
|
|
|
|
2014-12-09 10:09:03 +01:00
|
|
|
#include <eduos/stdio.h>
|
|
|
|
#include <eduos/string.h>
|
|
|
|
#include <eduos/errno.h>
|
|
|
|
#include <asm/irqflags.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
|
|
|
|
#include <asm/pci.h>
|
2014-12-19 11:35:24 +01:00
|
|
|
#ifdef WITH_PCI_NAMES
|
2014-12-09 10:09:03 +01:00
|
|
|
#include "pcihdr.h"
|
2014-12-19 11:35:24 +01:00
|
|
|
#endif
|
2014-12-09 10:09:03 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* PCI configuration registers
|
|
|
|
*/
|
|
|
|
#define PCI_CFID 0x00 /* Configuration ID */
|
|
|
|
#define PCI_CFCS 0x04 /* Configurtion Command/Status */
|
|
|
|
#define PCI_CFRV 0x08 /* Configuration Revision */
|
|
|
|
#define PCI_CFLT 0x0c /* Configuration Latency Timer */
|
|
|
|
#define PCI_CBIO 0x10 /* Configuration Base IO Address */
|
|
|
|
#define PCI_CFIT 0x3c /* Configuration Interrupt */
|
|
|
|
#define PCI_CFDA 0x40 /* Configuration Driver Area */
|
|
|
|
|
|
|
|
#define PHYS_IO_MEM_START 0
|
|
|
|
#define PCI_MEM 0
|
|
|
|
#define PCI_INTA 0
|
|
|
|
#define PCI_NSLOTS 22
|
|
|
|
#define PCI_NBUS 0
|
|
|
|
|
|
|
|
#define PCI_CONF_ADDR_REG 0xcf8
|
|
|
|
#define PCI_CONF_FRWD_REG 0xcf8
|
|
|
|
#define PCI_CONF_DATA_REG 0xcfc
|
|
|
|
|
|
|
|
#define PCI_IO_CONF_START 0xc000
|
|
|
|
|
|
|
|
#define MAX_BUS 16
|
|
|
|
#define MAX_SLOTS 32
|
|
|
|
|
|
|
|
static uint32_t mechanism = 0;
|
|
|
|
static uint32_t adapters[MAX_BUS][MAX_SLOTS] = {[0 ... MAX_BUS-1][0 ... MAX_SLOTS-1] = -1};
|
|
|
|
|
|
|
|
static void pci_conf_write(uint32_t bus, uint32_t slot, uint32_t off, uint32_t val)
|
|
|
|
{
|
|
|
|
if (mechanism == 1) {
|
|
|
|
outportl(PCI_CONF_FRWD_REG, bus);
|
|
|
|
outportl(PCI_CONF_ADDR_REG, 0xf0);
|
|
|
|
outportl(PCI_IO_CONF_START | (slot << 8) | off, val);
|
|
|
|
} else {
|
2014-12-09 22:32:59 +01:00
|
|
|
outportl(PCI_CONF_ADDR_REG, (0x80000000 | (bus << 16) | (slot << 11) | off));
|
2014-12-09 10:09:03 +01:00
|
|
|
outportl(PCI_CONF_DATA_REG, val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t pci_conf_read(uint32_t bus, uint32_t slot, uint32_t off)
|
|
|
|
{
|
|
|
|
uint32_t data = -1;
|
|
|
|
|
2014-12-09 22:35:38 +01:00
|
|
|
outportl(PCI_CONF_ADDR_REG, (0x80000000 | (bus << 16) | (slot << 11) | off));
|
2014-12-09 10:09:03 +01:00
|
|
|
data = inportl(PCI_CONF_DATA_REG);
|
|
|
|
|
|
|
|
if ((data == 0xffffffff) && (slot < 0x10)) {
|
|
|
|
outportl(PCI_CONF_FRWD_REG, bus);
|
|
|
|
outportl(PCI_CONF_ADDR_REG, 0xf0);
|
|
|
|
data = inportl(PCI_IO_CONF_START | (slot << 8) | off);
|
|
|
|
if (data == 0xffffffff)
|
|
|
|
return data;
|
|
|
|
if (!mechanism)
|
|
|
|
mechanism = 1;
|
|
|
|
} else if (!mechanism)
|
|
|
|
mechanism = 2;
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2014-12-13 17:53:42 +01:00
|
|
|
static inline uint8_t pci_what_irq(uint32_t bus, uint32_t slot)
|
2014-12-09 10:09:03 +01:00
|
|
|
{
|
|
|
|
return pci_conf_read(bus, slot, PCI_CFIT) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint32_t pci_what_iobase(uint32_t bus, uint32_t slot, uint32_t nr)
|
|
|
|
{
|
|
|
|
return pci_conf_read(bus, slot, PCI_CBIO + nr*4) & 0xFFFFFFFC;
|
|
|
|
}
|
|
|
|
|
2014-12-13 17:53:42 +01:00
|
|
|
static inline uint32_t pci_what_type(uint32_t bus, uint32_t slot, uint32_t nr)
|
|
|
|
{
|
|
|
|
return pci_conf_read(bus, slot, PCI_CBIO + nr*4) & 0x1;
|
|
|
|
}
|
|
|
|
|
2014-12-09 10:09:03 +01:00
|
|
|
static inline uint32_t pci_what_size(uint32_t bus, uint32_t slot, uint32_t nr)
|
|
|
|
{
|
|
|
|
uint32_t tmp, ret;
|
|
|
|
|
|
|
|
// backup the original value
|
|
|
|
tmp = pci_conf_read(bus, slot, PCI_CBIO + nr*4);
|
|
|
|
|
|
|
|
// determine size
|
|
|
|
pci_conf_write(bus, slot, PCI_CBIO + nr*4, 0xFFFFFFFF);
|
|
|
|
ret = ~pci_conf_read(bus, slot, PCI_CBIO + nr*4) + 1;
|
|
|
|
|
|
|
|
// restore original value
|
|
|
|
pci_conf_write(bus, slot, PCI_CBIO + nr*4, tmp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pci_init(void)
|
|
|
|
{
|
|
|
|
uint32_t slot, bus;
|
|
|
|
|
|
|
|
for (bus = 0; bus < MAX_BUS; bus++)
|
|
|
|
for (slot = 0; slot < MAX_SLOTS; slot++)
|
|
|
|
adapters[bus][slot] = pci_conf_read(bus, slot, PCI_CFID);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pci_get_device_info(uint32_t vendor_id, uint32_t device_id, pci_info_t* info)
|
|
|
|
{
|
|
|
|
uint32_t slot, bus, i;
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!mechanism)
|
|
|
|
pci_init();
|
|
|
|
|
|
|
|
for (bus = 0; bus < MAX_BUS; bus++) {
|
|
|
|
for (slot = 0; slot < MAX_SLOTS; slot++) {
|
|
|
|
if (adapters[bus][slot] != -1) {
|
|
|
|
if (((adapters[bus][slot] & 0xffff) == vendor_id) &&
|
|
|
|
(((adapters[bus][slot] & 0xffff0000) >> 16) == device_id)) {
|
2014-12-13 17:53:42 +01:00
|
|
|
info->slot = slot;
|
|
|
|
info->bus = bus;
|
2014-12-09 10:09:03 +01:00
|
|
|
for(i=0; i<6; i++) {
|
|
|
|
info->base[i] = pci_what_iobase(bus, slot, i);
|
2014-12-13 17:53:42 +01:00
|
|
|
info->type[i] = pci_what_type(bus, slot, i);
|
2014-12-09 10:09:03 +01:00
|
|
|
info->size[i] = (info->base[i]) ? pci_what_size(bus, slot, i) : 0;
|
|
|
|
}
|
|
|
|
info->irq = pci_what_irq(bus, slot);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-12-19 11:35:24 +01:00
|
|
|
#ifdef WITH_PCI_NAMES
|
2014-12-09 10:09:03 +01:00
|
|
|
int print_pci_adapters(void)
|
|
|
|
{
|
|
|
|
uint32_t slot, bus;
|
|
|
|
uint32_t i, counter = 0;
|
|
|
|
|
|
|
|
if (!mechanism)
|
|
|
|
pci_init();
|
|
|
|
|
|
|
|
for (bus = 0; bus < MAX_BUS; bus++) {
|
|
|
|
for (slot = 0; slot < MAX_SLOTS; slot++) {
|
|
|
|
|
|
|
|
if (adapters[bus][slot] != -1) {
|
|
|
|
counter++;
|
|
|
|
|
|
|
|
kprintf("%d) Vendor ID: 0x%x Device Id: 0x%x\n",
|
|
|
|
counter, adapters[bus][slot] & 0xffff,
|
|
|
|
(adapters[bus][slot] & 0xffff0000) >> 16);
|
|
|
|
|
|
|
|
for (i=0; i<PCI_VENTABLE_LEN; i++) {
|
|
|
|
if ((adapters[bus][slot] & 0xffff) ==
|
|
|
|
(uint32_t)PciVenTable[i].VenId)
|
|
|
|
kprintf("\tVendor is %s\n",
|
|
|
|
PciVenTable[i].VenShort);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<PCI_DEVTABLE_LEN; i++) {
|
|
|
|
if ((adapters[bus][slot] & 0xffff) ==
|
|
|
|
(uint32_t)PciDevTable[i].VenId) {
|
|
|
|
if (((adapters[bus][slot] & 0xffff0000) >> 16) ==
|
|
|
|
PciDevTable[i].DevId) {
|
|
|
|
kprintf
|
|
|
|
("\tChip: %s ChipDesc: %s\n",
|
|
|
|
PciDevTable[i].Chip,
|
|
|
|
PciDevTable[i].ChipDesc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-12-19 11:35:24 +01:00
|
|
|
#endif
|
2014-12-09 10:09:03 +01:00
|
|
|
|
|
|
|
#endif
|