qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Isaku Yamahata <yamahata@valinux.co.jp>
To: qemu-devel@nongnu.org
Cc: armbru@redhat.com, mst@redhat.com
Subject: [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator.
Date: Fri,  1 May 2009 18:33:56 +0900	[thread overview]
Message-ID: <1241170436-2800-5-git-send-email-yamahata@valinux.co.jp> (raw)
In-Reply-To: <1241170436-2800-1-git-send-email-yamahata@valinux.co.jp>

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 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

  parent reply	other threads:[~2009-05-01  9:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-01  9:33 [Qemu-devel] [PATCH 00/04] RFC: pci bridge clean up and multiple pci bus support Isaku Yamahata
2009-05-01  9:33 ` [Qemu-devel] [PATCH] minor fix of pci_register_bus() Isaku Yamahata
2009-05-01  9:33 ` [Qemu-devel] [PATCH] use PCI_HEADER_TYPE Isaku Yamahata
2009-05-01  9:33 ` [Qemu-devel] [PATCH] pci bus: preliminary for multi pci bus support Isaku Yamahata
2009-05-01  9:33 ` Isaku Yamahata [this message]
2009-05-01 14:17   ` [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator M. Warner Losh
2009-05-04 16:06     ` Isaku Yamahata
  -- strict thread matches above, loose matches on Subject: below --
2009-05-01 13:16 [Qemu-devel] [RFC PATCH 00/04] pci bridge clean up and multiple pci bus support Isaku Yamahata
2009-05-01 13:17 ` [Qemu-devel] [PATCH] try to implement complete pci-to-pci bridge emulator Isaku Yamahata

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1241170436-2800-5-git-send-email-yamahata@valinux.co.jp \
    --to=yamahata@valinux.co.jp \
    --cc=armbru@redhat.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).