Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ee53f4c authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/bjorn-p2p-bridge-windows' into next

* pci/bjorn-p2p-bridge-windows:
  sparc/PCI: replace pci_cfg_fake_ranges() with pci_read_bridge_bases()
  PCI: support sizing P2P bridge I/O windows with 1K granularity
  PCI: reimplement P2P bridge 1K I/O windows (Intel P64H2)
  PCI: allow P2P bridge windows starting at PCI bus address zero

Conflicts:
	drivers/pci/probe.c
	include/linux/pci.h
parents d68e70c6 1c975931
Loading
Loading
Loading
Loading
+1 −88
Original line number Diff line number Diff line
@@ -375,93 +375,6 @@ static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
	*last_p = last;
}

/* For PCI bus devices which lack a 'ranges' property we interrogate
 * the config space values to set the resources, just like the generic
 * Linux PCI probing code does.
 */
static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
					  struct pci_bus *bus,
					  struct pci_pbm_info *pbm)
{
	struct pci_bus_region region;
	struct resource *res, res2;
	u8 io_base_lo, io_limit_lo;
	u16 mem_base_lo, mem_limit_lo;
	unsigned long base, limit;

	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;

	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
		u16 io_base_hi, io_limit_hi;

		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
		base |= (io_base_hi << 16);
		limit |= (io_limit_hi << 16);
	}

	res = bus->resource[0];
	if (base <= limit) {
		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
		res2.flags = res->flags;
		region.start = base;
		region.end = limit + 0xfff;
		pcibios_bus_to_resource(dev, &res2, &region);
		if (!res->start)
			res->start = res2.start;
		if (!res->end)
			res->end = res2.end;
	}

	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;

	res = bus->resource[1];
	if (base <= limit) {
		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
			      IORESOURCE_MEM);
		region.start = base;
		region.end = limit + 0xfffff;
		pcibios_bus_to_resource(dev, res, &region);
	}

	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;

	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
		u32 mem_base_hi, mem_limit_hi;

		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);

		/*
		 * Some bridges set the base > limit by default, and some
		 * (broken) BIOSes do not initialize them.  If we find
		 * this, just assume they are not being used.
		 */
		if (mem_base_hi <= mem_limit_hi) {
			base |= ((long) mem_base_hi) << 32;
			limit |= ((long) mem_limit_hi) << 32;
		}
	}

	res = bus->resource[2];
	if (base <= limit) {
		res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
			      IORESOURCE_MEM | IORESOURCE_PREFETCH);
		region.start = base;
		region.end = limit + 0xfffff;
		pcibios_bus_to_resource(dev, res, &region);
	}
}

/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
 * a proper 'ranges' property.
 */
@@ -550,7 +463,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
		apb_fake_ranges(dev, bus, pbm);
		goto after_ranges;
	} else if (ranges == NULL) {
		pci_cfg_fake_ranges(dev, bus, pbm);
		pci_read_bridge_bases(bus);
		goto after_ranges;
	}
	i = 1;
+17 −14
Original line number Diff line number Diff line
@@ -306,15 +306,23 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
{
	struct pci_dev *dev = child->self;
	u8 io_base_lo, io_limit_lo;
	unsigned long base, limit;
	unsigned long io_mask, io_granularity, base, limit;
	struct pci_bus_region region;
	struct resource *res, res2;
	struct resource *res;

	io_mask = PCI_IO_RANGE_MASK;
	io_granularity = 0x1000;
	if (dev->io_window_1k) {
		/* Support 1K I/O space granularity */
		io_mask = PCI_IO_1K_RANGE_MASK;
		io_granularity = 0x400;
	}

	res = child->resource[0];
	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
	base = (io_base_lo & io_mask) << 8;
	limit = (io_limit_lo & io_mask) << 8;

	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
		u16 io_base_hi, io_limit_hi;
@@ -325,16 +333,11 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
		limit |= ((unsigned long) io_limit_hi << 16);
	}

	if (base && base <= limit) {
	if (base <= limit) {
		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
		res2.flags = res->flags;
		region.start = base;
		region.end = limit + 0xfff;
		pcibios_bus_to_resource(dev, &res2, &region);
		if (!res->start)
			res->start = res2.start;
		if (!res->end)
			res->end = res2.end;
		region.end = limit + io_granularity - 1;
		pcibios_bus_to_resource(dev, res, &region);
		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
	}
}
@@ -352,7 +355,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
	base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
	limit = ((unsigned long) mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
	if (base && base <= limit) {
	if (base <= limit) {
		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
		region.start = base;
		region.end = limit + 0xfffff;
@@ -399,7 +402,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
#endif
		}
	}
	if (base && base <= limit) {
	if (base <= limit) {
		res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
					 IORESOURCE_MEM | IORESOURCE_PREFETCH;
		if (res->flags & PCI_PREF_RANGE_TYPE_64)
+1 −38
Original line number Diff line number Diff line
@@ -1938,53 +1938,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
{
	u16 en1k;
	u8 io_base_lo, io_limit_lo;
	unsigned long base, limit;
	struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;

	pci_read_config_word(dev, 0x40, &en1k);

	if (en1k & 0x200) {
		dev_info(&dev->dev, "Enable I/O Space to 1KB granularity\n");

		pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
		pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
		base = (io_base_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8;
		limit = (io_limit_lo & (PCI_IO_RANGE_MASK | 0x0c)) << 8;

		if (base <= limit) {
			res->start = base;
			res->end = limit + 0x3ff;
		}
		dev->io_window_1k = 1;
	}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	0x1460,		quirk_p64h2_1k_io);

/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
 * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
 * in drivers/pci/setup-bus.c
 */
static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
{
	u16 en1k, iobl_adr, iobl_adr_1k;
	struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;

	pci_read_config_word(dev, 0x40, &en1k);

	if (en1k & 0x200) {
		pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);

		iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);

		if (iobl_adr != iobl_adr_1k) {
			dev_info(&dev->dev, "Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1KB granularity\n",
				iobl_adr,iobl_adr_1k);
			pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
		}
	}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x1460,		quirk_p64h2_1k_io_fix_iobl);

/* Under some circumstances, AER is not linked with extended capabilities.
 * Force it to be linked by setting the corresponding control bit in the
 * config space.
+31 −8
Original line number Diff line number Diff line
@@ -469,16 +469,23 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
	struct pci_dev *bridge = bus->self;
	struct resource *res;
	struct pci_bus_region region;
	unsigned long io_mask;
	u8 io_base_lo, io_limit_lo;
	u32 l, io_upper16;

	io_mask = PCI_IO_RANGE_MASK;
	if (bridge->io_window_1k)
		io_mask = PCI_IO_1K_RANGE_MASK;

	/* Set up the top and bottom of the PCI I/O segment for this bus. */
	res = bus->resource[0];
	pcibios_resource_to_bus(bridge, &region, res);
	if (res->flags & IORESOURCE_IO) {
		pci_read_config_dword(bridge, PCI_IO_BASE, &l);
		l &= 0xffff0000;
		l |= (region.start >> 8) & 0x00f0;
		l |= region.end & 0xf000;
		io_base_lo = (region.start >> 8) & io_mask;
		io_limit_lo = (region.end >> 8) & io_mask;
		l |= ((u32) io_limit_lo << 8) | io_base_lo;
		/* Set up upper 16 bits of I/O base/limit. */
		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
		dev_info(&bridge->dev, "  bridge window %pR\n", res);
@@ -699,7 +706,7 @@ static resource_size_t calculate_memsize(resource_size_t size,
 * @realloc_head : track the additional io window on this list
 *
 * Sizing the IO windows of the PCI-PCI bridge is trivial,
 * since these windows have 4K granularity and the IO ranges
 * since these windows have 1K or 4K granularity and the IO ranges
 * of non-bridge PCI devices are limited to 256 bytes.
 * We must be careful with the ISA aliasing though.
 */
@@ -710,10 +717,17 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
	unsigned long size = 0, size0 = 0, size1 = 0;
	resource_size_t children_add_size = 0;
	resource_size_t min_align = 4096, align;

	if (!b_res)
 		return;

	/*
	 * Per spec, I/O windows are 4K-aligned, but some bridges have an
	 * extension to support 1K alignment.
	 */
	if (bus->self->io_window_1k)
		min_align = 1024;
	list_for_each_entry(dev, &bus->devices, bus_list) {
		int i;

@@ -731,17 +745,25 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
			else
				size1 += r_size;

			align = pci_resource_alignment(dev, r);
			if (align > min_align)
				min_align = align;

			if (realloc_head)
				children_add_size += get_res_add_size(realloc_head, r);
		}
	}

	if (min_align > 4096)
		min_align = 4096;

	size0 = calculate_iosize(size, min_size, size1,
			resource_size(b_res), 4096);
			resource_size(b_res), min_align);
	if (children_add_size > add_size)
		add_size = children_add_size;
	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
		calculate_iosize(size, min_size, add_size + size1,
			resource_size(b_res), 4096);
			resource_size(b_res), min_align);
	if (!size0 && !size1) {
		if (b_res->start || b_res->end)
			dev_info(&bus->self->dev, "disabling bridge window "
@@ -750,12 +772,13 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
		b_res->flags = 0;
		return;
	}
	/* Alignment of the IO window is always 4K */
	b_res->start = 4096;

	b_res->start = min_align;
	b_res->end = b_res->start + size0 - 1;
	b_res->flags |= IORESOURCE_STARTALIGN;
	if (size1 > size0 && realloc_head) {
		add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);
		add_to_list(realloc_head, bus->self, b_res, size1-size0,
			    min_align);
		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
				 "%pR to %pR add_size %lx\n", b_res,
				 &bus->busn_res, size1-size0);
+1 −0
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ struct pci_dev {
	unsigned int    __aer_firmware_first_valid:1;
	unsigned int	__aer_firmware_first:1;
	unsigned int	broken_intx_masking:1;
	unsigned int	io_window_1k:1;	/* Intel P2P bridge 1K I/O windows */
	pci_dev_flags_t dev_flags;
	atomic_t	enable_cnt;	/* pci_enable_device has been called */

Loading