dev: Adding support for large BAR
authorPouya Fotouhi <Pouya.Fotouhi@amd.com>
Tue, 22 Oct 2019 22:29:57 +0000 (17:29 -0500)
committerPouya Fotouhi <pfotouhi@ucdavis.edu>
Wed, 30 Oct 2019 18:47:09 +0000 (18:47 +0000)
During PCI setup, this patch checks if a Base Address Register (BAR) is
used as a large BAR (64 bits rather than 32), and return proper address
range. The order which updates are done is decided by kernel, so this
patch implements both cases (writing lower or upper bits first).

Bit 2 in a BAR indicates a 64-bit decoder (10X to be more exact, 11X is
reserved).

The addresses in BARAddrs are full addresses and are set to zero for BAR
providing upper 32 bits to avoid conflicts in addr ranges reported.

Change-Id: I93303d36ac83dab9ed6837c81e77c9dfb778f409
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/22082
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/dev/pci/device.cc
src/dev/pci/device.hh

index 1097573f8817dd377ddbd9d900adff5d7639778d..e4c4eb170c00578d1ce451579a633974faae6675 100644 (file)
@@ -380,9 +380,30 @@ PciDevice::writeConfig(PacketPtr pkt)
                         // does it mean something special to write 0 to a BAR?
                         he_new_bar &= ~bar_mask;
                         if (he_new_bar) {
-                            BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
-                                hostInterface.pioAddr(he_new_bar) :
-                                hostInterface.memAddr(he_new_bar);
+                            if (isLargeBAR(barnum)) {
+                                if (BAR_IO_SPACE(he_old_bar))
+                                    warn("IO BARs can't be set as large BAR");
+                                uint64_t he_large_bar =
+                                         letoh(config.baseAddr[barnum + 1]);
+                                he_large_bar = he_large_bar << 32;
+                                he_large_bar += he_new_bar;
+                                BARAddrs[barnum] =
+                                        hostInterface.memAddr(he_large_bar);
+                            } else if (isLargeBAR(barnum - 1)) {
+                                BARAddrs[barnum] = 0;
+                                uint64_t he_large_bar = he_new_bar;
+                                he_large_bar = he_large_bar << 32;
+                                // We need to apply mask to lower bits
+                                he_large_bar +=
+                                         letoh(config.baseAddr[barnum - 1]
+                                         & ~bar_mask);
+                                BARAddrs[barnum - 1] =
+                                        hostInterface.memAddr(he_large_bar);
+                           } else {
+                                BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
+                                    hostInterface.pioAddr(he_new_bar) :
+                                    hostInterface.memAddr(he_new_bar);
+                            }
                             pioPort.sendRangeChange();
                         }
                     }
index ba783a6b1bbc4e9408b2fcd1a58518ba0f1f443b..d1545262ed575d29570e21bb9bc9aafef176e288 100644 (file)
@@ -115,6 +115,15 @@ class PciDevice : public DmaDevice
     /** Whether the BARs are really hardwired legacy IO locations. */
     bool legacyIO[6];
 
+    /**
+     * Does the given BAR represent 32 lower bits of a 64-bit address?
+     */
+    bool
+    isLargeBAR(int bar) const
+    {
+        return bits(config.baseAddr[bar], 2, 1) == 0x2;
+    }
+
     /**
      * Does the given address lie within the space mapped by the given
      * base address register?