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

Commit 3ec829b6 authored by John Keller's avatar John Keller Committed by Tony Luck
Browse files

[IA64-SGI] altix: pci_window fixup



Altix only patch to add fixup code that sets up
pci_controller->window. This code is a temporary
fix until ACPI support on Altix is added.

Also, corrects the usage of pci_dev->sysdata,
which had previously been used to reference
platform specific device info, to now point to
a pci_controller struct.

Signed-off-by: default avatarJohn Keller <jpk@sgi.com>
Signed-off-by: default avatarTony Luck <tony.luck@intel.com>
parent 3e356b26
Loading
Loading
Loading
Loading
+131 −22
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
 */

#include <linux/bootmem.h>
@@ -146,6 +146,24 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
	return ret_stuff.v0;
}

/*
 * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
 *			  device.
 */
inline struct pcidev_info *
sn_pcidev_info_get(struct pci_dev *dev)
{
	struct pcidev_info *pcidev;

	list_for_each_entry(pcidev,
			    &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) {
		if (pcidev->pdi_linux_pcidev == dev) {
			return pcidev;
		}
	}
	return NULL;
}

/*
 * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 
 *	each node in the system.
@@ -229,6 +247,50 @@ static void sn_fixup_ionodes(void)

}

/*
 * sn_pci_window_fixup() - Create a pci_window for each device resource.
 *			   Until ACPI support is added, we need this code
 *			   to setup pci_windows for use by
 *			   pcibios_bus_to_resource(),
 *			   pcibios_resource_to_bus(), etc.
 */
static void
sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
		    int64_t * pci_addrs)
{
	struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
	unsigned int i;
	unsigned int idx;
	unsigned int new_count;
	struct pci_window *new_window;

	if (count == 0)
		return;
	idx = controller->windows;
	new_count = controller->windows + count;
	new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
	if (new_window == NULL)
		BUG();
	if (controller->window) {
		memcpy(new_window, controller->window,
		       sizeof(struct pci_window) * controller->windows);
		kfree(controller->window);
	}

	/* Setup a pci_window for each device resource. */
	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
		if (pci_addrs[i] == -1)
			continue;

		new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
		new_window[idx].resource = dev->resource[i];
		idx++;
	}

	controller->windows = new_count;
	controller->window = new_window;
}

void sn_pci_unfixup_slot(struct pci_dev *dev)
{
	struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
@@ -246,21 +308,23 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
 */
void sn_pci_fixup_slot(struct pci_dev *dev)
{
	unsigned int count = 0;
	int idx;
	int segment = pci_domain_nr(dev->bus);
	int status = 0;
	struct pcibus_bussoft *bs;
 	struct pci_bus *host_pci_bus;
 	struct pci_dev *host_pci_dev;
	struct pcidev_info *pcidev_info;
	int64_t pci_addrs[PCI_ROM_RESOURCE + 1];
 	struct sn_irq_info *sn_irq_info;
 	unsigned long size;
 	unsigned int bus_no, devfn;

	pci_dev_get(dev); /* for the sysdata pointer */
	dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
	if (SN_PCIDEV_INFO(dev) <= 0)
	pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
	if (pcidev_info <= 0)
		BUG();		/* Cannot afford to run out of memory */
	memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));

	sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
	if (sn_irq_info <= 0)
@@ -270,22 +334,34 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
	/* Call to retrieve pci device information needed by kernel. */
	status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, 
				     dev->devfn,
				     (u64) __pa(SN_PCIDEV_INFO(dev)),
				     (u64) __pa(pcidev_info),
				     (u64) __pa(sn_irq_info));
	if (status)
		BUG(); /* Cannot get platform pci device information */

	/* Add pcidev_info to list in sn_pci_controller struct */
	list_add_tail(&pcidev_info->pdi_list,
		      &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info));

	/* Copy over PIO Mapped Addresses */
	for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
		unsigned long start, end, addr;

		if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx])
		if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
			pci_addrs[idx] = -1;
			continue;
		}

		start = dev->resource[idx].start;
		end = dev->resource[idx].end;
		size = end - start;
		addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx];
		if (size == 0) {
			pci_addrs[idx] = -1;
			continue;
		}
		pci_addrs[idx] = start;
		count++;
		addr = pcidev_info->pdi_pio_mapped_addr[idx];
		addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
		dev->resource[idx].start = addr;
		dev->resource[idx].end = addr + size;
@@ -294,23 +370,27 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
		else
			dev->resource[idx].parent = &iomem_resource;
	}
	/* Create a pci_window in the pci_controller struct for
	 * each device resource.
	 */
	if (count > 0)
		sn_pci_window_fixup(dev, count, pci_addrs);

	/*
	 * Using the PROMs values for the PCI host bus, get the Linux
 	 * PCI host_pci_dev struct and set up host bus linkages
 	 */

 	bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
 	devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
	bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
	devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
 	host_pci_bus = pci_find_bus(segment, bus_no);
 	host_pci_dev = pci_get_slot(host_pci_bus, devfn);

	SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
	SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
	    					SN_PCIDEV_INFO(host_pci_dev);
	SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
	pcidev_info->host_pci_dev = host_pci_dev;
	pcidev_info->pdi_linux_pcidev = dev;
	pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
	bs = SN_PCIBUS_BUSSOFT(dev->bus);
	SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
	pcidev_info->pdi_pcibus_info = bs;

	if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
		SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
@@ -320,11 +400,11 @@ void sn_pci_fixup_slot(struct pci_dev *dev)

	/* Only set up IRQ stuff if this device has a host bus context */
	if (bs && sn_irq_info->irq_irq) {
		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
		dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
		pcidev_info->pdi_sn_irq_info = sn_irq_info;
		dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
		sn_irq_fixup(dev, sn_irq_info);
	} else {
		SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
		pcidev_info->pdi_sn_irq_info = NULL;
		kfree(sn_irq_info);
	}
}
@@ -338,6 +418,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
	int status = 0;
	int nasid, cnode;
	struct pci_controller *controller;
	struct sn_pci_controller *sn_controller;
	struct pcibus_bussoft *prom_bussoft_ptr;
	struct hubdev_info *hubdev_info;
	void *provider_soft = NULL;
@@ -349,10 +430,15 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
		return;		/*bus # does not exist */
	prom_bussoft_ptr = __va(prom_bussoft_ptr);

 	controller = kzalloc(sizeof(struct pci_controller), GFP_KERNEL);
	controller->segment = segment;
 	if (!controller)
	/* Allocate a sn_pci_controller, which has a pci_controller struct
	 * as the first member.
	 */
	sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL);
	if (!sn_controller)
		BUG();
	INIT_LIST_HEAD(&sn_controller->pcidev_info);
	controller = &sn_controller->pci_controller;
	controller->segment = segment;

	if (bus == NULL) {
 		bus = pci_scan_bus(busnum, &pci_root_ops, controller);
@@ -389,6 +475,29 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
		goto error_return;
	}

	/*
	 * Setup pci_windows for legacy IO and MEM space.
	 * (Temporary until ACPI support is in place.)
	 */
	controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL);
	if (controller->window == NULL)
		BUG();
	controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io;
	controller->window[0].resource.name = "legacy_io";
	controller->window[0].resource.flags = IORESOURCE_IO;
	controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io;
	controller->window[0].resource.end =
	    controller->window[0].resource.start + 0xffff;
	controller->window[0].resource.parent = &ioport_resource;
	controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem;
	controller->window[1].resource.name = "legacy_mem";
	controller->window[1].resource.flags = IORESOURCE_MEM;
	controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem;
	controller->window[1].resource.end =
	    controller->window[1].resource.start + (1024 * 1024) - 1;
	controller->window[1].resource.parent = &iomem_resource;
	controller->windows = 2;

	/*
	 * Generic bus fixup goes here.  Don't reference prom_bussoft_ptr
	 * after this point.
@@ -421,7 +530,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)

error_return:

	kfree(controller);
	kfree(sn_controller);
	return;
}

@@ -434,7 +543,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev)
		dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
		return;
	}
	element->sysdata = dev->sysdata;
	element->sysdata = SN_PCIDEV_INFO(dev);
	list_add(&element->entry, &sn_sysdata_list);
}

+17 −3
Original line number Diff line number Diff line
@@ -3,15 +3,27 @@
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
 */
#ifndef _ASM_IA64_SN_PCI_PCIDEV_H
#define _ASM_IA64_SN_PCI_PCIDEV_H

#include <linux/pci.h>

#define SN_PCIDEV_INFO(pci_dev) \
        ((struct pcidev_info *)(pci_dev)->sysdata)
/*
 * In ia64, pci_dev->sysdata must be a *pci_controller. To provide access to
 * the pcidev_info structs for all devices under a controller, we extend the
 * definition of pci_controller, via sn_pci_controller, to include a list
 * of pcidev_info.
 */
struct sn_pci_controller {
	struct pci_controller pci_controller;
	struct list_head pcidev_info;
};

#define SN_PCI_CONTROLLER(dev) ((struct sn_pci_controller *) dev->sysdata)

#define SN_PCIDEV_INFO(dev)	sn_pcidev_info_get(dev)

#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
	(struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
@@ -53,11 +65,13 @@ struct pcidev_info {
	struct sn_irq_info	*pdi_sn_irq_info;
	struct sn_pcibus_provider *pdi_provider;	/* sn pci ops */
	struct pci_dev 		*host_pci_dev;		/* host bus link */
	struct list_head	pdi_list;		/* List of pcidev_info */
};

extern void sn_irq_fixup(struct pci_dev *pci_dev,
			 struct sn_irq_info *sn_irq_info);
extern void sn_irq_unfixup(struct pci_dev *pci_dev);
extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
extern void sn_pci_controller_fixup(int segment, int busnum,
 				    struct pci_bus *bus);
extern void sn_bus_store_sysdata(struct pci_dev *dev);