[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulato
From: |
Isaku Yamahata |
Subject: |
[Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator. |
Date: |
Fri, 1 May 2009 22:17:02 +0900 |
Signed-off-by: Isaku Yamahata <address@hidden>
---
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 <assert.h>
#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