Skip to content

Commit

Permalink
[SPARC64] PCI: Use root list of pbm's instead of pci_controller_info's
Browse files Browse the repository at this point in the history
The idea is to move more and more things into the pbm,
with the eventual goal of eliminating the pci_controller_info
entirely as there really isn't any need for it.

This stage of the transformations requires some reworking of
the PCI error interrupt handling.

It might be tricky to get rid of the pci_controller_info parenting for
a few reasons:

1) When we get an uncorrectable or correctable error we want
   to interrogate the IOMMU and streaming cache of both
   PBMs for error status.  These errors come from the UPA
   front-end which is shared between the two PBM PCI bus
   segments.

   Historically speaking this is why I choose the datastructure
   hierarchy of pci_controller_info-->pci_pbm_info

2) The probing does a portid/devhandle match to look for the
   'other' pbm, but this is entirely an artifact and can be
   eliminated trivially.

What we could do to solve #1 is to have a "buddy" pointer from one pbm
to another.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 8, 2007
1 parent 5a4a3e5 commit 34768bc
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 315 deletions.
12 changes: 6 additions & 6 deletions arch/sparc64/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
#else

/* List of all PCI controllers found in the system. */
struct pci_controller_info *pci_controller_root = NULL;
struct pci_pbm_info *pci_pbm_root = NULL;

/* Each PCI controller found gets a unique index. */
int pci_num_controllers = 0;
Expand Down Expand Up @@ -291,7 +291,7 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,

/* Find each controller in the system, attach and initialize
* software state structure for each and link into the
* pci_controller_root. Setup the controller enough such
* pci_pbm_root. Setup the controller enough such
* that bus scanning can be done.
*/
static void __init pci_controller_probe(void)
Expand Down Expand Up @@ -776,18 +776,18 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)

static void __init pci_scan_each_controller_bus(void)
{
struct pci_controller_info *p;
struct pci_pbm_info *pbm;

for (p = pci_controller_root; p; p = p->next)
p->scan_bus(p);
for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
pbm->scan_bus(pbm);
}

extern void power_init(void);

static int __init pcibios_init(void)
{
pci_controller_probe();
if (pci_controller_root == NULL)
if (pci_pbm_root == NULL)
return 0;

pci_scan_each_controller_bus();
Expand Down
39 changes: 10 additions & 29 deletions arch/sparc64/kernel/pci_fire.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,21 +160,9 @@ static struct pci_ops pci_fire_ops = {
.write = fire_write_pci_cfg,
};

static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
{
pbm->pci_bus = pci_scan_one_pbm(pbm);
}

static void pci_fire_scan_bus(struct pci_controller_info *p)
{
struct device_node *dp;

if ((dp = p->pbm_A.prom_node) != NULL)
pbm_scan_bus(p, &p->pbm_A);

if ((dp = p->pbm_B.prom_node) != NULL)
pbm_scan_bus(p, &p->pbm_B);

/* XXX register error interrupt handlers XXX */
}
Expand Down Expand Up @@ -313,7 +301,7 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
}

static void pci_fire_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid)
struct device_node *dp, u32 portid)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
Expand All @@ -323,6 +311,11 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
else
pbm = &p->pbm_B;

pbm->next = pci_pbm_root;
pci_pbm_root = pbm;

pbm->scan_bus = pci_fire_scan_bus;

pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = dp;
Expand Down Expand Up @@ -354,19 +347,11 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
struct pci_controller_info *p;
u32 portid = of_getintprop_default(dp, "portid", 0xff);
struct iommu *iommu;
struct pci_pbm_info *pbm;

for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;

if (p->pbm_A.prom_node && p->pbm_B.prom_node)
continue;

pbm = (p->pbm_A.prom_node ?
&p->pbm_A :
&p->pbm_B);

for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid)) {
pci_fire_pbm_init(p, dp, portid);
pci_fire_pbm_init(pbm->parent, dp, portid);
return;
}
}
Expand All @@ -387,12 +372,8 @@ void fire_pci_init(struct device_node *dp, const char *model_name)

p->pbm_B.iommu = iommu;

p->next = pci_controller_root;
pci_controller_root = p;

p->index = pci_num_controllers++;

p->scan_bus = pci_fire_scan_bus;
/* XXX MSI support XXX */
p->pci_ops = &pci_fire_ops;

Expand Down
2 changes: 1 addition & 1 deletion arch/sparc64/kernel/pci_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <asm/io.h>
#include <asm/prom.h>

extern struct pci_controller_info *pci_controller_root;
extern struct pci_pbm_info *pci_pbm_root;
extern unsigned long pci_memspace_mask;

extern int pci_num_controllers;
Expand Down
107 changes: 49 additions & 58 deletions arch/sparc64/kernel/pci_psycho.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ static unsigned long stc_error_buf[128];
static unsigned long stc_tag_buf[16];
static unsigned long stc_line_buf[16];

static void __psycho_check_one_stc(struct pci_controller_info *p,
struct pci_pbm_info *pbm,
static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
int is_pbm_a)
{
struct pci_controller_info *p = pbm->parent;
struct strbuf *strbuf = &pbm->stc;
unsigned long regbase = p->pbm_A.controller_regs;
unsigned long regbase = pbm->controller_regs;
unsigned long err_base, tag_base, line_base;
u64 control;
int i;
Expand Down Expand Up @@ -362,20 +362,13 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
spin_unlock(&stc_buf_lock);
}

static void __psycho_check_stc_error(struct pci_controller_info *p,
static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
unsigned long afsr,
unsigned long afar,
enum psycho_error_type type)
{
struct pci_pbm_info *pbm;

pbm = &p->pbm_A;
if (pbm->stc.strbuf_enabled)
__psycho_check_one_stc(p, pbm, 1);

pbm = &p->pbm_B;
if (pbm->stc.strbuf_enabled)
__psycho_check_one_stc(p, pbm, 0);
__psycho_check_one_stc(pbm,
(pbm == &pbm->parent->pbm_A));
}

/* When an Uncorrectable Error or a PCI Error happens, we
Expand Down Expand Up @@ -413,12 +406,13 @@ static void __psycho_check_stc_error(struct pci_controller_info *p,
#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
static void psycho_check_iommu_error(struct pci_controller_info *p,
static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
unsigned long afsr,
unsigned long afar,
enum psycho_error_type type)
{
struct iommu *iommu = p->pbm_A.iommu;
struct pci_controller_info *p = pbm->parent;
struct iommu *iommu = pbm->iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
Expand Down Expand Up @@ -465,7 +459,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
psycho_write(iommu->iommu_control,
control | PSYCHO_IOMMU_CTRL_DENAB);
for (i = 0; i < 16; i++) {
unsigned long base = p->pbm_A.controller_regs;
unsigned long base = pbm->controller_regs;

iommu_tag[i] =
psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
Expand Down Expand Up @@ -516,7 +510,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
(data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
}
}
__psycho_check_stc_error(p, afsr, afar, type);
__psycho_check_stc_error(pbm, afsr, afar, type);
spin_unlock_irqrestore(&iommu->lock, flags);
}

Expand All @@ -541,9 +535,10 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,

static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
{
struct pci_controller_info *p = dev_id;
unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
struct pci_pbm_info *pbm = dev_id;
struct pci_controller_info *p = pbm->parent;
unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;

Expand Down Expand Up @@ -593,8 +588,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
printk("(none)");
printk("]\n");

/* Interrogate IOMMU for error status. */
psycho_check_iommu_error(p, afsr, afar, UE_ERR);
/* Interrogate both IOMMUs for error status. */
psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);

return IRQ_HANDLED;
}
Expand All @@ -618,9 +614,10 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)

static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
{
struct pci_controller_info *p = dev_id;
unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
struct pci_pbm_info *pbm = dev_id;
struct pci_controller_info *p = pbm->parent;
unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR;
unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;

Expand Down Expand Up @@ -823,11 +820,11 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
* a bug in the IOMMU support code or a PCI device driver.
*/
if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
psycho_check_iommu_error(p, afsr, afar, PCI_ERR);
pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
pci_scan_for_target_abort(pbm->parent, pbm, pbm->pci_bus);
}
if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
pci_scan_for_master_abort(pbm->parent, pbm, pbm->pci_bus);

/* For excessive retries, PSYCHO/PBM will abort the device
* and there is no way to specifically check for excessive
Expand All @@ -837,7 +834,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
*/

if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
pci_scan_for_parity_error(pbm->parent, pbm, pbm->pci_bus);

return IRQ_HANDLED;
}
Expand All @@ -847,34 +844,33 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */
#define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
static void psycho_register_error_handlers(struct pci_controller_info *p)
static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
{
struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
struct of_device *op = of_find_device_by_node(pbm->prom_node);
unsigned long base = p->pbm_A.controller_regs;
unsigned long base = pbm->controller_regs;
u64 tmp;

if (!op)
return;

/* Psycho interrupt property order is:
* 0: PCIERR PBM B INO
* 0: PCIERR INO for this PBM
* 1: UE ERR
* 2: CE ERR
* 3: POWER FAIL
* 4: SPARE HARDWARE
* 5: PCIERR PBM A INO
* 5: POWER MANAGEMENT
*/

if (op->num_irqs < 6)
return;

request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
"PSYCHO PCIERR-A", &p->pbm_A);
request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
"PSYCHO PCIERR-B", &p->pbm_B);
request_irq(op->irqs[1], psycho_ue_intr, 0,
"PSYCHO_UE", pbm);
request_irq(op->irqs[2], psycho_ce_intr, 0,
"PSYCHO_CE", pbm);
request_irq(op->irqs[0], psycho_pcierr_intr, 0,
"PSYCHO_PCIERR", pbm);

/* Enable UE and CE interrupts for controller. */
psycho_write(base + PSYCHO_ECC_CTRL,
Expand Down Expand Up @@ -918,25 +914,16 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}

static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
static void psycho_scan_bus(struct pci_pbm_info *pbm)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable = 0;
pbm->pci_bus = pci_scan_one_pbm(pbm);
}

static void psycho_scan_bus(struct pci_controller_info *p)
{
pbm_config_busmastering(&p->pbm_B);
p->pbm_B.is_66mhz_capable = 0;
pbm_config_busmastering(&p->pbm_A);
p->pbm_A.is_66mhz_capable = 1;
pbm_scan_bus(p, &p->pbm_B);
pbm_scan_bus(p, &p->pbm_A);

/* After the PCI bus scan is complete, we can register
* the error interrupt handlers.
*/
psycho_register_error_handlers(p);
psycho_register_error_handlers(pbm);
}

static void psycho_iommu_init(struct pci_controller_info *p)
Expand Down Expand Up @@ -1096,6 +1083,11 @@ static void psycho_pbm_init(struct pci_controller_info *p,
else
pbm = &p->pbm_B;

pbm->next = pci_pbm_root;
pci_pbm_root = pbm;

pbm->scan_bus = psycho_scan_bus;

pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
Expand Down Expand Up @@ -1127,6 +1119,7 @@ void psycho_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_pbm_info *pbm;
struct iommu *iommu;
struct property *prop;
u32 upa_portid;
Expand All @@ -1137,7 +1130,9 @@ void psycho_init(struct device_node *dp, char *model_name)
if (prop)
upa_portid = *(u32 *) prop->value;

for(p = pci_controller_root; p; p = p->next) {
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
struct pci_controller_info *p = pbm->parent;

if (p->pbm_A.portid == upa_portid) {
is_pbm_a = (p->pbm_A.prom_node == NULL);
psycho_pbm_init(p, dp, is_pbm_a);
Expand All @@ -1157,13 +1152,9 @@ void psycho_init(struct device_node *dp, char *model_name)
}
p->pbm_A.iommu = p->pbm_B.iommu = iommu;

p->next = pci_controller_root;
pci_controller_root = p;

p->pbm_A.portid = upa_portid;
p->pbm_B.portid = upa_portid;
p->index = pci_num_controllers++;
p->scan_bus = psycho_scan_bus;
p->pci_ops = &psycho_ops;

prop = of_find_property(dp, "reg", NULL);
Expand Down
Loading

0 comments on commit 34768bc

Please sign in to comment.