diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_sabre.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sabre.c | 152 |
1 files changed, 92 insertions, 60 deletions
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 46a9b31cf..3788f71d3 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1,9 +1,9 @@ -/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $ +/* $Id: pci_sabre.c,v 1.8 2000/01/06 23:51:49 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */ #include <linux/kernel.h> @@ -65,6 +65,14 @@ #define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */ #define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */ #define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */ +#define SABRE_IOMMU_TSBSZ_1K 0x0000000000000000 +#define SABRE_IOMMU_TSBSZ_2K 0x0000000000010000 +#define SABRE_IOMMU_TSBSZ_4K 0x0000000000020000 +#define SABRE_IOMMU_TSBSZ_8K 0x0000000000030000 +#define SABRE_IOMMU_TSBSZ_16K 0x0000000000040000 +#define SABRE_IOMMU_TSBSZ_32K 0x0000000000050000 +#define SABRE_IOMMU_TSBSZ_64K 0x0000000000060000 +#define SABRE_IOMMU_TSBSZ_128K 0x0000000000070000 #define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */ #define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */ #define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */ @@ -601,7 +609,7 @@ static unsigned int __init sabre_irq_build(struct pci_controller_info *p, unsigned int ino) { struct ino_bucket *bucket; - volatile unsigned int *imap, *iclr; + unsigned long imap, iclr; unsigned long imap_off, iclr_off; int pil, inofixup = 0; @@ -620,12 +628,12 @@ static unsigned int __init sabre_irq_build(struct pci_controller_info *p, /* Now build the IRQ bucket. */ pil = sabre_ino_to_pil(pdev, ino); - imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); - imap += 1; + imap = p->controller_regs + imap_off; + imap += 4; iclr_off = sabre_iclr_offset(ino); - iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); - iclr += 1; + iclr = p->controller_regs + iclr_off; + iclr += 4; if ((ino & 0x20) == 0) inofixup = ino & 0x03; @@ -717,13 +725,13 @@ static void sabre_check_iommu_error(struct pci_controller_info *p, type_string = "Unknown"; break; }; - printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", - p->index, i, type_string, + printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", + p->index, i, tag, type_string, ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT)); - printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n", - p->index, i, + printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n", + p->index, i, data, ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), @@ -814,6 +822,10 @@ static void sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs) "DMA Read" : ((error_bits & SABRE_CEAFSR_PDWR) ? "DMA Write" : "???"))); + + /* XXX Use syndrome and afar to print out module string just like + * XXX UDB CE trap handler does... -DaveM + */ printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "was_block(%d)\n", p->index, @@ -1020,21 +1032,15 @@ static void __init sabre_base_address_update(struct pci_dev *pdev, int resource) static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) { - struct pci_dev *pdev; - u32 dword; - u16 word; - - for(pdev = pci_devices; pdev; pdev = pdev->next) { - if(pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); - break; - } - } + struct list_head *walk = &sabre_bus->devices; + + for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { + struct pci_dev *pdev = pci_dev_b(walk); - for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { + u16 word; + sabre_read_word(pdev, PCI_COMMAND, &word); word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | @@ -1044,32 +1050,6 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre /* Status register bits are "write 1 to clear". */ sabre_write_word(pdev, PCI_STATUS, 0xffff); sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); - - sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word); - word = PCI_BRIDGE_CTL_MASTER_ABORT | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_PARITY; - sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word); - - sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword); - dword = APB_PCI_CTL_HIGH_SERR | - APB_PCI_CTL_HIGH_ARBITER_EN; - sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword); - - /* Systems with SIMBA are usually workstations, so - * we configure to park to SIMBA not to the previous - * bus owner. - */ - sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword); - dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; - sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword); - - /* Don't mess with the retry limit and PIO/DMA latency - * timer settings. But do set primary and secondary - * latency timers. - */ - sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); - sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); } } } @@ -1077,7 +1057,8 @@ static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre static void __init sabre_scan_bus(struct pci_controller_info *p) { static int once = 0; - struct pci_bus *sabre_bus, *pbus; + struct pci_bus *sabre_bus; + struct list_head *walk; /* Unlike for PSYCHO, we can only have one SABRE * in a system. Having multiple SABREs is thus @@ -1100,7 +1081,9 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) &p->pbm_A); apb_init(p, sabre_bus); - for (pbus = sabre_bus->children; pbus; pbus = pbus->next) { + walk = &sabre_bus->children; + for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { + struct pci_bus *pbus = pci_bus_b(walk); struct pci_pbm_info *pbm; if (pbus->number == p->pbm_A.pci_first_busno) { @@ -1124,30 +1107,49 @@ static void __init sabre_scan_bus(struct pci_controller_info *p) static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset) { +#ifndef NEW_PCI_DMA_MAP struct linux_mlist_p1275 *mlist; - unsigned long tsbbase, i, n, order; + unsigned long n; iopte_t *iopte; +#endif + unsigned long tsbbase, i, order; u64 control; + /* Setup initial software IOMMU state. */ + spin_lock_init(&p->iommu.lock); + p->iommu.iommu_cur_ctx = 0; + + /* Register addresses. */ + p->iommu.iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL; + p->iommu.iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE; + p->iommu.iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH; + p->iommu.write_complete_reg = p->controller_regs + SABRE_WRSYNC; + /* Sabre's IOMMU lacks ctx flushing. */ + p->iommu.iommu_ctxflush = 0; + /* Invalidate TLB Entries. */ control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); - control |= IOMMU_CTRL_DENAB; + control |= SABRE_IOMMUCTRL_DENAB; sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); for(i = 0; i < 16; i++) sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); - control &= ~(IOMMU_CTRL_DENAB); + control &= ~(SABRE_IOMMUCTRL_DENAB); sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); for(order = 0;; order++) if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) break; - tsbbase = __get_free_pages(GFP_DMA, order); + tsbbase = __get_free_pages(GFP_KERNEL, order); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } + p->iommu.page_table = (iopte_t *)tsbbase; + p->iommu.page_table_map_base = dvma_offset; + +#ifndef NEW_PCI_DMA_MAP iopte = (iopte_t *)tsbbase; /* Initialize to "none" settings. */ @@ -1216,27 +1218,47 @@ out: prom_printf("Try booting with mem=xxxM or similar\n"); prom_halt(); } +#endif sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); - control &= ~(IOMMU_CTRL_TSBSZ); - control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); +#ifndef NEW_PCI_DMA_MAP + control &= ~(SABRE_IOMMUCTRL_TSBSZ); + control |= (SABRE_IOMMUCTRL_TBWSZ | SABRE_IOMMUCTRL_ENAB); switch(tsbsize) { case 8: - control |= IOMMU_TSBSZ_8K; + control |= SABRE_IOMMU_TSBSZ_8K; break; case 16: - control |= IOMMU_TSBSZ_16K; + control |= SABRE_IOMMU_TSBSZ_16K; break; case 32: - control |= IOMMU_TSBSZ_32K; + control |= SABRE_IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } +#else + control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); + control |= SABRE_IOMMUCTRL_ENAB; + switch(tsbsize) { + case 64: + control |= SABRE_IOMMU_TSBSZ_64K; + p->iommu.page_table_sz_bits = 16; + break; + case 128: + control |= SABRE_IOMMU_TSBSZ_128K; + p->iommu.page_table_sz_bits = 17; break; default: prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); prom_halt(); break; } +#endif sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); } @@ -1445,6 +1467,7 @@ void __init sabre_init(int pnode) } switch(vdma[1]) { +#ifndef NEW_PCI_DMA_MAP case 0x20000000: tsbsize = 8; break; @@ -1454,6 +1477,15 @@ void __init sabre_init(int pnode) case 0x80000000: tsbsize = 32; break; +#else + case 0x20000000: + tsbsize = 64; + break; + case 0x40000000: + case 0x80000000: + tsbsize = 128; + break; +#endif default: prom_printf("SABRE: strange virtual-dma size.\n"); prom_halt(); |