/* * linux/arch/alpha/kernel/core_marvel.c * * Code common to all Marvel based systems. */ #define __EXTERN_INLINE inline #include #include #undef __EXTERN_INLINE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "proto.h" #include "pci_impl.h" /* * Debug helpers */ #define DEBUG_CONFIG 0 #if DEBUG_CONFIG # define DBG_CFG(args) printk args #else # define DBG_CFG(args) #endif /* * Private data */ static struct io7 *io7_head = NULL; /* * Helper functions */ static unsigned long __attribute__ ((unused)) read_ev7_csr(int pe, unsigned long offset) { ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset); unsigned long q; mb(); q = ev7csr->csr; mb(); return q; } static void __attribute__ ((unused)) write_ev7_csr(int pe, unsigned long offset, unsigned long q) { ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset); mb(); ev7csr->csr = q; mb(); } static char * __init mk_resource_name(int pe, int port, char *str) { char tmp[80]; char *name; sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port); name = alloc_bootmem(strlen(tmp) + 1); strcpy(name, tmp); return name; } inline struct io7 * marvel_next_io7(struct io7 *prev) { return (prev ? prev->next : io7_head); } struct io7 * marvel_find_io7(int pe) { struct io7 *io7; for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next) continue; return io7; } static struct io7 * __init alloc_io7(unsigned int pe) { struct io7 *io7; struct io7 *insp; int h; if (marvel_find_io7(pe)) { printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe); return NULL; } io7 = alloc_bootmem(sizeof(*io7)); io7->pe = pe; spin_lock_init(&io7->irq_lock); for (h = 0; h < 4; h++) { io7->ports[h].io7 = io7; io7->ports[h].port = h; io7->ports[h].enabled = 0; /* default to disabled */ } /* * Insert in pe sorted order. */ if (NULL == io7_head) /* empty list */ io7_head = io7; else if (io7_head->pe > io7->pe) { /* insert at head */ io7->next = io7_head; io7_head = io7; } else { /* insert at position */ for (insp = io7_head; insp; insp = insp->next) { if (insp->pe == io7->pe) { printk(KERN_ERR "Too many IO7s at PE %d\n", io7->pe); return NULL; } if (NULL == insp->next || insp->next->pe > io7->pe) { /* insert here */ io7->next = insp->next; insp->next = io7; break; } } if (NULL == insp) { /* couldn't insert ?!? */ printk(KERN_WARNING "Failed to insert IO7 at PE %d " " - adding at head of list\n", io7->pe); io7->next = io7_head; io7_head = io7; } } return io7; } void io7_clear_errors(struct io7 *io7) { io7_port7_csrs *p7csrs; io7_ioport_csrs *csrs; int port; /* * First the IO ports. */ for (port = 0; port < 4; port++) { csrs = IO7_CSRS_KERN(io7->pe, port); csrs->POx_ERR_SUM.csr = -1UL; csrs->POx_TLB_ERR.csr = -1UL; csrs->POx_SPL_COMPLT.csr = -1UL; csrs->POx_TRANS_SUM.csr = -1UL; } /* * Then the common ones. */ p7csrs = IO7_PORT7_CSRS_KERN(io7->pe); p7csrs->PO7_ERROR_SUM.csr = -1UL; p7csrs->PO7_UNCRR_SYM.csr = -1UL; p7csrs->PO7_CRRCT_SYM.csr = -1UL; } /* * IO7 PCI, PCI/X, AGP configuration. */ static void __init io7_init_hose(struct io7 *io7, int port) { static int hose_index = 0; struct pci_controller *hose = alloc_pci_controller(); struct io7_port *io7_port = &io7->ports[port]; io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port); int i; hose->index = hose_index++; /* arbitrary */ /* * We don't have an isa or legacy hose, but glibc expects to be * able to use the bus == 0 / dev == 0 form of the iobase syscall * to determine information about the i/o system. Since XFree86 * relies on glibc's determination to tell whether or not to use * sparse access, we need to point the pci_isa_hose at a real hose * so at least that determination is correct. */ if (hose->index == 0) pci_isa_hose = hose; io7_port->csrs = csrs; io7_port->hose = hose; hose->sysdata = io7_port; hose->io_space = alloc_resource(); hose->mem_space = alloc_resource(); /* * Base addresses for userland consumption. Since these are going * to be mapped, they are pure physical addresses. */ hose->sparse_mem_base = hose->sparse_io_base = 0; hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port); hose->dense_io_base = IO7_IO_PHYS(io7->pe, port); /* * Base addresses and resource ranges for kernel consumption. */ hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port); hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port); hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1; hose->io_space->name = mk_resource_name(io7->pe, port, "IO"); hose->io_space->flags = IORESOURCE_IO; hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port); hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1; hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM"); hose->mem_space->flags = IORESOURCE_MEM; if (request_resource(&ioport_resource, hose->io_space) < 0) printk(KERN_ERR "Failed to request IO on hose %d\n", hose->index); if (request_resource(&iomem_resource, hose->mem_space) < 0) printk(KERN_ERR "Failed to request MEM on hose %d\n", hose->index); /* * Save the existing DMA window settings for later restoration. */ for (i = 0; i < 4; i++) { io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr; io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr; io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr; } /* * Set up the PCI to main memory translation windows. * * Window 0 is scatter-gather 8MB at 8MB * Window 1 is direct access 1GB at 2GB * Window 2 is scatter-gather (up-to) 1GB at 3GB * Window 3 is disabled */ /* * TBIA before modifying windows. */ marvel_pci_tbi(hose, 0, -1); /* * Set up window 0 for scatter-gather 8MB at 8MB. */ hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe), hose, 0x00800000, 0x00800000, 0); hose->sg_isa->align_entry = 8; /* cache line boundary */ csrs->POx_WBASE[0].csr = hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg; csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr; csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes); /* * Set up window 1 for direct-mapped 1GB at 2GB. */ csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena; csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr; csrs->POx_TBASE[1].csr = 0; /* * Set up window 2 for scatter-gather (up-to) 1GB at 3GB. */ hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe), hose, 0xc0000000, 0x40000000, 0); hose->sg_pci->align_entry = 8; /* cache line boundary */ csrs->POx_WBASE[2].csr = hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg; csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr; csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes); /* * Disable window 3. */ csrs->POx_WBASE[3].csr = 0; /* * Make sure that the AGP Monster Window is disabled. */ csrs->POx_CTRL.csr &= ~(1UL << 61); #if 1 printk("FIXME: disabling master aborts\n"); csrs->POx_MSK_HEI.csr &= ~(3UL << 14); #endif /* * TBIA after modifying windows. */ marvel_pci_tbi(hose, 0, -1); } static void __init marvel_init_io7(struct io7 *io7) { int i; printk("Initializing IO7 at PID %d\n", io7->pe); /* * Get the Port 7 CSR pointer. */ io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);