qemu-patch-raspberry4/hw/pci/pcie_port.c
Alex Williamson ba7d8515c1 pci: Teach PCI Bridges about VGA routing
Each PCI Bridge has a set of implied VGA regions that are enabled when
the VGA bit is set in the bridge control register.  This allows VGA
devices behind bridges.  Unfortunately with VGA Enable, which we
formerly allowed but didn't back, comes along some required VGA
baggage.  VGA Palette Snooping is required, along with VGA 16-bit
decoding.  We don't yet have support for palette snooping.
We also don't have support for 10-bit VGA aliases, the default mode, but
we enable the register, even on root ports, to avoid confusing guests.
Fortunately there's likely nothing from this century that requires these
features, so the missing bits are noted with TODOs.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2013-03-26 21:02:17 +02:00

117 lines
3.2 KiB
C

/*
* pcie_port.c
*
* Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
* VA Linux Systems Japan K.K.
*
* 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/pci/pcie_port.h"
void pcie_port_init_reg(PCIDevice *d)
{
/* Unlike pci bridge,
66MHz and fast back to back don't apply to pci express port. */
pci_set_word(d->config + PCI_STATUS, 0);
pci_set_word(d->config + PCI_SEC_STATUS, 0);
/* Unlike conventional pci bridge, some bits are hardwired to 0. */
#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_ISA |
PCI_BRIDGE_CTL_VGA |
PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */
PCI_BRIDGE_CTL_SERR |
PCI_BRIDGE_CTL_BUS_RESET);
}
/**************************************************************************
* (chassis number, pcie physical slot number) -> pcie slot conversion
*/
struct PCIEChassis {
uint8_t number;
QLIST_HEAD(, PCIESlot) slots;
QLIST_ENTRY(PCIEChassis) next;
};
static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
{
struct PCIEChassis *c;
QLIST_FOREACH(c, &chassis, next) {
if (c->number == chassis_number) {
break;
}
}
return c;
}
void pcie_chassis_create(uint8_t chassis_number)
{
struct PCIEChassis *c;
c = pcie_chassis_find(chassis_number);
if (c) {
return;
}
c = g_malloc0(sizeof(*c));
c->number = chassis_number;
QLIST_INIT(&c->slots);
QLIST_INSERT_HEAD(&chassis, c, next);
}
static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
uint8_t slot)
{
PCIESlot *s;
QLIST_FOREACH(s, &c->slots, next) {
if (s->slot == slot) {
break;
}
}
return s;
}
PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
{
struct PCIEChassis *c;
c = pcie_chassis_find(chassis_number);
if (!c) {
return NULL;
}
return pcie_chassis_find_slot_with_chassis(c, slot);
}
int pcie_chassis_add_slot(struct PCIESlot *slot)
{
struct PCIEChassis *c;
c = pcie_chassis_find(slot->chassis);
if (!c) {
return -ENODEV;
}
if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
return -EBUSY;
}
QLIST_INSERT_HEAD(&c->slots, slot, next);
return 0;
}
void pcie_chassis_del_slot(PCIESlot *s)
{
QLIST_REMOVE(s, next);
}