WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [linux-2.6.18-xen] Backport: PCI: rewrite PCI BAR readin

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] Backport: PCI: rewrite PCI BAR reading code
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 13 Mar 2009 00:50:15 -0700
Delivery-date: Fri, 13 Mar 2009 00:51:24 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1236929988 0
# Node ID bca9d4cfbca27ddd955c533367a11a20062fdce5
# Parent  0430b1dbfb3af5f374921b903c96b9b3234cd77c
Backport: PCI: rewrite PCI BAR reading code

    commit 6ac665c63dcac8fcec534a1d224ecbb8b867ad59
    Author: Matthew Wilcox <matthew@xxxxxx>
    Date:   Mon Jul 28 13:38:59 2008 -0400

    PCI: rewrite PCI BAR reading code

    Factor out the code to read one BAR from the loop in
    pci_read_bases into
    a new function, __pci_read_base.  The new code is slightly more
    readable, better commented and removes the ifdef.

    Signed-off-by: Matthew Wilcox <willy@xxxxxxxxxxxxxxx>
    Signed-off-by: Jesse Barnes <jbarnes@xxxxxxxxxxxxxxxx>

Signed-off-by: Yu Zhao <yu.zhao@xxxxxxxxx>
---
 drivers/pci/probe.c |  219 +++++++++++++++++++++++++++++++---------------------
 1 files changed, 133 insertions(+), 86 deletions(-)

diff -r 0430b1dbfb3a -r bca9d4cfbca2 drivers/pci/probe.c
--- a/drivers/pci/probe.c       Fri Mar 06 12:51:33 2009 +0000
+++ b/drivers/pci/probe.c       Fri Mar 13 07:39:48 2009 +0000
@@ -123,12 +123,9 @@ static inline unsigned int pci_calc_reso
        return IORESOURCE_MEM;
 }
 
-/*
- * Find the extent of a PCI decode..
- */
-static u32 pci_size(u32 base, u32 maxbase, u32 mask)
-{
-       u32 size = mask & maxbase;      /* Find the significant bits */
+static u64 pci_size(u64 base, u64 maxbase, u64 mask)
+{
+       u64 size = mask & maxbase;      /* Find the significant bits */
        if (!size)
                return 0;
 
@@ -144,91 +141,141 @@ static u32 pci_size(u32 base, u32 maxbas
        return size;
 }
 
+enum pci_bar_type {
+       pci_bar_unknown,        /* Standard PCI BAR probe */
+       pci_bar_io,             /* An io port BAR */
+       pci_bar_mem32,          /* A 32-bit memory BAR */
+       pci_bar_mem64,          /* A 64-bit memory BAR */
+};
+
+static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
+{
+       if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+               res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
+               return pci_bar_io;
+       }
+
+       res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
+
+       if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64)
+               return pci_bar_mem64;
+       return pci_bar_mem32;
+}
+
+/*
+ * If the type is not unknown, we assume that the lowest bit is 'enable'.
+ * Returns 1 if the BAR was 64-bit and 0 if it was 32-bit.
+ */
+static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+                       struct resource *res, unsigned int pos)
+{
+       u32 l, sz, mask;
+
+       mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0;
+
+       res->name = pci_name(dev);
+
+       pci_read_config_dword(dev, pos, &l);
+       pci_write_config_dword(dev, pos, mask);
+       pci_read_config_dword(dev, pos, &sz);
+       pci_write_config_dword(dev, pos, l);
+
+       /*
+        * All bits set in sz means the device isn't working properly.
+        * If the BAR isn't implemented, all bits must be 0.  If it's a
+        * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit
+        * 1 must be clear.
+        */
+       if (!sz || sz == 0xffffffff)
+               goto fail;
+
+       /*
+        * I don't know how l can have all bits set.  Copied from old code.
+        * Maybe it fixes a bug on some ancient platform.
+        */
+       if (l == 0xffffffff)
+               l = 0;
+
+       if (type == pci_bar_unknown) {
+               type = decode_bar(res, l);
+               res->flags |= pci_calc_resource_flags(l);
+               if (type == pci_bar_io) {
+                       l &= PCI_BASE_ADDRESS_IO_MASK;
+                       mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
+               } else {
+                       l &= PCI_BASE_ADDRESS_MEM_MASK;
+                       mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+               }
+       } else {
+               res->flags |= (l & IORESOURCE_ROM_ENABLE);
+               l &= PCI_ROM_ADDRESS_MASK;
+               mask = (u32)PCI_ROM_ADDRESS_MASK;
+       }
+
+       if (type == pci_bar_mem64) {
+               u64 l64 = l;
+               u64 sz64 = sz;
+               u64 mask64 = mask | (u64)~0 << 32;
+
+               pci_read_config_dword(dev, pos + 4, &l);
+               pci_write_config_dword(dev, pos + 4, ~0);
+               pci_read_config_dword(dev, pos + 4, &sz);
+               pci_write_config_dword(dev, pos + 4, l);
+
+               l64 |= ((u64)l << 32);
+               sz64 |= ((u64)sz << 32);
+
+               sz64 = pci_size(l64, sz64, mask64);
+
+               if (!sz64)
+                       goto fail;
+
+               if ((BITS_PER_LONG < 64) && (sz64 > 0x100000000ULL)) {
+                       dev_err(&dev->dev, "can't handle 64-bit BAR\n");
+                       goto fail;
+               } else if ((BITS_PER_LONG < 64) && l) {
+                       /* Address above 32-bit boundary; disable the BAR */
+                       pci_write_config_dword(dev, pos, 0);
+                       pci_write_config_dword(dev, pos + 4, 0);
+                       res->start = 0;
+                       res->end = sz64;
+               } else {
+                       res->start = l64;
+                       res->end = l64 + sz64;
+               }
+       } else {
+               sz = pci_size(l, sz, mask);
+
+               if (!sz)
+                       goto fail;
+
+               res->start = l;
+               res->end = l + sz;
+       }
+
+ out:
+       return (type == pci_bar_mem64) ? 1 : 0;
+ fail:
+       res->flags = 0;
+       goto out;
+}
+
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
 {
-       unsigned int pos, reg, next;
-       u32 l, sz;
-       struct resource *res;
-
-       for(pos=0; pos<howmany; pos = next) {
-               next = pos+1;
-               res = &dev->resource[pos];
-               res->name = pci_name(dev);
+       unsigned int pos, reg;
+
+       for (pos = 0; pos < howmany; pos++) {
+               struct resource *res = &dev->resource[pos];
                reg = PCI_BASE_ADDRESS_0 + (pos << 2);
-               pci_read_config_dword(dev, reg, &l);
-               pci_write_config_dword(dev, reg, ~0);
-               pci_read_config_dword(dev, reg, &sz);
-               pci_write_config_dword(dev, reg, l);
-               if (!sz || sz == 0xffffffff)
-                       continue;
-               if (l == 0xffffffff)
-                       l = 0;
-               if ((l & PCI_BASE_ADDRESS_SPACE) == 
PCI_BASE_ADDRESS_SPACE_MEMORY) {
-                       sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
-                       if (!sz)
-                               continue;
-                       res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
-                       res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
-               } else {
-                       sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
-                       if (!sz)
-                               continue;
-                       res->start = l & PCI_BASE_ADDRESS_IO_MASK;
-                       res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
-               }
-               res->end = res->start + (unsigned long) sz;
-               res->flags |= pci_calc_resource_flags(l);
-               if ((l & (PCI_BASE_ADDRESS_SPACE | 
PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-                   == (PCI_BASE_ADDRESS_SPACE_MEMORY | 
PCI_BASE_ADDRESS_MEM_TYPE_64)) {
-                       u32 szhi, lhi;
-                       pci_read_config_dword(dev, reg+4, &lhi);
-                       pci_write_config_dword(dev, reg+4, ~0);
-                       pci_read_config_dword(dev, reg+4, &szhi);
-                       pci_write_config_dword(dev, reg+4, lhi);
-                       szhi = pci_size(lhi, szhi, 0xffffffff);
-                       next++;
-#if BITS_PER_LONG == 64
-                       res->start |= ((unsigned long) lhi) << 32;
-                       res->end = res->start + sz;
-                       if (szhi) {
-                               /* This BAR needs > 4GB?  Wow. */
-                               res->end |= (unsigned long)szhi<<32;
-                       }
-#else
-                       if (szhi) {
-                               printk(KERN_ERR "PCI: Unable to handle 64-bit 
BAR for device %s\n", pci_name(dev));
-                               res->start = 0;
-                               res->flags = 0;
-                       } else if (lhi) {
-                               /* 64-bit wide address, treat as disabled */
-                               pci_write_config_dword(dev, reg, l & 
~(u32)PCI_BASE_ADDRESS_MEM_MASK);
-                               pci_write_config_dword(dev, reg+4, 0);
-                               res->start = 0;
-                               res->end = sz;
-                       }
-#endif
-               }
-       }
+               pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
+       }
+
        if (rom) {
+               struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
                dev->rom_base_reg = rom;
-               res = &dev->resource[PCI_ROM_RESOURCE];
-               res->name = pci_name(dev);
-               pci_read_config_dword(dev, rom, &l);
-               pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
-               pci_read_config_dword(dev, rom, &sz);
-               pci_write_config_dword(dev, rom, l);
-               if (l == 0xffffffff)
-                       l = 0;
-               if (sz && sz != 0xffffffff) {
-                       sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
-                       if (sz) {
-                               res->flags = (l & IORESOURCE_ROM_ENABLE) |
-                                 IORESOURCE_MEM | IORESOURCE_PREFETCH |
-                                 IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
-                               res->start = l & PCI_ROM_ADDRESS_MASK;
-                               res->end = res->start + (unsigned long) sz;
-                       }
-               }
+               res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
+                               IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+               __pci_read_base(dev, pci_bar_mem32, res, rom);
        }
 }
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] Backport: PCI: rewrite PCI BAR reading code, Xen patchbot-linux-2.6.18-xen <=