#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/oplib.h>
#include "pci_impl.h"
#include "iommu_common.h"
SCHIZO_CONFIG_ENCODE(bus, devfn, where));
}
-/* Just make sure the bus number is in range. */
-static int schizo_out_of_range(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned char devfn)
-{
- if (bus < pbm->pci_first_busno ||
- bus > pbm->pci_last_busno)
- return 1;
- return 0;
-}
-
-/* SCHIZO PCI configuration space accessors. */
-
-static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
- u16 tmp16;
- u8 tmp8;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
-
- addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (schizo_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
- switch (size) {
- case 1:
- pci_config_read8((u8 *)addr, &tmp8);
- *value = tmp8;
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read16((u16 *)addr, &tmp16);
- *value = tmp16;
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read32(addr, value);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
- addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (schizo_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_write8((u8 *)addr, value);
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write16((u16 *)addr, value);
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_config_write32(addr, value);
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops schizo_ops = {
- .read = schizo_read_pci_cfg,
- .write = schizo_write_pci_cfg,
-};
-
/* SCHIZO error handling support. */
enum schizo_error_type {
UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
schizo_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Uncorrectable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & SCHIZO_UEAFSR_PPIO) ?
"PIO" :
((error_bits & SCHIZO_UEAFSR_PDRD) ?
"DMA Read" :
((error_bits & SCHIZO_UEAFSR_PDWR) ?
"DMA Write" : "???")))));
- printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
- p->index,
+ printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
- printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
- p->index,
+ printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
- printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
- printk("PCI%d: UE Secondary errors [", p->index);
+ printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: UE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SCHIZO_UEAFSR_SPIO) {
reported++;
static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
{
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;
schizo_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PCI%d: Correctable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Correctable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & SCHIZO_CEAFSR_PPIO) ?
"PIO" :
((error_bits & SCHIZO_CEAFSR_PDRD) ?
/* XXX Use syndrome and afar to print out module string just like
* XXX UDB CE trap handler does... -DaveM
*/
- printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
- p->index,
+ printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
- printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
- p->index,
+ printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
- printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
- printk("PCI%d: CE Secondary errors [", p->index);
+ printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: CE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SCHIZO_CEAFSR_SPIO) {
reported++;
*/
if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
schizo_check_iommu_error(p, PCI_ERR);
- pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+ pci_scan_for_target_abort(pbm, pbm->pci_bus);
}
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
- pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+ pci_scan_for_master_abort(pbm, pbm->pci_bus);
/* For excessive retries, PSYCHO/PBM will abort the device
* and there is no way to specifically check for excessive
*/
if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
- pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+ pci_scan_for_parity_error(pbm, pbm->pci_bus);
return IRQ_HANDLED;
}
errlog & ~(SAFARI_ERRLOG_ERROUT));
if (!(errlog & BUS_ERROR_UNMAP)) {
- printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
- p->index, errlog);
+ printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
+ pbm->name, errlog);
return IRQ_HANDLED;
}
- printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
- p->index);
+ printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+ pbm->name);
schizo_check_iommu_error(p, SAFARI_ERR);
return IRQ_HANDLED;
{
struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
+ int err;
/* Tomatillo IRQ property layout is:
* 0: PCIERR
* 4: POWER FAIL?
*/
- if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO))
- request_irq(op->irqs[1], schizo_ue_intr, 0,
- "TOMATILLO_UE", pbm);
-
- 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);
-
- if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO))
- request_irq(op->irqs[3], schizo_safarierr_intr, 0,
- "TOMATILLO_SERR", pbm);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+ err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "TOMATILLO_UE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register UE, "
+ "err=%d\n", pbm->name, err);
+ }
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+ err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "TOMATILLO_CE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register CE, "
+ "err=%d\n", pbm->name, err);
+ }
+ err = 0;
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
+ } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
+ }
+ if (err)
+ printk(KERN_WARNING "%s: Could not register PCIERR, "
+ "err=%d\n", pbm->name, err);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+ err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "TOMATILLO_SERR", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register SERR, "
+ "err=%d\n", pbm->name, err);
+ }
/* Enable UE and CE interrupts for controller. */
schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
{
struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
+ int err;
/* Schizo IRQ property layout is:
* 0: PCIERR
* 4: POWER FAIL?
*/
- 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);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+ err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "SCHIZO_UE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register UE, "
+ "err=%d\n", pbm->name, err);
+ }
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+ err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "SCHIZO_CE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register CE, "
+ "err=%d\n", pbm->name, err);
+ }
+ err = 0;
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+ } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+ }
+ if (err)
+ printk(KERN_WARNING "%s: Could not register PCIERR, "
+ "err=%d\n", pbm->name, err);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+ err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "SCHIZO_SERR", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register SERR, "
+ "err=%d\n", pbm->name, err);
+ }
/* Enable UE and CE interrupts for controller. */
schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
#define SCHIZO_IOMMU_FLUSH (0x00210UL)
#define SCHIZO_IOMMU_CTXFLUSH (0x00218UL)
-static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
+static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
+ int tsbsize, err;
u64 control;
- int tsbsize;
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH;
+ iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH;
/* We use the main control/status register of SCHIZO as the write
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
- pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ if (err)
+ return err;
schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
control |= SCHIZO_IOMMU_CTRL_ENAB;
schizo_write(iommu->iommu_control, control);
+
+ return 0;
}
#define SCHIZO_PCI_IRQ_RETRY (0x1a00UL)
}
}
-static void schizo_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid,
- int chip_type)
+static int schizo_pbm_init(struct pci_controller_info *p,
+ struct device_node *dp, u32 portid,
+ int chip_type)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
const char *chipset_name;
- int is_pbm_a;
+ int is_pbm_a, err;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
pci_pbm_root = pbm;
pbm->scan_bus = schizo_scan_bus;
- pbm->pci_ops = &schizo_ops;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 8;
+
+ pbm->index = pci_num_pbms++;
pbm->portid = portid;
pbm->parent = p;
pci_get_pbm_props(pbm);
- schizo_pbm_iommu_init(pbm);
+ err = schizo_pbm_iommu_init(pbm);
+ if (err)
+ return err;
+
schizo_pbm_strbuf_init(pbm);
+
+ return 0;
}
static inline int portid_compare(u32 x, u32 y, int chip_type)
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid, chip_type)) {
- schizo_pbm_init(pbm->parent, dp, portid, chip_type);
+ if (schizo_pbm_init(pbm->parent, dp,
+ portid, chip_type))
+ goto fatal_memory_error;
return;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
- goto memfail;
+ goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
- goto memfail;
+ goto fatal_memory_error;
p->pbm_A.iommu = iommu;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
- goto memfail;
+ goto fatal_memory_error;
p->pbm_B.iommu = iommu;
- p->index = pci_num_controllers++;
-
- /* Like PSYCHO we have a 2GB aligned area for memory space. */
- pci_memspace_mask = 0x7fffffffUL;
+ if (schizo_pbm_init(p, dp, portid, chip_type))
+ goto fatal_memory_error;
- schizo_pbm_init(p, dp, portid, chip_type);
return;
-memfail:
+fatal_memory_error:
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}