Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 81092
b: refs/heads/master
c: 38958dd
h: refs/heads/master
v: v3
  • Loading branch information
Olof Johansson authored and Paul Mackerras committed Dec 20, 2007
1 parent 1a78c3b commit c23427e
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 731e74c43d4e47daf327748128f1a3648e5d39a5
refs/heads/master: 38958dd9113c19cd7a927009ae585bd5aba3295e
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/platforms/pasemi/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static __init void pas_init_IRQ(void)

mpic = mpic_alloc(mpic_node, openpic_addr,
MPIC_PRIMARY|MPIC_LARGE_VECTORS,
0, 0, " PAS-OPIC ");
0, 0, "PASEMI-OPIC");
BUG_ON(!mpic);

mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/powerpc/sysdev/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc
endif

mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)

obj-$(CONFIG_PPC_MPC106) += grackle.o
Expand Down
20 changes: 20 additions & 0 deletions trunk/arch/powerpc/sysdev/mpic.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,24 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
return 0;
}

void mpic_set_vector(unsigned int virq, unsigned int vector)
{
struct mpic *mpic = mpic_from_irq(virq);
unsigned int src = mpic_irq_to_hw(virq);
unsigned int vecpri;

DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
mpic, virq, src, vector);

if (src >= mpic->irq_count)
return;

vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK);
vecpri |= vector;
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
}

static struct irq_chip mpic_irq_chip = {
.mask = mpic_mask_irq,
.unmask = mpic_unmask_irq,
Expand Down Expand Up @@ -1229,6 +1247,8 @@ void __init mpic_init(struct mpic *mpic)
mpic_u3msi_init(mpic);
}

mpic_pasemi_msi_init(mpic);

for (i = 0; i < mpic->num_sources; i++) {
/* start with vector = source number, and masked */
u32 vecpri = MPIC_VECPRI_MASK | i |
Expand Down
7 changes: 7 additions & 0 deletions trunk/arch/powerpc/sysdev/mpic.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extern int mpic_msi_init_allocator(struct mpic *mpic);
extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
extern int mpic_u3msi_init(struct mpic *mpic);
extern int mpic_pasemi_msi_init(struct mpic *mpic);
#else
static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
irq_hw_number_t hwirq)
Expand All @@ -28,9 +29,15 @@ static inline int mpic_u3msi_init(struct mpic *mpic)
{
return -1;
}

static inline int mpic_pasemi_msi_init(struct mpic *mpic)
{
return -1;
}
#endif

extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
extern void mpic_set_vector(unsigned int virq, unsigned int vector);
extern void mpic_end_irq(unsigned int irq);
extern void mpic_mask_irq(unsigned int irq);
extern void mpic_unmask_irq(unsigned int irq);
Expand Down
172 changes: 172 additions & 0 deletions trunk/arch/powerpc/sysdev/mpic_pasemi_msi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Copyright 2007, Olof Johansson, PA Semi
*
* Based on arch/powerpc/sysdev/mpic_u3msi.c:
*
* Copyright 2006, Segher Boessenkool, IBM Corporation.
* Copyright 2006-2007, Michael Ellerman, IBM Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2 of the
* License.
*
*/

#undef DEBUG

#include <linux/irq.h>
#include <linux/bootmem.h>
#include <linux/msi.h>
#include <asm/mpic.h>
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>

#include "mpic.h"

/* Allocate 16 interrupts per device, to give an alignment of 16,
* since that's the size of the grouping w.r.t. affinity. If someone
* needs more than 32 MSI's down the road we'll have to rethink this,
* but it should be OK for now.
*/
#define ALLOC_CHUNK 16

#define PASEMI_MSI_ADDR 0xfc080000

/* A bit ugly, can we get this from the pci_dev somehow? */
static struct mpic *msi_mpic;


static void mpic_pasemi_msi_mask_irq(unsigned int irq)
{
pr_debug("mpic_pasemi_msi_mask_irq %d\n", irq);
mask_msi_irq(irq);
mpic_mask_irq(irq);
}

static void mpic_pasemi_msi_unmask_irq(unsigned int irq)
{
pr_debug("mpic_pasemi_msi_unmask_irq %d\n", irq);
mpic_unmask_irq(irq);
unmask_msi_irq(irq);
}

static struct irq_chip mpic_pasemi_msi_chip = {
.shutdown = mpic_pasemi_msi_mask_irq,
.mask = mpic_pasemi_msi_mask_irq,
.unmask = mpic_pasemi_msi_unmask_irq,
.eoi = mpic_end_irq,
.set_type = mpic_set_irq_type,
.set_affinity = mpic_set_affinity,
.typename = "PASEMI-MSI ",
};

static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("pasemi_msi: MSI-X untested, trying anyway\n");

return 0;
}

static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;

pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev);

list_for_each_entry(entry, &pdev->msi_list, list) {
if (entry->irq == NO_IRQ)
continue;

set_irq_msi(entry->irq, NULL);
mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq),
ALLOC_CHUNK);
irq_dispose_mapping(entry->irq);
}

return;
}

static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
irq_hw_number_t hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
u64 addr;

pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
pdev, nvec, type);

msg.address_hi = 0;
msg.address_lo = PASEMI_MSI_ADDR;

list_for_each_entry(entry, &pdev->msi_list, list) {
/* Allocate 16 interrupts for now, since that's the grouping for
* affinity. This can be changed later if it turns out 32 is too
* few MSIs for someone, but restrictions will apply to how the
* sources can be changed independently.
*/
hwirq = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK);
if (hwirq < 0) {
pr_debug("pasemi_msi: failed allocating hwirq\n");
return hwirq;
}

virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) {
pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq);
mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK);
return -ENOSPC;
}

/* Vector on MSI is really an offset, the hardware adds
* it to the value written at the magic address. So set
* it to 0 to remain sane.
*/
mpic_set_vector(virq, 0);

set_irq_msi(virq, entry);
set_irq_chip(virq, &mpic_pasemi_msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING);

pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n",
virq, hwirq, addr);

/* Likewise, the device writes [0...511] into the target
* register to generate MSI [512...1023]
*/
msg.data = hwirq-0x200;
write_msi_msg(virq, &msg);
}

return 0;
}

int mpic_pasemi_msi_init(struct mpic *mpic)
{
int rc;

if (!mpic->irqhost->of_node ||
!of_device_is_compatible(mpic->irqhost->of_node,
"pasemi,pwrficient-openpic"))
return -ENODEV;

rc = mpic_msi_init_allocator(mpic);
if (rc) {
pr_debug("pasemi_msi: Error allocating bitmap!\n");
return rc;
}

pr_debug("pasemi_msi: Registering PA Semi MPIC MSI callbacks\n");

msi_mpic = mpic;
WARN_ON(ppc_md.setup_msi_irqs);
ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs;
ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs;
ppc_md.msi_check_device = pasemi_msi_check_device;

return 0;
}

0 comments on commit c23427e

Please sign in to comment.