|
@@ -146,24 +146,16 @@ static unsigned long stc_error_buf[128];
|
|
static unsigned long stc_tag_buf[16];
|
|
static unsigned long stc_tag_buf[16];
|
|
static unsigned long stc_line_buf[16];
|
|
static unsigned long stc_line_buf[16];
|
|
|
|
|
|
-static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
|
|
|
|
- int is_pbm_a)
|
|
|
|
|
|
+static void psycho_check_stc_error(struct pci_pbm_info *pbm)
|
|
{
|
|
{
|
|
struct strbuf *strbuf = &pbm->stc;
|
|
struct strbuf *strbuf = &pbm->stc;
|
|
- unsigned long regbase = pbm->controller_regs;
|
|
|
|
unsigned long err_base, tag_base, line_base;
|
|
unsigned long err_base, tag_base, line_base;
|
|
u64 control;
|
|
u64 control;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- if (is_pbm_a) {
|
|
|
|
- err_base = regbase + PSYCHO_STC_ERR_A;
|
|
|
|
- tag_base = regbase + PSYCHO_STC_TAG_A;
|
|
|
|
- line_base = regbase + PSYCHO_STC_LINE_A;
|
|
|
|
- } else {
|
|
|
|
- err_base = regbase + PSYCHO_STC_ERR_B;
|
|
|
|
- tag_base = regbase + PSYCHO_STC_TAG_B;
|
|
|
|
- line_base = regbase + PSYCHO_STC_LINE_B;
|
|
|
|
- }
|
|
|
|
|
|
+ err_base = strbuf->strbuf_err_stat;
|
|
|
|
+ tag_base = strbuf->strbuf_tag_diag;
|
|
|
|
+ line_base = strbuf->strbuf_line_diag;
|
|
|
|
|
|
spin_lock(&stc_buf_lock);
|
|
spin_lock(&stc_buf_lock);
|
|
|
|
|
|
@@ -239,15 +231,6 @@ static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
|
|
spin_unlock(&stc_buf_lock);
|
|
spin_unlock(&stc_buf_lock);
|
|
}
|
|
}
|
|
|
|
|
|
-static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
|
|
|
|
- unsigned long afsr,
|
|
|
|
- unsigned long afar,
|
|
|
|
- enum psycho_error_type type)
|
|
|
|
-{
|
|
|
|
- __psycho_check_one_stc(pbm,
|
|
|
|
- (pbm == &pbm->parent->pbm_A));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* When an Uncorrectable Error or a PCI Error happens, we
|
|
/* When an Uncorrectable Error or a PCI Error happens, we
|
|
* interrogate the IOMMU state to see if it is the cause.
|
|
* interrogate the IOMMU state to see if it is the cause.
|
|
*/
|
|
*/
|
|
@@ -386,7 +369,7 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
|
|
(data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
|
|
(data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- __psycho_check_stc_error(pbm, afsr, afar, type);
|
|
|
|
|
|
+ psycho_check_stc_error(pbm);
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -412,7 +395,6 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
|
|
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct pci_pbm_info *pbm = dev_id;
|
|
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 afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
|
|
unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
|
|
unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
|
|
unsigned long afsr, afar, error_bits;
|
|
unsigned long afsr, afar, error_bits;
|
|
@@ -465,8 +447,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
|
|
printk("]\n");
|
|
printk("]\n");
|
|
|
|
|
|
/* Interrogate both IOMMUs for error status. */
|
|
/* 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);
|
|
|
|
|
|
+ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
|
|
|
|
+ if (pbm->sibling)
|
|
|
|
+ psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
@@ -573,23 +556,18 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
|
|
#define PSYCHO_PCI_AFAR_A 0x2018UL
|
|
#define PSYCHO_PCI_AFAR_A 0x2018UL
|
|
#define PSYCHO_PCI_AFAR_B 0x4018UL
|
|
#define PSYCHO_PCI_AFAR_B 0x4018UL
|
|
|
|
|
|
-static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
|
|
|
|
|
|
+static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
|
|
{
|
|
{
|
|
- unsigned long csr_reg, csr, csr_error_bits;
|
|
|
|
|
|
+ unsigned long csr, csr_error_bits;
|
|
irqreturn_t ret = IRQ_NONE;
|
|
irqreturn_t ret = IRQ_NONE;
|
|
u16 stat;
|
|
u16 stat;
|
|
|
|
|
|
- if (is_pbm_a) {
|
|
|
|
- csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
|
|
|
|
- } else {
|
|
|
|
- csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
|
|
|
|
- }
|
|
|
|
- csr = psycho_read(csr_reg);
|
|
|
|
|
|
+ csr = psycho_read(pbm->pci_csr);
|
|
csr_error_bits =
|
|
csr_error_bits =
|
|
csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
|
|
csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
|
|
if (csr_error_bits) {
|
|
if (csr_error_bits) {
|
|
/* Clear the errors. */
|
|
/* Clear the errors. */
|
|
- psycho_write(csr_reg, csr);
|
|
|
|
|
|
+ psycho_write(pbm->pci_csr, csr);
|
|
|
|
|
|
/* Log 'em. */
|
|
/* Log 'em. */
|
|
if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
|
|
if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
|
|
@@ -616,19 +594,12 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
|
|
static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|
static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct pci_pbm_info *pbm = dev_id;
|
|
struct pci_pbm_info *pbm = dev_id;
|
|
- struct pci_controller_info *p = pbm->parent;
|
|
|
|
unsigned long afsr_reg, afar_reg;
|
|
unsigned long afsr_reg, afar_reg;
|
|
unsigned long afsr, afar, error_bits;
|
|
unsigned long afsr, afar, error_bits;
|
|
- int is_pbm_a, reported;
|
|
|
|
|
|
+ int reported;
|
|
|
|
|
|
- is_pbm_a = (pbm == &pbm->parent->pbm_A);
|
|
|
|
- if (is_pbm_a) {
|
|
|
|
- afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
|
|
|
|
- afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
|
|
|
|
- } else {
|
|
|
|
- afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
|
|
|
|
- afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
|
|
|
|
- }
|
|
|
|
|
|
+ afsr_reg = pbm->pci_afsr;
|
|
|
|
+ afar_reg = pbm->pci_afar;
|
|
|
|
|
|
/* Latch error status. */
|
|
/* Latch error status. */
|
|
afar = psycho_read(afar_reg);
|
|
afar = psycho_read(afar_reg);
|
|
@@ -641,7 +612,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
|
|
PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
|
|
PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
|
|
PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
|
|
PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
|
|
if (!error_bits)
|
|
if (!error_bits)
|
|
- return psycho_pcierr_intr_other(pbm, is_pbm_a);
|
|
|
|
|
|
+ return psycho_pcierr_intr_other(pbm);
|
|
psycho_write(afsr_reg, error_bits);
|
|
psycho_write(afsr_reg, error_bits);
|
|
|
|
|
|
/* Log the error. */
|
|
/* Log the error. */
|
|
@@ -923,10 +894,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
|
|
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
|
|
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A;
|
|
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
|
|
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A;
|
|
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A;
|
|
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A;
|
|
|
|
+ pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
|
|
|
|
+ pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
|
|
|
|
+ pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
|
|
} else {
|
|
} else {
|
|
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B;
|
|
pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B;
|
|
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
|
|
pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B;
|
|
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
|
|
pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B;
|
|
|
|
+ pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
|
|
|
|
+ pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
|
|
|
|
+ pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
|
|
}
|
|
}
|
|
/* PSYCHO's streaming buffer lacks ctx flushing. */
|
|
/* PSYCHO's streaming buffer lacks ctx flushing. */
|
|
pbm->stc.strbuf_ctxflush = 0;
|
|
pbm->stc.strbuf_ctxflush = 0;
|
|
@@ -971,16 +948,10 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
|
|
#define PSYCHO_MEMSPACE_B 0x180000000UL
|
|
#define PSYCHO_MEMSPACE_B 0x180000000UL
|
|
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
|
|
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
|
|
|
|
|
|
-static void __init psycho_pbm_init(struct pci_controller_info *p,
|
|
|
|
|
|
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
|
|
struct of_device *op, int is_pbm_a)
|
|
struct of_device *op, int is_pbm_a)
|
|
{
|
|
{
|
|
struct device_node *dp = op->node;
|
|
struct device_node *dp = op->node;
|
|
- struct pci_pbm_info *pbm;
|
|
|
|
-
|
|
|
|
- if (is_pbm_a)
|
|
|
|
- pbm = &p->pbm_A;
|
|
|
|
- else
|
|
|
|
- pbm = &p->pbm_B;
|
|
|
|
|
|
|
|
pbm->next = pci_pbm_root;
|
|
pbm->next = pci_pbm_root;
|
|
pci_pbm_root = pbm;
|
|
pci_pbm_root = pbm;
|
|
@@ -996,7 +967,6 @@ static void __init psycho_pbm_init(struct pci_controller_info *p,
|
|
pbm->chip_version = of_getintprop_default(dp, "version#", 0);
|
|
pbm->chip_version = of_getintprop_default(dp, "version#", 0);
|
|
pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
|
|
pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
|
|
|
|
|
|
- pbm->parent = p;
|
|
|
|
pbm->prom_node = dp;
|
|
pbm->prom_node = dp;
|
|
pbm->name = dp->full_name;
|
|
pbm->name = dp->full_name;
|
|
|
|
|
|
@@ -1013,6 +983,17 @@ static void __init psycho_pbm_init(struct pci_controller_info *p,
|
|
psycho_scan_bus(pbm, &op->dev);
|
|
psycho_scan_bus(pbm, &op->dev);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
|
|
|
|
+{
|
|
|
|
+ struct pci_pbm_info *pbm;
|
|
|
|
+
|
|
|
|
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
|
|
|
|
+ if (pbm->portid == upa_portid)
|
|
|
|
+ return pbm;
|
|
|
|
+ }
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
#define PSYCHO_CONFIGSPACE 0x001000000UL
|
|
#define PSYCHO_CONFIGSPACE 0x001000000UL
|
|
|
|
|
|
static int __devinit psycho_probe(struct of_device *op,
|
|
static int __devinit psycho_probe(struct of_device *op,
|
|
@@ -1020,7 +1001,6 @@ static int __devinit psycho_probe(struct of_device *op,
|
|
{
|
|
{
|
|
const struct linux_prom64_registers *pr_regs;
|
|
const struct linux_prom64_registers *pr_regs;
|
|
struct device_node *dp = op->node;
|
|
struct device_node *dp = op->node;
|
|
- struct pci_controller_info *p;
|
|
|
|
struct pci_pbm_info *pbm;
|
|
struct pci_pbm_info *pbm;
|
|
struct iommu *iommu;
|
|
struct iommu *iommu;
|
|
int is_pbm_a, err;
|
|
int is_pbm_a, err;
|
|
@@ -1028,33 +1008,26 @@ static int __devinit psycho_probe(struct of_device *op,
|
|
|
|
|
|
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
|
|
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
|
|
|
|
|
|
- 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, op, is_pbm_a);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
err = -ENOMEM;
|
|
err = -ENOMEM;
|
|
- p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
|
|
|
|
- if (!p) {
|
|
|
|
- printk(KERN_ERR PFX "Cannot allocate controller info.\n");
|
|
|
|
|
|
+ pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
|
|
|
|
+ if (!pbm) {
|
|
|
|
+ printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
|
|
goto out_err;
|
|
goto out_err;
|
|
}
|
|
}
|
|
|
|
|
|
- iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
|
|
|
|
- if (!iommu) {
|
|
|
|
- printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
|
|
|
- goto out_free_controller;
|
|
|
|
|
|
+ pbm->sibling = psycho_find_sibling(upa_portid);
|
|
|
|
+ if (pbm->sibling) {
|
|
|
|
+ iommu = pbm->sibling->iommu;
|
|
|
|
+ } else {
|
|
|
|
+ iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
|
|
|
|
+ if (!iommu) {
|
|
|
|
+ printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
|
|
|
|
+ goto out_free_controller;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- p->pbm_A.iommu = p->pbm_B.iommu = iommu;
|
|
|
|
-
|
|
|
|
- p->pbm_A.portid = upa_portid;
|
|
|
|
- p->pbm_B.portid = upa_portid;
|
|
|
|
|
|
+ pbm->iommu = iommu;
|
|
|
|
+ pbm->portid = upa_portid;
|
|
|
|
|
|
pr_regs = of_get_property(dp, "reg", NULL);
|
|
pr_regs = of_get_property(dp, "reg", NULL);
|
|
err = -ENODEV;
|
|
err = -ENODEV;
|
|
@@ -1063,29 +1036,43 @@ static int __devinit psycho_probe(struct of_device *op,
|
|
goto out_free_iommu;
|
|
goto out_free_iommu;
|
|
}
|
|
}
|
|
|
|
|
|
- p->pbm_A.controller_regs = pr_regs[2].phys_addr;
|
|
|
|
- p->pbm_B.controller_regs = pr_regs[2].phys_addr;
|
|
|
|
|
|
+ is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
|
|
|
|
+
|
|
|
|
+ pbm->controller_regs = pr_regs[2].phys_addr;
|
|
|
|
+ pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
|
|
|
|
|
|
- p->pbm_A.config_space = p->pbm_B.config_space =
|
|
|
|
- (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
|
|
|
|
|
|
+ if (is_pbm_a) {
|
|
|
|
+ pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
|
|
|
|
+ pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
|
|
|
|
+ pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIA_CTRL;
|
|
|
|
+ } else {
|
|
|
|
+ pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
|
|
|
|
+ pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
|
|
|
|
+ pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIB_CTRL;
|
|
|
|
+ }
|
|
|
|
|
|
- psycho_controller_hwinit(&p->pbm_A);
|
|
|
|
|
|
+ psycho_controller_hwinit(pbm);
|
|
|
|
+ if (!pbm->sibling) {
|
|
|
|
+ err = psycho_iommu_init(pbm);
|
|
|
|
+ if (err)
|
|
|
|
+ goto out_free_iommu;
|
|
|
|
+ }
|
|
|
|
|
|
- err = psycho_iommu_init(&p->pbm_A);
|
|
|
|
- if (err)
|
|
|
|
- goto out_free_iommu;
|
|
|
|
|
|
+ psycho_pbm_init(pbm, op, is_pbm_a);
|
|
|
|
|
|
- is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
|
|
|
|
|
|
+ if (pbm->sibling)
|
|
|
|
+ pbm->sibling->sibling = pbm;
|
|
|
|
|
|
- psycho_pbm_init(p, op, is_pbm_a);
|
|
|
|
|
|
+ dev_set_drvdata(&op->dev, pbm);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out_free_iommu:
|
|
out_free_iommu:
|
|
- kfree(p->pbm_A.iommu);
|
|
|
|
|
|
+ if (!pbm->sibling)
|
|
|
|
+ kfree(pbm->iommu);
|
|
|
|
|
|
out_free_controller:
|
|
out_free_controller:
|
|
- kfree(p);
|
|
|
|
|
|
+ kfree(pbm);
|
|
|
|
|
|
out_err:
|
|
out_err:
|
|
return err;
|
|
return err;
|