summaryrefslogtreecommitdiff
path: root/arch/sparc64/kernel/pci_schizo.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-05-07 23:06:27 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-05-08 16:41:24 -0700
commit34768bc8329194b14e42ee408a84edfa40059046 (patch)
tree3fff53138966f3a58e796a71c19a3b75de86fbf7 /arch/sparc64/kernel/pci_schizo.c
parent5a4a3e592d0d66653297049373caa7ac5b4febe0 (diff)
downloadlinux-34768bc8329194b14e42ee408a84edfa40059046.tar.gz
[SPARC64] PCI: Use root list of pbm's instead of pci_controller_info's
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>
Diffstat (limited to 'arch/sparc64/kernel/pci_schizo.c')
-rw-r--r--arch/sparc64/kernel/pci_schizo.c256
1 files changed, 89 insertions, 167 deletions
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index c0a6a3866e2f..4ebdcbd5262a 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -238,25 +238,6 @@ static unsigned long stc_line_buf[16];
#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */
#define SCHIZO_SERR_INO 0x34 /* Safari interface error */
-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
-{
- ino &= IMAP_INO;
- if (p->pbm_A.ino_bitmap & (1UL << ino))
- return &p->pbm_A;
- if (p->pbm_B.ino_bitmap & (1UL << ino))
- return &p->pbm_B;
-
- printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
- "PBM_A[%016lx] PBM_B[%016lx]",
- p->index, ino,
- p->pbm_A.ino_bitmap,
- p->pbm_B.ino_bitmap);
- printk("PCI%d: Using PBM_A, report this problem immediately.\n",
- p->index);
-
- return &p->pbm_A;
-}
-
#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */
@@ -522,9 +503,10 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
- unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
+ unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
unsigned long afsr, afar, error_bits;
int reported, limit;
@@ -610,9 +592,10 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
- unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
+ unsigned long afsr_reg = pbm->controller_regs + SCHIZO_CE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + SCHIZO_CE_AFAR;
unsigned long afsr, afar, error_bits;
int reported, limit;
@@ -940,11 +923,12 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
*/
static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
u64 errlog;
- errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
+ errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
errlog & ~(SAFARI_ERRLOG_ERROUT));
if (!(errlog & BUS_ERROR_UNMAP)) {
@@ -972,6 +956,16 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
#define SCHIZO_SAFARI_IRQCTRL 0x10010UL
#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL
+static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
+{
+ ino &= IMAP_INO;
+
+ if (pbm->ino_bitmap & (1UL << ino))
+ return 1;
+
+ return 0;
+}
+
/* How the Tomatillo IRQs are routed around is pure guesswork here.
*
* All the Tomatillo devices I see in prtconf dumps seem to have only
@@ -986,10 +980,9 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
* PCI bus units of the same Tomatillo. I still have not really
* figured this out...
*/
-static void tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm;
- struct of_device *op;
+ struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
/* Tomatillo IRQ property layout is:
@@ -1000,44 +993,27 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
* 4: POWER FAIL?
*/
- pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
- "TOMATILLO_UE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
- "TOMATILLO CE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "TOMATILLO PCIERR-A", pbm);
-
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "TOMATILLO PCIERR-B", pbm);
-
- pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
- "TOMATILLO SERR", p);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO))
+ request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "TOMATILLO_UE", pbm);
- /* Enable UE and CE interrupts for controller. */
- schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO))
+ request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "TOMATILLO_CE", pbm);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO))
+ request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
+ else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO))
+ request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
- schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO))
+ request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "TOMATILLO_SERR", pbm);
+
+ /* Enable UE and CE interrupts for controller. */
+ schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
(SCHIZO_ECCCTRL_EE |
SCHIZO_ECCCTRL_UE |
SCHIZO_ECCCTRL_CE));
@@ -1053,15 +1029,10 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
- tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
- tmp |= err_mask;
- tmp &= ~err_no_mask;
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
- tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -1070,8 +1041,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
SCHIZO_PCIAFSR_STTO);
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -1083,21 +1053,16 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
BUS_ERROR_APERR | BUS_ERROR_UNMAP |
BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
(SCHIZO_SAFERRCTRL_EN | err_mask));
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
-static void schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm;
- struct of_device *op;
+ struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
/* Schizo IRQ property layout is:
@@ -1108,39 +1073,27 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
* 4: POWER FAIL?
*/
- pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
- "SCHIZO_UE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
- "SCHIZO CE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "SCHIZO PCIERR-A", pbm);
-
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "SCHIZO PCIERR-B", pbm);
-
- pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
- "SCHIZO SERR", p);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO))
+ request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "SCHIZO_UE", pbm);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO))
+ request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "SCHIZO_CE", pbm);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO))
+ request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+ else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO))
+ request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO))
+ request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "SCHIZO_SERR", pbm);
/* Enable UE and CE interrupts for controller. */
- schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
(SCHIZO_ECCCTRL_EE |
SCHIZO_ECCCTRL_UE |
SCHIZO_ECCCTRL_CE));
@@ -1159,25 +1112,12 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
- tmp |= err_mask;
- tmp &= ~err_no_mask;
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR,
- (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
- SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
- SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
- SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
- SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
- SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
-
- tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
(SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
@@ -1210,11 +1150,8 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
#endif
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
(SCHIZO_SAFERRCTRL_EN | err_mask));
-
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1234,27 +1171,19 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_pbm_info *pbm)
{
- pbm_config_busmastering(&p->pbm_B);
- p->pbm_B.is_66mhz_capable =
- (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
- != NULL);
- pbm_config_busmastering(&p->pbm_A);
- p->pbm_A.is_66mhz_capable =
- (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
+ pbm_config_busmastering(pbm);
+ pbm->is_66mhz_capable =
+ (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
!= NULL);
- p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
- p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
- /* After the PCI bus scan is complete, we can register
- * the error interrupt handlers.
- */
- if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
- tomatillo_register_error_handlers(p);
+ if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+ tomatillo_register_error_handlers(pbm);
else
- schizo_register_error_handlers(p);
+ schizo_register_error_handlers(pbm);
}
#define SCHIZO_STRBUF_CONTROL (0x02800UL)
@@ -1529,6 +1458,11 @@ static void schizo_pbm_init(struct pci_controller_info *p,
else
pbm = &p->pbm_B;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ pbm->scan_bus = schizo_scan_bus;
+
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = dp;
@@ -1572,23 +1506,15 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
struct iommu *iommu;
u32 portid;
portid = of_getintprop_default(dp, "portid", 0xff);
- 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, chip_type)) {
- schizo_pbm_init(p, dp, portid, chip_type);
+ schizo_pbm_init(pbm->parent, dp, portid, chip_type);
return;
}
}
@@ -1609,11 +1535,7 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
p->pbm_B.iommu = iommu;
- p->next = pci_controller_root;
- pci_controller_root = p;
-
p->index = pci_num_controllers++;
- p->scan_bus = schizo_scan_bus;
p->pci_ops = &schizo_ops;
/* Like PSYCHO we have a 2GB aligned area for memory space. */