From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LzpA0-0002Uz-Jl for qemu-devel@nongnu.org; Fri, 01 May 2009 05:36:00 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lzp9v-0002Tc-AS for qemu-devel@nongnu.org; Fri, 01 May 2009 05:35:59 -0400 Received: from [199.232.76.173] (port=44542 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lzp9u-0002TK-Qh for qemu-devel@nongnu.org; Fri, 01 May 2009 05:35:54 -0400 Received: from fms-01.valinux.co.jp ([210.128.90.1]:36576 helo=mail.valinux.co.jp) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Lzp9t-0002NX-HR for qemu-devel@nongnu.org; Fri, 01 May 2009 05:35:54 -0400 From: Isaku Yamahata Date: Fri, 1 May 2009 18:33:56 +0900 Message-Id: <1241170436-2800-5-git-send-email-yamahata@valinux.co.jp> In-Reply-To: <1241170436-2800-1-git-send-email-yamahata@valinux.co.jp> References: <1241170436-2800-1-git-send-email-yamahata@valinux.co.jp> Subject: [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator. List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: armbru@redhat.com, mst@redhat.com Signed-off-by: Isaku Yamahata --- hw/pci.c | 175 +++++++++++++++++++++++++++++++++++++++------------------ hw/pci.h | 30 ++++++++++ hw/unin_pci.c | 2 +- 3 files changed, 151 insertions(+), 56 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 0be3662..a1123cb 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include "hw.h" #include "pci.h" #include "monitor.h" @@ -461,6 +462,9 @@ void pci_default_write_config(PCIDevice *d, int can_write, i; uint32_t end, addr; + assert((d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION) == + PCI_HEADER_TYPE_NORMAL); + if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || (address >= 0x30 && address < 0x34))) { PCIIORegion *r; @@ -490,56 +494,28 @@ void pci_default_write_config(PCIDevice *d, /* not efficient, but simple */ addr = address; for(i = 0; i < len; i++) { - /* default read/write accesses */ - switch(d->config[0x0e]) { + /* default read/write accesses */ + switch(addr) { case 0x00: - case 0x80: - switch(addr) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0e: - case 0x10 ... 0x27: /* base */ - case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ - case 0x30 ... 0x33: /* rom */ - case 0x3d: - can_write = 0; - break; - default: - can_write = 1; - break; - } + case 0x01: + case 0x02: + case 0x03: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: + case 0x10 ... 0x27: /* base */ + case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ + case 0x30 ... 0x33: /* rom */ + case 0x3d: + can_write = 0; break; default: - case 0x01: - switch(addr) { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0e: - case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */ - case 0x38 ... 0x3b: /* rom */ - case 0x3d: - can_write = 0; - break; - default: - can_write = 1; - break; - } + can_write = 1; + break; } if (can_write) { @@ -836,18 +812,107 @@ typedef struct { static void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { + int can_write; PCIBridge *s = (PCIBridge *)d; + uint32_t addr = address; + int i; + + assert((d->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION) == + PCI_HEADER_TYPE_BRIDGE); + + for (i = 0; i < len; i++) { + uint8_t val8 = val & 0xff; + switch (addr) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0e: /* header type */ + case 0x10 ... 0x17: /* BAR */ + /* BAR0, BAR1, ROM isn't implemented. so RO to 0 */ + case 0x30 ... 0x33: /* IO base/limit upper 16bits. always 0*/ + case 0x38 ... 0x3b: /* rom */ + /* Expansion ROM isn't implemented. so RO to 0 */ + case 0x3d: + case PCI_BRIDGE_CONTROL: /* 0x3e */ + can_write = 0; + break; + + case PCI_COMMAND: /* 0x04 */ + val8 &= ~PCI_COMMAND_RESERVED_BRIDGE; + can_write = 1; + break; + case PCI_COMMAND + 1: /* 0x05 */ + val8 &= ~PCI_COMMAND_RESERVED_MASK_HI_BRIDGE; + can_write = 1; + break; - if (address == 0x19 || (address == 0x18 && len > 1)) { - if (address == 0x19) + case PCI_IO_BASE: /* 0x1c */ + case PCI_IO_LIMIT: /* 0x1d */ + val8 = (val8 & PCI_IO_RANGE_MASK) | + (d->config[addr] & ~PCI_IO_BASE); + can_write = 1; + break; + + case PCI_SECONDARY_BUS: /* 0x19 */ s->bus->bus_num = val & 0xff; - else - s->bus->bus_num = (val >> 8) & 0xff; -#if defined(DEBUG_PCI) - printf ("pci-bridge: %s: Assigned bus %d\n", d->name, s->bus->bus_num); -#endif + can_write = 1; + break; + + case PCI_MEMORY_BASE: /* 0x20 */ + case PCI_MEMORY_LIMIT: /* 0x22 */ + val8 = val8 & PCI_MEMORY_RANGE_MASK; + can_write = 1; + break; + case PCI_MEMORY_BASE + 1: /* 0x21 */ + case PCI_MEMORY_LIMIT + 1: /* 0x23 */ + can_write = 1; + break; + + case PCI_PREF_MEMORY_BASE: /* 0x24 */ + case PCI_PREF_MEMORY_LIMIT: /* 0x26*/ + val8 = val8 & PCI_PREF_RANGE_MASK; + can_write = 1; + break; + case PCI_PREF_MEMORY_BASE + 1: /* 0x25 */ + case PCI_PREF_MEMORY_LIMIT + 1: /* 0x27 */ + can_write = 1; + break; + + case PCI_PREF_BASE_UPPER32: /* 0x28 */ + case PCI_PREF_LIMIT_UPPER32: /* 0x2c */ + can_write = 0; + /* + val8 = val8 & PCI_PREF_RANGE_MASK; + can_write = 1; + */ + break; + case (PCI_PREF_BASE_UPPER32 + 1) ... (PCI_PREF_BASE_UPPER32 + 3): + /* 0x28 ... 2b */ + case (PCI_PREF_LIMIT_UPPER32 + 1) ... (PCI_PREF_LIMIT_UPPER32 + 3): + /* 0x2c ... 3f */ + can_write = 0; + /* can_write = 1; */ + break; + + default: + can_write = 1; + break; + } + + if (can_write) + d->config[addr] = val8; + + if (+addr > 0xff) + break; + val >>= 8; } - pci_default_write_config(d, address, val, len); } PCIBus *pci_find_bus(int bus_num) diff --git a/hw/pci.h b/hw/pci.h index 5993fb3..f5b1052 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -137,6 +137,36 @@ typedef struct PCIIORegion { #define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8) +/* Header type 1 (PCI-to-PCI bridges) */ +#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ + +#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ +#define PCI_IO_LIMIT 0x1d +#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ +#define PCI_IO_RANGE_TYPE_16 0x00 +#define PCI_IO_RANGE_TYPE_32 0x01 +#define PCI_IO_RANGE_MASK (~0x0fUL) +#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ +#define PCI_MEMORY_LIMIT 0x22 +#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL +#define PCI_MEMORY_RANGE_MASK (~0x0fUL) +#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ +#define PCI_PREF_MEMORY_LIMIT 0x26 +#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL +#define PCI_PREF_RANGE_TYPE_32 0x00 +#define PCI_PREF_RANGE_TYPE_64 0x01 +#define PCI_PREF_RANGE_MASK (~0x0fUL) +#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ +#define PCI_PREF_LIMIT_UPPER32 0x2c +#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ +#define PCI_IO_LIMIT_UPPER16 0x32 +#define PCI_BRIDGE_CONTROL 0x3e + +/* Bits in the PCI Command Register (PCI 2.3 spec) */ +#define PCI_COMMAND_RESERVED_BRIDGE 0xf880 + +#define PCI_COMMAND_RESERVED_MASK_HI_BRIDGE (PCI_COMMAND_RESERVED >> 8) + struct PCIDevice { /* PCI config space */ uint8_t config[256]; diff --git a/hw/unin_pci.c b/hw/unin_pci.c index b751916..d4c79fc 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -198,7 +198,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic) #if 0 // XXX: not activated as PPC BIOS doesn't handle multiple buses properly /* pci-to-pci bridge */ d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, - NULL, NULL); + NULL, pci_bridge_write_config); pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC); pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154); d->config[0x08] = 0x05; // revision -- 1.6.0.2