Adding upstream version 1:10.0.2+ds.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
parent
bf2768bd0f
commit
ea34ddeea6
37998 changed files with 9510514 additions and 0 deletions
156
roms/qemu-palcode/pci.c
Normal file
156
roms/qemu-palcode/pci.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
/* Simplistic PCI support.
|
||||
|
||||
Copyright (C) 2011 Richard Henderson
|
||||
|
||||
This file is part of QEMU PALcode.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the text
|
||||
of the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; see the file COPYING. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* We don't bother supporting PCI bridges, because the device model we're
|
||||
currently using for QEMU doesn't build any.
|
||||
|
||||
We don't bother to build real datastructures in memory, because it's
|
||||
fairly quick under emulation simply to access configuration space again.
|
||||
This helps when running kernels under the emulator that might have
|
||||
re-organized the BARs out from under us. */
|
||||
|
||||
#include "protos.h"
|
||||
#include "pci.h"
|
||||
#include "pci_regs.h"
|
||||
#include SYSTEM_H
|
||||
|
||||
|
||||
#define PCI_SLOT_MAX 32
|
||||
#define PCI_FUNC_MAX 8
|
||||
#define PCI_REGION_ROM 6
|
||||
#define PCI_REGIONS_MAX 7
|
||||
|
||||
|
||||
void
|
||||
pci_config_maskw(int bdf, int addr, uint16_t off, uint16_t on)
|
||||
{
|
||||
uint16_t val = pci_config_readw(bdf, addr);
|
||||
val = (val & ~off) | on;
|
||||
pci_config_writew(bdf, addr, val);
|
||||
}
|
||||
|
||||
int
|
||||
pci_next(int bdf, int *pmax)
|
||||
{
|
||||
int max;
|
||||
|
||||
if (PCI_FUNC(bdf) == 1)
|
||||
{
|
||||
/* If the last device was not a multi-function device, skip to next. */
|
||||
if ((pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
|
||||
bdf += 7;
|
||||
}
|
||||
|
||||
max = *pmax;
|
||||
while (1)
|
||||
{
|
||||
uint16_t vendor;
|
||||
|
||||
/* ??? Support multiple PCI busses here at some point. */
|
||||
if (bdf >= max)
|
||||
return -1;
|
||||
|
||||
/* Check if there is a device present at the location. */
|
||||
vendor = pci_config_readw(bdf, PCI_VENDOR_ID);
|
||||
if (vendor != 0x0000 && vendor != 0xffff)
|
||||
return bdf;
|
||||
|
||||
bdf += (PCI_FUNC(bdf) == 0 ? 8 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pci_setup_device(int bdf, uint32_t *p_io_base, uint32_t *p_mem_base)
|
||||
{
|
||||
int vendor_id, device_id, class_id, region;
|
||||
|
||||
vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
|
||||
device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
|
||||
class_id = pci_config_readw(bdf, PCI_CLASS_DEVICE);
|
||||
|
||||
printf("PCI: %02x:%02x:%x class %04x id %04x:%04x\r\n",
|
||||
PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf),
|
||||
class_id, vendor_id, device_id);
|
||||
|
||||
for (region = 0; region < PCI_REGION_ROM; region++)
|
||||
{
|
||||
int ofs = PCI_BASE_ADDRESS_0 + region * 4;
|
||||
uint32_t old, mask, val, size, align;
|
||||
uint32_t *p_base;
|
||||
|
||||
old = pci_config_readl(bdf, ofs);
|
||||
if (old & PCI_BASE_ADDRESS_SPACE_IO)
|
||||
{
|
||||
mask = PCI_BASE_ADDRESS_IO_MASK;
|
||||
p_base = p_io_base;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = PCI_BASE_ADDRESS_MEM_MASK;
|
||||
p_base = p_mem_base;
|
||||
}
|
||||
|
||||
pci_config_writel(bdf, ofs, -1);
|
||||
val = pci_config_readl(bdf, ofs);
|
||||
pci_config_writel(bdf, ofs, old);
|
||||
|
||||
align = size = ~(val & mask) + 1;
|
||||
if (val != 0)
|
||||
{
|
||||
uint32_t addr = *p_base;
|
||||
addr = (addr + align - 1) & ~(align - 1);
|
||||
*p_base = addr + size;
|
||||
pci_config_writel(bdf, ofs, addr);
|
||||
|
||||
printf("PCI: region %d: %08x\r\n", region, addr);
|
||||
|
||||
if ((old & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
|
||||
== (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64))
|
||||
{
|
||||
pci_config_writel(bdf, ofs + 4, 0);
|
||||
region++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
|
||||
|
||||
/* Map the interrupt and program the IRQ into the line register.
|
||||
Some operating systems rely on the Console providing this information
|
||||
in order to avoid having mapping tables for every possible system
|
||||
variation. */
|
||||
|
||||
const uint8_t pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
|
||||
const uint8_t slot = PCI_SLOT(bdf);
|
||||
const uint8_t irq = MAP_PCI_INTERRUPT(slot, pin, class_id);
|
||||
|
||||
pci_config_writeb(bdf, PCI_INTERRUPT_LINE, irq);
|
||||
}
|
||||
|
||||
void
|
||||
pci_setup(void)
|
||||
{
|
||||
uint32_t io_base = 0xc000;
|
||||
uint32_t mem_base = 256 * 1024 * 1024;
|
||||
int bdf, max;
|
||||
|
||||
foreachpci (bdf, max)
|
||||
pci_setup_device(bdf, &io_base, &mem_base);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue