]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'pci-for-jesse' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
authorJesse Barnes <jbarnes@virtuousgeek.org>
Mon, 18 Aug 2008 16:54:13 +0000 (09:54 -0700)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Mon, 18 Aug 2008 16:54:13 +0000 (09:54 -0700)
Conflicts:

drivers/pci/probe.c

1  2 
drivers/pci/probe.c

diff --combined drivers/pci/probe.c
index a04498d390c85fbac5c4ec940b06f501bb076d2d,d2bd74ee3e0875c9f6211ed90ae7ab696b4a54a7..cce2f4cb1fbf37985d7303ec2e34d9f507d92aee
@@@ -52,49 -52,27 +52,49 @@@ EXPORT_SYMBOL(no_pci_devices)
   * Some platforms allow access to legacy I/O port and ISA memory space on
   * a per-bus basis.  This routine creates the files and ties them into
   * their associated read, write and mmap files from pci-sysfs.c
 + *
 + * On error unwind, but don't propogate the error to the caller
 + * as it is ok to set up the PCI bus without these files.
   */
  static void pci_create_legacy_files(struct pci_bus *b)
  {
 +      int error;
 +
        b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2,
                               GFP_ATOMIC);
 -      if (b->legacy_io) {
 -              b->legacy_io->attr.name = "legacy_io";
 -              b->legacy_io->size = 0xffff;
 -              b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
 -              b->legacy_io->read = pci_read_legacy_io;
 -              b->legacy_io->write = pci_write_legacy_io;
 -              device_create_bin_file(&b->dev, b->legacy_io);
 -
 -              /* Allocated above after the legacy_io struct */
 -              b->legacy_mem = b->legacy_io + 1;
 -              b->legacy_mem->attr.name = "legacy_mem";
 -              b->legacy_mem->size = 1024*1024;
 -              b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
 -              b->legacy_mem->mmap = pci_mmap_legacy_mem;
 -              device_create_bin_file(&b->dev, b->legacy_mem);
 -      }
 +      if (!b->legacy_io)
 +              goto kzalloc_err;
 +
 +      b->legacy_io->attr.name = "legacy_io";
 +      b->legacy_io->size = 0xffff;
 +      b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
 +      b->legacy_io->read = pci_read_legacy_io;
 +      b->legacy_io->write = pci_write_legacy_io;
 +      error = device_create_bin_file(&b->dev, b->legacy_io);
 +      if (error)
 +              goto legacy_io_err;
 +
 +      /* Allocated above after the legacy_io struct */
 +      b->legacy_mem = b->legacy_io + 1;
 +      b->legacy_mem->attr.name = "legacy_mem";
 +      b->legacy_mem->size = 1024*1024;
 +      b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
 +      b->legacy_mem->mmap = pci_mmap_legacy_mem;
 +      error = device_create_bin_file(&b->dev, b->legacy_mem);
 +      if (error)
 +              goto legacy_mem_err;
 +
 +      return;
 +
 +legacy_mem_err:
 +      device_remove_bin_file(&b->dev, b->legacy_io);
 +legacy_io_err:
 +      kfree(b->legacy_io);
 +      b->legacy_io = NULL;
 +kzalloc_err:
 +      printk(KERN_WARNING "pci: warning: could not create legacy I/O port "
 +             "and ISA memory resources to sysfs\n");
 +      return;
  }
  
  void pci_remove_legacy_files(struct pci_bus *b)
@@@ -185,9 -163,12 +185,9 @@@ static inline unsigned int pci_calc_res
        return IORESOURCE_MEM;
  }
  
 -/*
 - * Find the extent of a PCI decode..
 - */
 -static u32 pci_size(u32 base, u32 maxbase, u32 mask)
 +static u64 pci_size(u64 base, u64 maxbase, u64 mask)
  {
 -      u32 size = mask & maxbase;      /* Find the significant bits */
 +      u64 size = mask & maxbase;      /* Find the significant bits */
        if (!size)
                return 0;
  
        return size;
  }
  
 -static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
 +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)
  {
 -      u64 size = mask & maxbase;      /* Find the significant bits */
 -      if (!size)
 -              return 0;
 +      if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
 +              res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
 +              return pci_bar_io;
 +      }
  
 -      /* Get the lowest of them to find the decode size, and
 -         from that the extent.  */
 -      size = (size & ~(size-1)) - 1;
 +      res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
  
 -      /* base == maxbase can be valid only if the BAR has
 -         already been programmed with all 1s.  */
 -      if (base == maxbase && ((base | size) & mask) != mask)
 -              return 0;
 -
 -      return size;
 +      if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64)
 +              return pci_bar_mem64;
 +      return pci_bar_mem32;
  }
  
 -static inline int is_64bit_memory(u32 mask)
 +/*
 + * 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)
  {
 -      if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
 -          (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
 -              return 1;
 -      return 0;
 -}
 +      u32 l, sz, mask;
  
 -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;
 +      mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0;
  
 -      for(pos=0; pos<howmany; pos = next) {
 -              u64 l64;
 -              u64 sz64;
 -              u32 raw_sz;
 +      res->name = pci_name(dev);
  
 -              next = pos+1;
 -              res = &dev->resource[pos];
 -              res->name = pci_name(dev);
 -              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;
 -              raw_sz = sz;
 -              if ((l & PCI_BASE_ADDRESS_SPACE) ==
 -                              PCI_BASE_ADDRESS_SPACE_MEMORY) {
 -                      sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
 -                      /*
 -                       * For 64bit prefetchable memory sz could be 0, if the
 -                       * real size is bigger than 4G, so we need to check
 -                       * szhi for that.
 -                       */
 -                      if (!is_64bit_memory(l) && !sz)
 -                              continue;
 -                      res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
 -                      res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
 +      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) | IORESOURCE_SIZEALIGN;
 +              if (type == pci_bar_io) {
 +                      l &= PCI_BASE_ADDRESS_IO_MASK;
 +                      mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
                } 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;
 +                      l &= PCI_BASE_ADDRESS_MEM_MASK;
 +                      mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
                }
 -              res->end = res->start + (unsigned long) sz;
 -              res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
 -              if (is_64bit_memory(l)) {
 -                      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);
 -                      sz64 = ((u64)szhi << 32) | raw_sz;
 -                      l64 = ((u64)lhi << 32) | l;
 -                      sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
 -                      next++;
 -#if BITS_PER_LONG == 64
 -                      if (!sz64) {
 -                              res->start = 0;
 -                              res->end = 0;
 -                              res->flags = 0;
 -                              continue;
 -                      }
 -                      res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
 -                      res->end = res->start + sz64;
 -                      printk(KERN_INFO "PCI: %s reg %x 64bit mmio: [%llx, %llx]\n", pci_name(dev), reg, res->start, res->end);
 -#else
 -                      if (sz64 > 0x100000000ULL) {
 -                              dev_err(&dev->dev, "BAR %d: can't handle 64-bit"
 -                                      " BAR\n", pos);
 -                              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
 +      } 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 ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) {
 +                      dev_err(&dev->dev, "can't handle 64-bit BAR\n");
 +                      goto fail;
 +              } else if ((sizeof(resource_size_t) < 8) && 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 {
 -                      printk(KERN_INFO "PCI: %s reg %x %s: [%llx, %llx]\n", pci_name(dev), reg, (res->flags & IORESOURCE_IO)? "io port":"32bit mmio", res->start, res->end);
 +                      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;
 +
 +      for (pos = 0; pos < howmany; pos++) {
 +              struct resource *res = &dev->resource[pos];
 +              reg = PCI_BASE_ADDRESS_0 + (pos << 2);
 +              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 |
 -                                IORESOURCE_SIZEALIGN;
 -                              res->start = l & PCI_ROM_ADDRESS_MASK;
 -                              res->end = res->start + (unsigned long) sz;
 -                      }
 -              }
 +              res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
 +                              IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
 +                              IORESOURCE_SIZEALIGN;
 +              __pci_read_base(dev, pci_bar_mem32, res, rom);
        }
  }
  
@@@ -383,6 -360,7 +383,7 @@@ void __devinit pci_read_bridge_bases(st
                        res->start = base;
                if (!res->end)
                        res->end = limit + 0xfff;
+               printk(KERN_INFO "PCI: bridge %s io port: [%llx, %llx]\n", pci_name(dev), res->start, res->end);
        }
  
        res = child->resource[1];
                res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
                res->start = base;
                res->end = limit + 0xfffff;
+               printk(KERN_INFO "PCI: bridge %s 32bit mmio: [%llx, %llx]\n", pci_name(dev), res->start, res->end);
        }
  
        res = child->resource[2];
                res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
                res->start = base;
                res->end = limit + 0xfffff;
+               printk(KERN_INFO "PCI: bridge %s %sbit mmio pref: [%llx, %llx]\n", pci_name(dev), (res->flags & PCI_PREF_RANGE_TYPE_64)?"64":"32",res->start, res->end);
        }
  }
  
@@@ -1079,8 -1059,7 +1082,8 @@@ int pci_scan_slot(struct pci_bus *bus, 
                }
        }
  
 -      if (bus->self)
 +      /* only one slot has pcie device */
 +      if (bus->self && nr)
                pcie_aspm_init_link_state(bus->self);
  
        return nr;