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

Commit 83821d3f authored by Mark Maule's avatar Mark Maule Committed by Greg Kroah-Hartman
Browse files

[PATCH] PCI: altix: msi support



MSI callouts for altix.  Involves a fair amount of code reorg in sn irq.c
code as well as adding some extensions to the altix PCI provider abstaction.

Signed-off-by: default avatarMark Maule <maule@sgi.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 10083072
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ static int max_pcibus_number = 255; /* Default highest pci bus number */
 */

static dma_addr_t
sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
{
	return 0;
}
@@ -457,13 +457,6 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
		pcidev_info->pdi_sn_irq_info = NULL;
		kfree(sn_irq_info);
	}

	/*
	 * MSI currently not supported on altix.  Remove this when
	 * the MSI abstraction patches are integrated into the kernel
	 * (sometime after 2.6.16 releases)
	 */
	dev->no_msi = 1;
}

/*
+77 −58
Original line number Diff line number Diff line
@@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);

int sn_force_interrupt_flag = 1;
extern int sn_ioif_inited;
static struct list_head **sn_irq_lh;
struct list_head **sn_irq_lh;
static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */

static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
				     u64 sn_irq_info,
u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
				     struct sn_irq_info *sn_irq_info,
				     int req_irq, nasid_t req_nasid,
				     int req_slice)
{
@@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,

	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
			(u64) SAL_INTR_ALLOC, (u64) local_nasid,
			(u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
			(u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
			(u64) req_nasid, (u64) req_slice);

	return ret_stuff.status;
}

static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
void sn_intr_free(nasid_t local_nasid, int local_widget,
				struct sn_irq_info *sn_irq_info)
{
	struct ia64_sal_retval ret_stuff;
@@ -112,17 +113,12 @@ static void sn_end_irq(unsigned int irq)

static void sn_irq_info_free(struct rcu_head *head);

static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
				       nasid_t nasid, int slice)
{
	struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
	int cpuid, cpuphys;

	cpuid = first_cpu(mask);
	cpuphys = cpu_physical_id(cpuid);

	list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
				 sn_irq_lh[irq], list) {
		u64 bridge;
	int vector;
	int cpuphys;
	int64_t bridge;
	int local_widget, status;
	nasid_t local_nasid;
	struct sn_irq_info *new_irq_info;
@@ -130,13 +126,14 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)

	new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
	if (new_irq_info == NULL)
			break;
		return NULL;

	memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));

	bridge = (u64) new_irq_info->irq_bridge;
	if (!bridge) {
		kfree(new_irq_info);
			break; /* irq is not a device interrupt */
		return NULL; /* irq is not a device interrupt */
	}

	local_nasid = NASID_GET(bridge);
@@ -146,6 +143,7 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
	else
		local_widget = SWIN_WIDGETNUM(bridge);

	vector = sn_irq_info->irq_irq;
	/* Free the old PROM new_irq_info structure */
	sn_intr_free(local_nasid, local_widget, new_irq_info);
	/* Update kernels new_irq_info with new target info */
@@ -153,21 +151,27 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)

	/* allocate a new PROM new_irq_info struct */
	status = sn_intr_alloc(local_nasid, local_widget,
				       __pa(new_irq_info), irq,
				       cpuid_to_nasid(cpuid),
				       cpuid_to_slice(cpuid));
			       new_irq_info, vector,
			       nasid, slice);

	/* SAL call failed */
	if (status) {
		kfree(new_irq_info);
			break;
		return NULL;
	}

		new_irq_info->irq_cpuid = cpuid;
	cpuphys = nasid_slice_to_cpuid(nasid, slice);
	new_irq_info->irq_cpuid = cpuphys;
	register_intr_pda(new_irq_info);

	pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
		if (pci_provider && pci_provider->target_interrupt)

	/*
	 * If this represents a line interrupt, target it.  If it's
	 * an msi (irq_int_bit < 0), it's already targeted.
	 */
	if (new_irq_info->irq_int_bit >= 0 &&
	    pci_provider && pci_provider->target_interrupt)
		(pci_provider->target_interrupt)(new_irq_info);

	spin_lock(&sn_irq_info_lock);
@@ -176,9 +180,24 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);

#ifdef CONFIG_SMP
		set_irq_affinity_info((irq & 0xff), cpuphys, 0);
	set_irq_affinity_info((vector & 0xff), cpuphys, 0);
#endif

	return new_irq_info;
}

static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
{
	struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
	nasid_t nasid;
	int slice;

	nasid = cpuid_to_nasid(first_cpu(mask));
	slice = cpuid_to_slice(first_cpu(mask));

	list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
				 sn_irq_lh[irq], list)
		(void)sn_retarget_vector(sn_irq_info, nasid, slice);
}

struct hw_interrupt_type irq_type_sn = {
+6 −4
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@

#include <linux/module.h>
#include <asm/dma.h>
#include <asm/sn/pcibr_provider.h>
#include <asm/sn/intr.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
#include <asm/sn/sn_sal.h>
@@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
	 * resources.
	 */

	*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
	*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
						   SN_DMA_ADDR_PHYS);
	if (!*dma_handle) {
		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
		free_pages((unsigned long)cpuaddr, get_order(size));
@@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size,
	BUG_ON(dev->bus != &pci_bus_type);

	phys_addr = __pa(cpu_addr);
	dma_addr = provider->dma_map(pdev, phys_addr, size);
	dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
	if (!dma_addr) {
		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
		return 0;
@@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
	for (i = 0; i < nhwentries; i++, sg++) {
		phys_addr = SG_ENT_PHYS_ADDRESS(sg);
		sg->dma_address = provider->dma_map(pdev,
						    phys_addr, sg->length);
						    phys_addr, sg->length,
						    SN_DMA_ADDR_PHYS);

		if (!sg->dma_address) {
			printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
+44 −18
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ extern int sn_ioif_inited;

static dma_addr_t
pcibr_dmamap_ate32(struct pcidev_info *info,
		   u64 paddr, size_t req_size, u64 flags)
		   u64 paddr, size_t req_size, u64 flags, int dma_flags)
{

	struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
@@ -81,9 +81,12 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
	if (IS_PCIX(pcibus_info))
		ate_flags &= ~(PCI32_ATE_PREF);

	xio_addr =
	    IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
	if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS))
		xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
	    					      PHYS_TO_TIODMA(paddr);
	else
		xio_addr = paddr;

	offset = IOPGOFF(xio_addr);
	ate = ate_flags | (xio_addr - offset);

@@ -91,6 +94,13 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
	if (IS_PIC_SOFT(pcibus_info)) {
		ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
	}

	/*
	 * If we're mapping for MSI, set the MSI bit in the ATE
	 */
	if (dma_flags & SN_DMA_MSI)
		ate |= PCI32_ATE_MSI;

	ate_write(pcibus_info, ate_index, ate_count, ate);

	/*
@@ -105,20 +115,27 @@ pcibr_dmamap_ate32(struct pcidev_info *info,
	if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
		ATE_SWAP_ON(pci_addr);


	return pci_addr;
}

static dma_addr_t
pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
			u64 dma_attributes)
			u64 dma_attributes, int dma_flags)
{
	struct pcibus_info *pcibus_info = (struct pcibus_info *)
	    ((info->pdi_host_pcidev_info)->pdi_pcibus_info);
	u64 pci_addr;

	/* Translate to Crosstalk View of Physical Address */
	pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
		    PHYS_TO_TIODMA(paddr)) | dma_attributes;
	if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
		pci_addr = IS_PIC_SOFT(pcibus_info) ?
				PHYS_TO_DMA(paddr) :
		    		PHYS_TO_TIODMA(paddr) | dma_attributes;
	else
		pci_addr = IS_PIC_SOFT(pcibus_info) ?
				paddr :
				paddr | dma_attributes;

	/* Handle Bus mode */
	if (IS_PCIX(pcibus_info))
@@ -130,7 +147,9 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
		    ((u64) pcibus_info->
		     pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
	} else
		pci_addr |= TIOCP_PCI64_CMDTYPE_MEM;
		pci_addr |= (dma_flags & SN_DMA_MSI) ?
				TIOCP_PCI64_CMDTYPE_MSI :
				TIOCP_PCI64_CMDTYPE_MEM;

	/* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
	if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
@@ -141,7 +160,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,

static dma_addr_t
pcibr_dmatrans_direct32(struct pcidev_info * info,
			u64 paddr, size_t req_size, u64 flags)
			u64 paddr, size_t req_size, u64 flags, int dma_flags)
{
	struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
	struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info->
@@ -156,8 +175,14 @@ pcibr_dmatrans_direct32(struct pcidev_info * info,
		return 0;
	}

	if (dma_flags & SN_DMA_MSI)
		return 0;

	if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
		xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
	    					      PHYS_TO_TIODMA(paddr);
	else
		xio_addr = paddr;

	xio_base = pcibus_info->pbi_dir_xbase;
	offset = xio_addr - xio_base;
@@ -327,7 +352,7 @@ void sn_dma_flush(u64 addr)
 */

dma_addr_t
pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags)
{
	dma_addr_t dma_handle;
	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
@@ -344,11 +369,11 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
		 */

		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
						     PCI64_ATTR_PREF);
						     PCI64_ATTR_PREF, dma_flags);
	} else {
		/* Handle 32-63 bit cards via direct mapping */
		dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
						     size, 0);
						     size, 0, dma_flags);
		if (!dma_handle) {
			/*
			 * It is a 32 bit card and we cannot do direct mapping,
@@ -356,7 +381,8 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
			 */

			dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
							size, PCI32_ATE_PREF);
							size, PCI32_ATE_PREF,
							dma_flags);
		}
	}

@@ -365,18 +391,18 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)

dma_addr_t
pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
			 size_t size)
			 size_t size, int dma_flags)
{
	dma_addr_t dma_handle;
	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);

	if (hwdev->dev.coherent_dma_mask == ~0UL) {
		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
					    PCI64_ATTR_BAR);
					    PCI64_ATTR_BAR, dma_flags);
	} else {
		dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
						    phys_addr, size,
						    PCI32_ATE_BAR);
						    PCI32_ATE_BAR, dma_flags);
	}

	return dma_handle;
+7 −1
Original line number Diff line number Diff line
@@ -515,10 +515,16 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
 * use the GART mapped mode.
 */
static u64
tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count)
tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
{
	u64 mapaddr;

	/*
	 * Not supported for now ...
	 */
	if (dma_flags & SN_DMA_MSI)
		return 0;

	/*
	 * If card is 64 or 48 bit addresable, use a direct mapping.  32
	 * bit direct is so restrictive w.r.t. where the memory resides that
Loading