summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci_schizo.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/pci_schizo.c')
-rw-r--r--arch/sparc64/kernel/pci_schizo.c155
1 files changed, 98 insertions, 57 deletions
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 9248c67..e1c5657 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,6 +1,6 @@
/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
*
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -13,14 +13,15 @@
#include <asm/iommu.h>
#include <asm/irq.h>
-#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
-#include <asm/oplib.h>
#include "pci_impl.h"
#include "iommu_common.h"
+#define DRIVER_NAME "schizo"
+#define PFX DRIVER_NAME ": "
+
/* All SCHIZO registers are 64-bits. The following accessor
* routines are how they are accessed. The REG parameter
* is a physical address.
@@ -1084,14 +1085,15 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+ struct device *parent)
{
pbm_config_busmastering(pbm);
pbm->is_66mhz_capable =
(of_find_property(pbm->prom_node, "66mhz-capable", NULL)
!= NULL);
- pbm->pci_bus = pci_scan_one_pbm(pbm);
+ pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
tomatillo_register_error_handlers(pbm);
@@ -1150,24 +1152,17 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
- struct iommu *iommu = pbm->iommu;
+ static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
unsigned long i, tagbase, database;
- struct property *prop;
- u32 vdma[2], dma_mask;
+ struct iommu *iommu = pbm->iommu;
int tsbsize, err;
+ const u32 *vdma;
+ u32 dma_mask;
u64 control;
- prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
- if (prop) {
- u32 *val = prop->value;
-
- vdma[0] = val[0];
- vdma[1] = val[1];
- } else {
- /* No property, use default values. */
- vdma[0] = 0xc0000000;
- vdma[1] = 0x40000000;
- }
+ vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+ if (!vdma)
+ vdma = vdma_default;
dma_mask = vdma[0];
switch (vdma[1]) {
@@ -1187,9 +1182,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
break;
default:
- prom_printf("SCHIZO: strange virtual-dma size.\n");
- prom_halt();
- };
+ printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+ return -EINVAL;
+ }
/* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1212,7 +1207,7 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
- for(i = 0; i < 16; i++) {
+ for (i = 0; i < 16; i++) {
schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
}
@@ -1222,8 +1217,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
*/
err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
pbm->numa_node);
- if (err)
+ if (err) {
+ printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
return err;
+ }
schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
@@ -1236,7 +1233,7 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
case 128:
control |= SCHIZO_IOMMU_TSBSZ_128K;
break;
- };
+ }
control |= SCHIZO_IOMMU_CTRL_ENAB;
schizo_write(iommu->iommu_control, control);
@@ -1280,7 +1277,6 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
- struct property *prop;
u64 tmp;
schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
@@ -1294,8 +1290,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
- if (!prop)
+ if (!of_find_property(pbm->prom_node, "no-bus-parking", NULL))
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1334,11 +1329,12 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
}
-static int __init schizo_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid,
- int chip_type)
+static int __devinit schizo_pbm_init(struct pci_controller_info *p,
+ struct of_device *op, u32 portid,
+ int chip_type)
{
const struct linux_prom64_registers *regs;
+ struct device_node *dp = op->node;
struct pci_pbm_info *pbm;
const char *chipset_name;
int is_pbm_a, err;
@@ -1382,7 +1378,6 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
pbm->numa_node = -1;
- pbm->scan_bus = schizo_scan_bus;
pbm->pci_ops = &sun4u_pci_ops;
pbm->config_space_reg_bits = 8;
@@ -1420,6 +1415,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
schizo_pbm_strbuf_init(pbm);
+ schizo_scan_bus(pbm, &op->dev);
+
return 0;
}
@@ -1433,62 +1430,106 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
-static void __init __schizo_init(struct device_node *dp, char *model_name,
- int chip_type)
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
{
+ struct device_node *dp = op->node;
struct pci_controller_info *p;
struct pci_pbm_info *pbm;
struct iommu *iommu;
u32 portid;
+ int err;
portid = of_getintprop_default(dp, "portid", 0xff);
+ err = -ENOMEM;
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid, chip_type)) {
- if (schizo_pbm_init(pbm->parent, dp,
+ if (schizo_pbm_init(pbm->parent, op,
portid, chip_type))
- goto fatal_memory_error;
- return;
+ goto out_err;
+ return 0;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p)
- goto fatal_memory_error;
+ if (!p) {
+ printk(KERN_ERR PFX "Cannot allocate controller info.\n");
+ goto out_err;
+ }
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+ goto out_free_controller;
+ }
p->pbm_A.iommu = iommu;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu)
- goto fatal_memory_error;
+ if (!iommu) {
+ printk(KERN_ERR PFX "Cannot allocate PBM B iommu.\n");
+ goto out_free_iommu_A;
+ }
p->pbm_B.iommu = iommu;
- if (schizo_pbm_init(p, dp, portid, chip_type))
- goto fatal_memory_error;
+ if (schizo_pbm_init(p, op, portid, chip_type))
+ goto out_free_iommu_B;
- return;
+ return 0;
-fatal_memory_error:
- prom_printf("SCHIZO: Fatal memory allocation error.\n");
- prom_halt();
-}
+out_free_iommu_B:
+ kfree(p->pbm_B.iommu);
-void __init schizo_init(struct device_node *dp, char *model_name)
-{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+out_free_iommu_A:
+ kfree(p->pbm_A.iommu);
+
+out_free_controller:
+ kfree(p);
+
+out_err:
+ return err;
}
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+ const struct of_device_id *match)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
+ return __schizo_init(op, (unsigned long) match->data);
}
-void __init tomatillo_init(struct device_node *dp, char *model_name)
+/* The ordering of this table is very important. Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001. So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+ {
+ .name = "pci",
+ .compatible = "pci108e,a801",
+ .data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+ },
+ {
+ .name = "pci",
+ .compatible = "pci108e,8002",
+ .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+ },
+ {
+ .name = "pci",
+ .compatible = "pci108e,8001",
+ .data = (void *) PBM_CHIP_TYPE_SCHIZO,
+ },
+ {},
+};
+
+static struct of_platform_driver schizo_driver = {
+ .name = DRIVER_NAME,
+ .match_table = schizo_match,
+ .probe = schizo_probe,
+};
+
+static int __init schizo_init(void)
{
- __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
+ return of_register_driver(&schizo_driver, &of_bus_type);
}
+
+subsys_initcall(schizo_init);
OpenPOWER on IntegriCloud