#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
+#include <asm/pstate.h>
#include "pci_impl.h"
#include "iommu_common.h"
/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */
/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */
/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */
-/*0x18*/4, /* SCSI */
-/*0x19*/4, /* second SCSI */
+/*0x18*/5, /* SCSI */
+/*0x19*/5, /* second SCSI */
/*0x1a*/0, /* UNKNOWN */
/*0x1b*/0, /* UNKNOWN */
/*0x1c*/8, /* Parallel */
/*0x20*/13, /* Audio Record */
/*0x21*/14, /* Audio Playback */
/*0x22*/12, /* Serial */
-/*0x23*/4, /* EBUS I2C */
+/*0x23*/5, /* EBUS I2C */
/*0x24*/10, /* RTC Clock */
/*0x25*/11, /* Floppy */
/*0x26*/0, /* UNKNOWN */
/*0x3f*/0, /* Reserved for NewLink */
};
-static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+static int schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
{
int ret;
ret = schizo_pil_table[ino];
if (ret == 0 && pdev == NULL) {
- ret = 4;
+ ret = 5;
} else if (ret == 0) {
switch ((pdev->class >> 16) & 0xff) {
case PCI_BASE_CLASS_STORAGE:
- ret = 4;
+ ret = 5;
break;
case PCI_BASE_CLASS_NETWORK:
break;
default:
- ret = 4;
+ ret = 5;
break;
};
}
return ret;
}
-static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
- struct pci_dev *pdev,
- unsigned int ino)
+static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
+{
+ unsigned long sync_reg = (unsigned long) _arg2;
+ u64 mask = 1UL << (__irq_ino(__irq(bucket)) & IMAP_INO);
+ u64 val;
+ int limit;
+
+ schizo_write(sync_reg, mask);
+
+ limit = 100000;
+ val = 0;
+ while (--limit) {
+ val = schizo_read(sync_reg);
+ if (!(val & mask))
+ break;
+ }
+ if (limit <= 0) {
+ printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
+ val, mask);
+ }
+
+ if (_arg1) {
+ static unsigned char cacheline[64]
+ __attribute__ ((aligned (64)));
+
+ __asm__ __volatile__("rd %%fprs, %0\n\t"
+ "or %0, %4, %1\n\t"
+ "wr %1, 0x0, %%fprs\n\t"
+ "stda %%f0, [%5] %6\n\t"
+ "wr %0, 0x0, %%fprs\n\t"
+ "membar #Sync"
+ : "=&r" (mask), "=&r" (val)
+ : "0" (mask), "1" (val),
+ "i" (FPRS_FEF), "r" (&cacheline[0]),
+ "i" (ASI_BLK_COMMIT_P));
+ }
+}
+
+static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
+ struct pci_dev *pdev,
+ unsigned int ino)
{
struct ino_bucket *bucket;
unsigned long imap, iclr;
bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap));
bucket->flags |= IBF_PCI;
+ if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+ struct irq_desc *p = bucket->irq_info;
+
+ p->pre_handler = tomatillo_wsync_handler;
+ p->pre_handler_arg1 = ((pbm->chip_version <= 4) ?
+ (void *) 1 : (void *) 0);
+ p->pre_handler_arg2 = (void *) pbm->sync_reg;
+ }
+
return __irq(bucket);
}
UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
};
-static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(stc_buf_lock);
static unsigned long stc_error_buf[128];
static unsigned long stc_tag_buf[16];
static unsigned long stc_line_buf[16];
-/* These offsets look weird because I keep in pbm->controller_regs
- * the second PROM register property minus 0x10000 which is the
- * base of the Safari and UPA64S registers of SCHIZO.
- */
-#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL)
-#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL)
+#define SCHIZO_UE_INO 0x30 /* Uncorrectable ECC error */
+#define SCHIZO_CE_INO 0x31 /* Correctable ECC error */
+#define SCHIZO_PCIERR_A_INO 0x32 /* PBM A PCI bus error */
+#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */
+#define SCHIZO_SERR_INO 0x34 /* Safari interface error */
-static void schizo_clear_other_err_intr(int irq)
+struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
{
- struct ino_bucket *bucket = __bucket(irq);
- unsigned long iclr = bucket->iclr;
+ 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;
+}
+
+static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
+{
+ struct pci_pbm_info *pbm;
+ struct ino_bucket *bucket;
+ unsigned long iclr;
+
+ /* Do not clear the interrupt for the other PCI bus.
+ *
+ * This "ACK both PBM IRQs" only needs to be performed
+ * for chip-wide error interrupts.
+ */
+ if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO ||
+ (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO)
+ return;
+
+ pbm = pbm_for_ino(p, irq);
+ if (pbm == &p->pbm_A)
+ pbm = &p->pbm_B;
+ else
+ pbm = &p->pbm_A;
+
+ irq = schizo_irq_build(pbm, NULL,
+ (pbm->portid << 6) | (irq & IMAP_INO));
+ bucket = __bucket(irq);
+ iclr = bucket->iclr;
- iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF);
upa_writel(ICLR_IDLE, iclr);
}
/* Interrogate IOMMU for error status. */
schizo_check_iommu_error(p, UE_ERR);
- schizo_clear_other_err_intr(irq);
+ schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
printk("(none)");
printk("]\n");
- schizo_clear_other_err_intr(irq);
+ schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
#define SCHIZO_PCI_CTRL (0x2000UL)
#define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) /* Safari */
+#define SCHIZO_PCICTRL_DTO_INT (1UL << 61UL) /* Tomatillo */
#define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */
#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) /* Safari */
#define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) /* Safari */
#define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL) /* Safari */
#define SCHIZO_PCICTRL_SERR (1UL << 34UL) /* Safari/Tomatillo */
#define SCHIZO_PCICTRL_PCISPD (1UL << 33UL) /* Safari */
-#define SCHIZO_PCICTRL_MRM_PREF (1UL << 28UL) /* Tomatillo */
-#define SCHIZO_PCICTRL_RDO_PREF (1UL << 27UL) /* Tomatillo */
-#define SCHIZO_PCICTRL_RDL_PREF (1UL << 26UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_MRM_PREF (1UL << 30UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDO_PREF (1UL << 29UL) /* Tomatillo */
+#define SCHIZO_PCICTRL_RDL_PREF (1UL << 28UL) /* Tomatillo */
#define SCHIZO_PCICTRL_PTO (3UL << 24UL) /* Safari/Tomatillo */
#define SCHIZO_PCICTRL_PTO_SHIFT 24UL
#define SCHIZO_PCICTRL_TRWSW (7UL << 21UL) /* Tomatillo */
if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
- schizo_clear_other_err_intr(irq);
+ schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
p->index, errlog);
- schizo_clear_other_err_intr(irq);
+ schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
p->index);
schizo_check_iommu_error(p, SAFARI_ERR);
- schizo_clear_other_err_intr(irq);
+ schizo_clear_other_err_intr(p, irq);
return IRQ_HANDLED;
}
#define SCHIZO_SAFARI_IRQCTRL 0x10010UL
#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL
-#define SCHIZO_UE_INO 0x30 /* Uncorrectable ECC error */
-#define SCHIZO_CE_INO 0x31 /* Correctable ECC error */
-#define SCHIZO_PCIERR_A_INO 0x32 /* PBM A PCI bus error */
-#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;
- prom_printf("TOMATILLO%d: No entry in ino bitmap for %d\n",
- p->index, ino);
- prom_halt();
- /* NOTREACHED */
- return NULL;
-}
-
/* How the Tomatillo IRQs are routed around is pure guesswork here.
*
* All the Tomatillo devices I see in prtconf dumps seem to have only
* PCI bus units of the same Tomatillo. I still have not really
* figured this out...
*/
-static void __init tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm;
unsigned int irq;
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
-static void __init schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_controller_info *p)
{
struct pci_pbm_info *pbm;
unsigned int irq;
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
-static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+static void pbm_config_busmastering(struct pci_pbm_info *pbm)
{
u8 *addr;
pci_config_write8(addr, 64);
}
-static void __init pbm_scan_bus(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
+static void pbm_scan_bus(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
{
- struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL);
+ struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
if (!cookie) {
prom_printf("%s: Critical allocation failure.\n", pbm->name);
}
/* All we care about is the PBM. */
- memset(cookie, 0, sizeof(*cookie));
cookie->pbm = pbm;
pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
pci_setup_busmastering(pbm, pbm->pci_bus);
}
-static void __init __schizo_scan_bus(struct pci_controller_info *p,
- int chip_type)
+static void __schizo_scan_bus(struct pci_controller_info *p,
+ int chip_type)
{
if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) {
printk("PCI: Only one PCI bus module of controller found.\n");
schizo_register_error_handlers(p);
}
-static void __init schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_controller_info *p)
{
__schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);
}
-static void __init tomatillo_scan_bus(struct pci_controller_info *p)
+static void tomatillo_scan_bus(struct pci_controller_info *p)
{
__schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);
}
-static void __init schizo_base_address_update(struct pci_dev *pdev, int resource)
+static void schizo_base_address_update(struct pci_dev *pdev, int resource)
{
struct pcidev_cookie *pcp = pdev->sysdata;
struct pci_pbm_info *pbm = pcp->pbm;
(((u32)(res->start - root->start)) & ~size));
if (resource == PCI_ROM_RESOURCE) {
reg |= PCI_ROM_ADDRESS_ENABLE;
- res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ res->flags |= IORESOURCE_ROM_ENABLE;
}
pci_write_config_dword(pdev, where, reg);
pci_write_config_dword(pdev, where + 4, 0);
}
-static void __init schizo_resource_adjust(struct pci_dev *pdev,
- struct resource *res,
- struct resource *root)
+static void schizo_resource_adjust(struct pci_dev *pdev,
+ struct resource *res,
+ struct resource *root)
{
res->start += root->start;
res->end += root->start;
pbm->mem_space.start);
}
-static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
+static void pbm_register_toplevel_resources(struct pci_controller_info *p,
+ struct pci_pbm_info *pbm)
{
pbm->io_space.name = pbm->mem_space.name = pbm->name;
static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
- unsigned long tsbbase, i, tagbase, database, order;
+ unsigned long i, tagbase, database;
u32 vdma[2], dma_mask;
u64 control;
int err, tsbsize;
prom_halt();
};
- /* Setup initial software IOMMU state. */
- spin_lock_init(&iommu->lock);
- iommu->iommu_cur_ctx = 0;
-
/* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
+ pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
- iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0);
- if (!iommu->dummy_page) {
- prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n");
- prom_halt();
- }
- memset((void *)iommu->dummy_page, 0, PAGE_SIZE);
- iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page);
-
- /* Using assumed page size 8K with 128K entries we need 1MB iommu page
- * table (128K ioptes * 8 bytes per iopte). This is
- * page order 7 on UltraSparc.
- */
- order = get_order(tsbsize * 8 * 1024);
- tsbbase = __get_free_pages(GFP_KERNEL, order);
- if (!tsbbase) {
- prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name);
- prom_halt();
- }
-
- iommu->page_table = (iopte_t *)tsbbase;
- iommu->page_table_map_base = vdma[0];
- iommu->dma_addr_mask = dma_mask;
- pci_iommu_table_init(iommu, PAGE_SIZE << order);
-
- switch (tsbsize) {
- case 64:
- iommu->page_table_sz_bits = 16;
- break;
-
- case 128:
- iommu->page_table_sz_bits = 17;
- break;
-
- default:
- prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
- prom_halt();
- break;
- };
-
- /* We start with no consistent mappings. */
- iommu->lowest_consistent_map =
- 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS);
-
- for (i = 0; i < PBM_NCLUSTERS; i++) {
- iommu->alloc_info[i].flush = 0;
- iommu->alloc_info[i].next = 0;
- }
-
- schizo_write(iommu->iommu_tsbbase, __pa(tsbbase));
+ schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
control = schizo_read(iommu->iommu_control);
control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
#define TOMATILLO_PCI_IOC_TDIAG (0x2250UL)
#define TOMATILLO_PCI_IOC_DDIAG (0x2290UL)
-static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm)
+static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
u64 tmp;
- /* Set IRQ retry to infinity. */
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY,
- SCHIZO_IRQ_RETRY_INF);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
- /* Enable arbiter for all PCI slots. Also, disable PCI interval
- * timer so that DTO (Discard TimeOuts) are not reported because
- * some Schizo revisions report them erroneously.
- */
tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
- if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS &&
- pbm->chip_version == 0x5 &&
- pbm->chip_revision == 0x1)
- tmp |= 0x0f;
- else
- tmp |= 0xff;
- tmp &= ~SCHIZO_PCICTRL_PTO;
+ /* Enable arbiter for all PCI slots. */
+ tmp |= 0xff;
+
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
- pbm->chip_version == 0x2)
+ pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- else
- tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
tmp |= SCHIZO_PCICTRL_PARK;
+ else
+ tmp &= ~SCHIZO_PCICTRL_PARK;
+
+ if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
+ pbm->chip_version <= 0x1)
+ tmp |= SCHIZO_PCICTRL_DTO_INT;
+ else
+ tmp &= ~SCHIZO_PCICTRL_DTO_INT;
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
- tmp |= SCHIZO_PCICTRL_MRM_PREF;
+ tmp |= (SCHIZO_PCICTRL_MRM_PREF |
+ SCHIZO_PCICTRL_RDO_PREF |
+ SCHIZO_PCICTRL_RDL_PREF);
schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
}
}
-static void __init schizo_pbm_init(struct pci_controller_info *p,
- int prom_node, u32 portid,
- int chip_type)
+static void schizo_pbm_init(struct pci_controller_info *p,
+ int prom_node, u32 portid,
+ int chip_type)
{
struct linux_prom64_registers pr_regs[4];
unsigned int busrange[2];
pbm->pbm_regs = pr_regs[0].phys_addr;
pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+ if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+ pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
+
sprintf(pbm->name,
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO%d PBM%c" :
return (x == y);
}
-static void __init __schizo_init(int node, char *model_name, int chip_type)
+static void __schizo_init(int node, char *model_name, int chip_type)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
}
}
- p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
+ p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p) {
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}
- memset(p, 0, sizeof(*p));
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu) {
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}
- memset(iommu, 0, sizeof(*iommu));
p->pbm_A.iommu = iommu;
- iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
+ iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC);
if (!iommu) {
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}
- memset(iommu, 0, sizeof(*iommu));
p->pbm_B.iommu = iommu;
p->next = pci_controller_root;
schizo_pbm_init(p, node, portid, chip_type);
}
-void __init schizo_init(int node, char *model_name)
+void schizo_init(int node, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
}
-void __init schizo_plus_init(int node, char *model_name)
+void schizo_plus_init(int node, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
}
-void __init tomatillo_init(int node, char *model_name)
+void tomatillo_init(int node, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
}