Commit f0bde625 authored by Richard Henderson's avatar Richard Henderson Committed by Richard Henderson

[ALPHA] Marvel (AlphaServer ES47, ES80, GS1280) support.

From Jeff.Wiedemeier@hp.com.
parent c0b775bb
...@@ -65,6 +65,7 @@ choice ...@@ -65,6 +65,7 @@ choice
LX164 AlphaPC164-LX LX164 AlphaPC164-LX
Miata Personal Workstation 433a, 433au, 500a, Miata Personal Workstation 433a, 433au, 500a,
500au, 600a, or 600au 500au, 600a, or 600au
Marvel AlphaServer ES47 / ES80 / GS1280
Mikasa AS 1000 Mikasa AS 1000
Noname AXPpci33, UDB (Multia) Noname AXPpci33, UDB (Multia)
Noritake AS 1000A, AS 600A, AS 800 Noritake AS 1000A, AS 600A, AS 800
...@@ -172,6 +173,11 @@ config ALPHA_LX164 ...@@ -172,6 +173,11 @@ config ALPHA_LX164
A technical overview of this board is available at A technical overview of this board is available at
<http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>. <http://www.unix-ag.org/Linux-Alpha/Architectures/LX164.html>.
config ALPHA_MARVEL
bool "Marvel"
help
AlphaServer ES47 / ES80 / GS1280 based on EV7.
config ALPHA_MIATA config ALPHA_MIATA
bool "Miata" bool "Miata"
help help
...@@ -394,7 +400,7 @@ config ALPHA_PYXIS ...@@ -394,7 +400,7 @@ config ALPHA_PYXIS
config ALPHA_EV6 config ALPHA_EV6
bool bool
depends on ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_DP264 || ALPHA_EIGER depends on ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_DP264 || ALPHA_EIGER || ALPHA_MARVEL
default y default y
config ALPHA_TSUNAMI config ALPHA_TSUNAMI
...@@ -404,11 +410,16 @@ config ALPHA_TSUNAMI ...@@ -404,11 +410,16 @@ config ALPHA_TSUNAMI
config ALPHA_EV67 config ALPHA_EV67
bool "EV67 (or later) CPU (speed > 600MHz)?" if ALPHA_DP264 || ALPHA_EIGER bool "EV67 (or later) CPU (speed > 600MHz)?" if ALPHA_DP264 || ALPHA_EIGER
default y if ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK default y if ALPHA_NAUTILUS || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
help help
Is this a machine based on the EV67 core? If in doubt, select N here Is this a machine based on the EV67 core? If in doubt, select N here
and the machine will be treated as an EV6. and the machine will be treated as an EV6.
config ALPHA_EV7
bool
depends on ALPHA_MARVEL
default y
config ALPHA_MCPCIA config ALPHA_MCPCIA
bool bool
depends on ALPHA_RAWHIDE depends on ALPHA_RAWHIDE
...@@ -426,7 +437,7 @@ config ALPHA_IRONGATE ...@@ -426,7 +437,7 @@ config ALPHA_IRONGATE
config ALPHA_SRM config ALPHA_SRM
bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME
default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
---help--- ---help---
There are two different types of booting firmware on Alphas: SRM, There are two different types of booting firmware on Alphas: SRM,
which is command line driven, and ARC, which uses menus and arrow which is command line driven, and ARC, which uses menus and arrow
...@@ -468,7 +479,7 @@ config ALPHA_BROKEN_IRQ_MASK ...@@ -468,7 +479,7 @@ config ALPHA_BROKEN_IRQ_MASK
config SMP config SMP
bool "Symmetric multi-processing support" bool "Symmetric multi-processing support"
depends on ALPHA_SABLE || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK depends on ALPHA_SABLE || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL
---help--- ---help---
This enables support for systems with more than one CPU. If you have This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If a system with only one CPU, like most personal computers, say N. If
......
...@@ -21,20 +21,19 @@ obj-$(CONFIG_MODULES) += module.o ...@@ -21,20 +21,19 @@ obj-$(CONFIG_MODULES) += module.o
ifdef CONFIG_ALPHA_GENERIC ifdef CONFIG_ALPHA_GENERIC
obj-y += core_apecs.o core_cia.o core_irongate.o core_lca.o \ obj-y += core_apecs.o core_cia.o core_irongate.o core_lca.o \
core_mcpcia.o core_polaris.o core_t2.o core_tsunami.o \ core_marvel.o core_mcpcia.o core_polaris.o core_t2.o \
core_titan.o core_wildfire.o core_tsunami.o core_titan.o core_wildfire.o
obj-y += sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \ obj-y += sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \ sys_jensen.o sys_marvel.o sys_miata.o sys_mikasa.o sys_nautilus.o \
sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ sys_titan.o sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
sys_sable.o sys_sio.o sys_sx164.o sys_takara.o \ sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_wildfire.o
sys_wildfire.o
obj-y += irq_pyxis.o irq_i8259.o irq_srm.o obj-y += irq_pyxis.o irq_i8259.o irq_srm.o
obj-y += es1888.o smc37c669.o smc37c93x.o ns87312.o obj-y += err_titan.o err_marvel.o
obj-y += err_titan.o obj-y += es1888.o smc37c669.o smc37c93x.o ns87312.o gct.o
else else
...@@ -43,6 +42,7 @@ obj-$(CONFIG_ALPHA_APECS) += core_apecs.o ...@@ -43,6 +42,7 @@ obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
obj-$(CONFIG_ALPHA_CIA) += core_cia.o obj-$(CONFIG_ALPHA_CIA) += core_cia.o
obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o
obj-$(CONFIG_ALPHA_LCA) += core_lca.o obj-$(CONFIG_ALPHA_LCA) += core_lca.o
obj-$(CONFIG_ALPHA_MARVEL) += core_marvel.o gct.o
obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o
obj-$(CONFIG_ALPHA_POLARIS) += core_polaris.o obj-$(CONFIG_ALPHA_POLARIS) += core_polaris.o
obj-$(CONFIG_ALPHA_T2) += core_t2.o obj-$(CONFIG_ALPHA_T2) += core_t2.o
...@@ -70,6 +70,7 @@ obj-$(CONFIG_ALPHA_EB64P) += sys_eb64p.o irq_i8259.o ...@@ -70,6 +70,7 @@ obj-$(CONFIG_ALPHA_EB64P) += sys_eb64p.o irq_i8259.o
obj-$(CONFIG_ALPHA_EB66) += sys_eb64p.o irq_i8259.o obj-$(CONFIG_ALPHA_EB66) += sys_eb64p.o irq_i8259.o
obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o irq_i8259.o obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o irq_i8259.o
obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o irq_i8259.o obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o irq_i8259.o
obj-$(CONFIG_ALPHA_MARVEL) += sys_marvel.o err_marvel.o
obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o irq_pyxis.o irq_i8259.o \ obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o irq_pyxis.o irq_i8259.o \
es1888.o smc37c669.o es1888.o smc37c669.o
obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o irq_i8259.o irq_srm.o obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o irq_i8259.o irq_srm.o
......
/*
* linux/arch/alpha/kernel/core_marvel.c
*
* Code common to all Marvel based systems
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/mc146818rtc.h>
#include <linux/rtc.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/smp.h>
#include <asm/hwrpb.h>
#include <asm/gct.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/rtc.h>
#define __EXTERN_INLINE inline
#include <asm/io.h>
#include <asm/core_marvel.h>
#undef __EXTERN_INLINE
#include <linux/bootmem.h> /* this must be *after* io.h / core_marvel.h */
#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
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;
}
struct io7 *marvel_next_io7(struct io7 *prev)
{
if (!prev) return io7_head;
return prev->next;
}
struct io7 *marvel_find_io7(int pe)
{
struct io7 *io7;
io7 = marvel_next_io7(NULL);
for(; io7 && io7->pe != pe; io7 = marvel_next_io7(io7));
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;
io7->irq_lock = SPIN_LOCK_UNLOCKED;
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 = (unsigned long)-1L;
csrs->POx_TLB_ERR.csr = (unsigned long)-1L;
csrs->POx_SPL_COMPLT.csr = (unsigned long)-1L;
csrs->POx_TRANS_SUM.csr = (unsigned long)-1L;
}
/*
* Then the common ones
*/
p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
p7csrs->PO7_ERROR_SUM.csr = (unsigned long)-1L;
p7csrs->PO7_UNCRR_SYM.csr = (unsigned long)-1L;
p7csrs->PO7_CRRCT_SYM.csr = (unsigned long)-1L;
}
/*
* 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);
/*
* Init this IO7's hoses
*/
for(i = 0; i < IO7_NUM_PORTS; i++) {
io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
if (csrs->POx_CACHE_CTL.csr == 8) {
io7->ports[i].enabled = 1;
io7_init_hose(io7, i);
}
}
}
void marvel_io7_present(gct6_node *node)
{
int pe;
if (node->type != GCT_TYPE_HOSE ||
node->subtype != GCT_SUBTYPE_IO_PORT_MODULE)
return;
pe = (node->id >> 8) & 0xff;
printk("Found an IO7 at PID %d\n", pe);
alloc_io7(pe);
}
static void __init
marvel_init_vga_hose(void)
{
#ifdef CONFIG_VGA_HOSE
u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
if (pu64[7] == 3) { /* TERM_TYPE == graphics */
struct pci_controller *hose = NULL;
int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
struct io7 *io7;
int pid, port;
/* FIXME - encoding is going to have to change for Marvel
* since hose will be able to overflow a byte...
* need to fix this decode when the console
* changes its encoding
*/
printk("console graphics is on hose %d (console)\n", h);
/*
* The console's hose numbering is:
*
* hose<n:2>: PID
* hose<1:0>: PORT
*
* We need to find the hose at that pid and port
*/
pid = h >> 2;
port = h & 3;
if ((io7 = marvel_find_io7(pid)))
hose = io7->ports[port].hose;
if (hose) {
printk("Console graphics on hose %d\n", hose->index);
pci_vga_hose = hose;
}
}
#endif /* CONFIG_VGA_HOSE */
}
gct6_search_struct gct_wanted_node_list[] = {
{ GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
{ 0, 0, NULL }
};
/*
* In case the GCT is not complete, let the user specify PIDs with IO7s
* at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
* where IO7s are connected
*/
static int __init marvel_specify_io7(char *str)
{
unsigned long pid;
struct io7 *io7;
char *pchar;
do {
pid = simple_strtoul(str, &pchar, 0);
if (pchar != str) {
printk("User-specified IO7 at PID %lu\n", pid);
io7 = alloc_io7(pid);
if (io7) marvel_init_io7(io7);
}
if (pchar == str) pchar++;
str = pchar;
} while(*str);
return 0;
}
__setup("io7=", marvel_specify_io7);
void __init
marvel_init_arch(void)
{
struct io7 *io7;
/* With multiple PCI busses, we play with I/O as physical addrs. */
ioport_resource.end = ~0UL;
iomem_resource.end = ~0UL;
/* PCI DMA Direct Mapping is 1GB at 2GB */
__direct_map_base = 0x80000000;
__direct_map_size = 0x40000000;
/* parse the config tree */
gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
/* init the io7s */
for(io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); )
marvel_init_io7(io7);
/* Check for graphic console location (if any) */
marvel_init_vga_hose();
}
void
marvel_kill_arch(int mode)
{
}
/*
* PCI Configuration Space access functions
*
* Configuration space addresses have the following format:
*
* |2 2 2 2|1 1 1 1|1 1 1 1|1 1
* |3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* n:24 reserved for hose base
* 23:16 bus number (8 bits = 128 possible buses)
* 15:11 Device number (5 bits)
* 10:8 function number
* 7:2 register number
*
* Notes:
* IO7 determines whether to use a type 0 or type 1 config cycle
* based on the bus number. Therefore the bus number must be set
* to 0 for the root bus on any hose.
*
* The function number selects which function of a multi-function device
* (e.g., SCSI and Ethernet).
*
*/
static inline unsigned long
build_conf_addr(struct pci_controller *hose, u8 bus,
unsigned int devfn, int where)
{
return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
}
static unsigned long
mk_conf_addr(struct pci_bus *pbus, unsigned int devfn, int where)
{
struct pci_controller *hose = pbus->sysdata;
struct io7_port *io7_port;
unsigned long addr = 0;
u8 bus = pbus->number;
if (!hose)
return addr;
/* check for enabled... */
io7_port = hose->sysdata;
if (!io7_port->enabled)
return addr;
if (hose->first_busno == bus) {
/* don't support idsel > 20 on primary bus */
if (devfn >= PCI_DEVFN(21, 0)) return addr;
bus = 0;
}
addr = build_conf_addr(hose, bus, devfn, where);
DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
return addr;
}
static int
marvel_read_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *value)
{
unsigned long addr;
if (0 == (addr = mk_conf_addr(bus, devfn, where)))
return PCIBIOS_DEVICE_NOT_FOUND;
switch(size) {
case 1:
*value = __kernel_ldbu(*(vucp)addr);
break;
case 2:
*value = __kernel_ldwu(*(vusp)addr);
break;
case 4:
*value = *(vuip)addr;
break;
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
return PCIBIOS_SUCCESSFUL;
}
static int
marvel_write_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 value)
{
unsigned long addr;
if (0 == (addr = mk_conf_addr(bus, devfn, where)))
return PCIBIOS_DEVICE_NOT_FOUND;
switch (size) {
case 1:
__kernel_stb(value, *(vucp)addr);
mb();
__kernel_ldbu(*(vucp)addr);
break;
case 2:
__kernel_stw(value, *(vusp)addr);
mb();
__kernel_ldwu(*(vusp)addr);
break;
case 4:
*(vuip)addr = value;
mb();
*(vuip)addr;
break;
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops marvel_pci_ops =
{
.read = marvel_read_config,
.write = marvel_write_config,
};
/*
* Other PCI helper functions
*/
void
marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
{
io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
wmb();
csrs->POx_SG_TBIA.csr = 0;
mb();
csrs->POx_SG_TBIA.csr;
}
/*
* IO map support
*/
unsigned long
marvel_ioremap(unsigned long addr, unsigned long size)
{
extern struct pci_controller *hose_head;
struct pci_controller *hose;
unsigned long baddr, last;
struct vm_struct *area;
unsigned long vaddr;
unsigned long *ptes;
unsigned long pfn;
/*
* Adjust the addr
*/
#ifdef CONFIG_VGA_HOSE
if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
addr += pci_vga_hose->mem_space->start;
}
#endif
if (!marvel_is_ioaddr(addr)) return 0UL;
/*
* Find the hose
*/
for(hose = hose_head; hose; hose = hose->next) {
if ((addr >> 32) == (hose->mem_space->start >> 32)) break;
}
if (!hose) return 0UL;
/*
* We have the hose - calculate the bus limits
*/
baddr = addr - hose->mem_space->start;
last = baddr + size - 1;
/*
* Is it direct-mapped?
*/
if ((baddr >= __direct_map_base) &&
((baddr + size - 1) < __direct_map_base + __direct_map_size))
return IDENT_ADDR | (baddr - __direct_map_base);
/*
* Check the scatter-gather arena...
*/
if (hose->sg_pci &&
baddr >= (unsigned long)hose->sg_pci->dma_base &&
last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
/*
* Adjust the limits (mappings must be page aligned)
*/
baddr -= hose->sg_pci->dma_base;
last -= hose->sg_pci->dma_base;
baddr &= PAGE_MASK;
size = PAGE_ALIGN(last) - baddr;
/*
* Map it
*/
area = get_vm_area(size, VM_IOREMAP);
if (!area) return (unsigned long)NULL;
ptes = hose->sg_pci->ptes;
for(vaddr = (unsigned long)area->addr;
baddr <= last;
baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
pfn = ptes[baddr >> PAGE_SHIFT];
if (!(pfn & 1)) {
printk("ioremap failed... pte not valid...\n");
vfree(area->addr);
return 0UL;
}
pfn >>= 1; /* make it a true pfn */
if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr),
pfn << PAGE_SHIFT,
PAGE_SIZE, 0)) {
printk("FAILED to map...\n");
vfree(area->addr);
return 0UL;
}
}
flush_tlb_all();
vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
return vaddr;
}
/*
* Not found - assume legacy ioremap
*/
return addr;
}
void
marvel_iounmap(unsigned long addr)
{
if (((long)addr >> 41) == -2)
return; /* kseg map, nothing to do */
if (addr) return vfree((void *)(PAGE_MASK & addr));
}
/*
* SRMCons support
*
* Marvel doesn't have a real serial console -- it's either graphics or
* server management based. If we're running on the server management based
* console, allow the srmcons callback driver to be a console device
*/
int marvel_srmcons_allowed(void)
{
u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
if (pu64[7] == 2) return 1;
return 0;
}
/*
* RTC Support
*/
struct marvel_rtc_access_info {
unsigned long function;
unsigned long index;
unsigned long data;
};
static void __marvel_access_rtc(void *info)
{
struct marvel_rtc_access_info *rtc_access = info;
register unsigned long __r0 __asm__("$0");
register unsigned long __r16 __asm__("$16") = rtc_access->function;
register unsigned long __r17 __asm__("$17") = rtc_access->index;
register unsigned long __r18 __asm__("$18") = rtc_access->data;
__asm__ __volatile__(
"call_pal %4 # cserve rtc"
: "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
: "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
: "$1", "$22", "$23", "$24", "$25");
rtc_access->data = __r0;
}
u8 __marvel_rtc_io(int write, u8 b, unsigned long addr)
{
struct marvel_rtc_access_info rtc_access = {0, };
static u8 index = 0;
u8 ret = 0;
switch(addr) {
case 0x70: /* RTC_PORT(0) */
if (write) index = b;
ret = index;
break;
case 0x71: /* RTC_PORT(1) */
rtc_access.index = index;
rtc_access.data = BCD_TO_BIN(b);
rtc_access.function = 0x49; /* GET_TOY */
if (write) rtc_access.function = 0x48; /* PUT_TOY */
#if CONFIG_SMP
if (smp_processor_id() != boot_cpuid)
smp_call_function_on_cpu(__marvel_access_rtc,
&rtc_access,
1, /* retry */
1, /* wait */
1UL << boot_cpuid);
else
__marvel_access_rtc(&rtc_access);
#else
__marvel_access_rtc(&rtc_access);
#endif
ret = BIN_TO_BCD(rtc_access.data);
break;
default:
printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
break;
}
return ret;
}
/*
* NUMA Support
*/
/**********
* FIXME - for now each cpu is a node by itself
* -- no real support for striped mode
**********
*/
int marvel_pa_to_nid(unsigned long pa)
{
int cpuid;
if ((pa >> 43) & 1) /* I/O */
cpuid = (~(pa >> 35) & 0xff);
else /* mem */
cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
return marvel_cpuid_to_nid(cpuid);
}
int marvel_cpuid_to_nid(int cpuid)
{
return cpuid;
}
unsigned long marvel_node_mem_start(int nid)
{
unsigned long pa;
pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
pa <<= 34;
return pa;
}
unsigned long marvel_node_mem_size(int nid)
{
return 16UL * 1024 * 1024 * 1024; /* 16GB */
}
/*
* AGP GART Support
*/
#include <linux/agp_backend.h>
#include <asm/agp_backend.h>
#include <linux/slab.h>
#include <linux/delay.h>
#define MARVEL_AGP_APER_SIZE (64 * 1024 * 1024)
struct marvel_agp_aperture {
struct pci_iommu_arena *arena;
long pg_start;
long pg_count;
};
static int marvel_agp_setup(alpha_agp_info *agp)
{
struct marvel_agp_aperture *aper;
aper = kmalloc(sizeof(*aper), GFP_KERNEL);
if (aper == NULL) return -ENOMEM;
aper->arena = agp->hose->sg_pci;
aper->pg_count = MARVEL_AGP_APER_SIZE / PAGE_SIZE;
aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
aper->pg_count - 1);
if (aper->pg_start < 0) {
printk(KERN_ERR "Failed to reserve AGP memory\n");
kfree(aper);
return -ENOMEM;
}
agp->aperture.bus_base =
aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
agp->aperture.size = aper->pg_count * PAGE_SIZE;
agp->aperture.sysdata = aper;
return 0;
}
static void marvel_agp_cleanup(alpha_agp_info *agp)
{
struct marvel_agp_aperture *aper = agp->aperture.sysdata;
int status;
status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
if (status == -EBUSY) {
printk(KERN_WARNING
"Attempted to release bound AGP memory - unbinding\n");
iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
status = iommu_release(aper->arena, aper->pg_start,
aper->pg_count);
}
if (status < 0) printk(KERN_ERR "Failed to release AGP memory\n");
kfree(aper);
kfree(agp);
}
static int marvel_agp_configure(alpha_agp_info *agp)
{
io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
unsigned int new_rate = 0;
unsigned long agp_pll;
/*
* Check the requested mode against the PLL setting.
* The agpgart_be code has not programmed the card yet, so we can
* still tweak mode here
*/
agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
switch(IO7_PLL_RNGB(agp_pll)) {
case 0x4: /* 2x only */
/*
* The PLL is only programmed for 2x, so adjust the
* rate to 2x, if necessary
*/
if (agp->mode.bits.rate != 2)
new_rate = 2;
break;
case 0x6: /* 1x / 4x */
/*
* The PLL is programmed for 1x or 4x. Don't go faster
* than requested, so if the requested rate is 2x, use 1x
*/
if (agp->mode.bits.rate == 2)
new_rate = 1;
break;
default: /* ??????? */
/*
* Don't know what this PLL setting is, take the requested
* rate, but warn the user
*/
printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
__FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
break;
}
/*
* Set the new rate, if necessary
*/
if (new_rate) {
printk("Requested AGP Rate %dX not compatible "
"with PLL setting - using %dX\n",
agp->mode.bits.rate,
new_rate);
agp->mode.bits.rate = new_rate;
}
printk("Enabling AGP on hose %d: %dX%s RQ %d\n",
agp->hose->index, agp->mode.bits.rate,
agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
csrs->AGP_CMD.csr = agp->mode.lw;
return 0;
}
static int
marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
{
struct marvel_agp_aperture *aper = agp->aperture.sysdata;
return iommu_bind(aper->arena, aper->pg_start + pg_start,
mem->page_count, mem->memory);
}
static int
marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
{
struct marvel_agp_aperture *aper = agp->aperture.sysdata;
return iommu_unbind(aper->arena, aper->pg_start + pg_start,
mem->page_count);
}
static unsigned long
marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
{
struct marvel_agp_aperture *aper = agp->aperture.sysdata;
unsigned long baddr = addr - aper->arena->dma_base;
unsigned long pte;
if (addr < agp->aperture.bus_base ||
addr >= agp->aperture.bus_base + agp->aperture.size) {
printk("%s: addr out of range\n", __FUNCTION__);
return -EINVAL;
}
pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
if (!(pte & 1)) {
printk("%s: pte not valid\n", __FUNCTION__);
return -EINVAL;
}
return (pte >> 1) << PAGE_SHIFT;
}
struct alpha_agp_ops marvel_agp_ops =
{
.setup = marvel_agp_setup,
.cleanup = marvel_agp_cleanup,
.configure = marvel_agp_configure,
.bind = marvel_agp_bind_memory,
.unbind = marvel_agp_unbind_memory,
.translate = marvel_agp_translate
};
alpha_agp_info *
marvel_agp_info(void)
{
struct pci_controller *hose;
io7_ioport_csrs *csrs;
alpha_agp_info *agp;
struct io7 *io7;
/*
* Find the first IO7 with an AGP card
*
* FIXME -- there should be a better way (we want to be able to
* specify and what if the agp card is not video???)
*/
hose = NULL;
for(io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
struct pci_controller *h;
vuip addr;
if (!io7->ports[IO7_AGP_PORT].enabled)
continue;
h = io7->ports[IO7_AGP_PORT].hose;
addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
if (*addr != 0xffffffffu) {
hose = h;
break;
}
}
printk("MARVEL - using hose %d as AGP\n", hose->index);
if (!hose || !hose->sg_pci) return NULL;
/*
* Get the csrs from the hose
*/
csrs = ((struct io7_port *)hose->sysdata)->csrs;
/*
* Allocate the info structure
*/
agp = kmalloc(sizeof(*agp), GFP_KERNEL);
/*
* Fill it in
*/
agp->type = ALPHA_CORE_AGP;
agp->hose = hose;
agp->private = NULL;
agp->ops = &marvel_agp_ops;
/*
* Aperture - not configured until ops.setup()
*/
agp->aperture.bus_base = 0;
agp->aperture.size = 0;
agp->aperture.sysdata = NULL;
/*
* Capabilities
*
* NOTE: IO7 reports through AGP_STAT that it can support a read queue
* depth of 17 (rq = 0x10). It actually only supports a depth of
* 16 (rq = 0xf).
*/
agp->capability.lw = csrs->AGP_STAT.csr;
agp->capability.bits.rq = 0xf;
/*
* Mode
*/
agp->mode.lw = csrs->AGP_CMD.csr;
return agp;
}
...@@ -146,6 +146,12 @@ extern void cdl_check_console_data_log(void); ...@@ -146,6 +146,12 @@ extern void cdl_check_console_data_log(void);
extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *); extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
extern int cdl_register_subpacket_handler(struct el_subpacket_handler *); extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
/*
* err_marvel.c
*/
extern void marvel_machine_check(u64, u64, struct pt_regs *);
extern void marvel_register_error_handlers(void);
/* /*
* err_titan.c * err_titan.c
*/ */
......
/*
* linux/arch/alpha/kernel/err_marvel.c
*
* Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
*
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/console.h>
#include <asm/core_marvel.h>
#include <asm/hwrpb.h>
#include <asm/smp.h>
#include "err_impl.h"
#include "proto.h"
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL)
void
marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
{
struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
/*
* Sync the processor
*/
mb();
draina();
srm_printk("MARVEL MACHINE CHECK!!!\n"); /* HACK */
el_process_subpacket(el_ptr);
srm_printk("...PROCESSED\n"); /* HACK */
switch(vector) {
case SCB_Q_SYSEVENT:
printk(KERN_CRIT "MARVEL SYSEVENT %ld\n", vector);
break;
case SCB_Q_SYSMCHK:
case SCB_Q_SYSERR:
printk(KERN_CRIT "MARVEL SYSMCHK/ERR %ld\n", vector);
break;
default: /* don't know it - pass it up */
return ev7_machine_check(vector, la_ptr, regs);
}
/*
* Release the logout frame
*/
wrmces(0x7);
mb();
}
void
marvel_register_error_handlers(void)
{
ev7_register_error_handlers();
}
#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_MARVEL */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <asm/hwrpb.h>
#include <asm/gct.h>
int
gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
{
gct6_search_struct *wanted;
int status = 0;
/* first check the magic number */
if (node->magic != GCT_NODE_MAGIC) {
printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
return -EINVAL;
}
/* check against the search struct */
for(wanted = search;
wanted && (wanted->type | wanted->subtype);
wanted++) {
if (node->type != wanted->type) continue;
if (node->subtype != wanted->subtype) continue;
/* found it -- call out */
if (wanted->callout) wanted->callout(node);
}
/* now walk the tree, siblings first.. */
if (node->next)
status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);
/* then the children */
if (node->child)
status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);
return status;
}
...@@ -9,10 +9,12 @@ ...@@ -9,10 +9,12 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
/* Whee. IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE. /* Whee. These systems don't have an HAE:
IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
Fix things up for the GENERIC kernel by defining the HAE address Fix things up for the GENERIC kernel by defining the HAE address
to be that of the cache. Now we can read and write it as we like. ;-) */ to be that of the cache. Now we can read and write it as we like. ;-) */
#define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache) #define IRONGATE_HAE_ADDRESS (&alpha_mv.hae_cache)
#define MARVEL_HAE_ADDRESS (&alpha_mv.hae_cache)
#define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache) #define POLARIS_HAE_ADDRESS (&alpha_mv.hae_cache)
#define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache) #define TSUNAMI_HAE_ADDRESS (&alpha_mv.hae_cache)
#define TITAN_HAE_ADDRESS (&alpha_mv.hae_cache) #define TITAN_HAE_ADDRESS (&alpha_mv.hae_cache)
...@@ -32,7 +34,6 @@ ...@@ -32,7 +34,6 @@
#define T2_IACK_SC 1 #define T2_IACK_SC 1
#define WILDFIRE_IACK_SC 1 /* FIXME */ #define WILDFIRE_IACK_SC 1 /* FIXME */
/* /*
* Some helpful macros for filling in the blanks. * Some helpful macros for filling in the blanks.
*/ */
...@@ -63,6 +64,13 @@ ...@@ -63,6 +64,13 @@
mv_flush_tlb_current: ev5_flush_tlb_current, \ mv_flush_tlb_current: ev5_flush_tlb_current, \
mv_flush_tlb_current_page: ev5_flush_tlb_current_page mv_flush_tlb_current_page: ev5_flush_tlb_current_page
#define DO_EV7_MMU \
max_asn: EV6_MAX_ASN, \
mv_switch_mm: ev5_switch_mm, \
mv_activate_mm: ev5_activate_mm, \
mv_flush_tlb_current: ev5_flush_tlb_current, \
mv_flush_tlb_current_page: ev5_flush_tlb_current_page
#define IO_LITE(UP,low) \ #define IO_LITE(UP,low) \
hae_register: (unsigned long *) CAT(UP,_HAE_ADDRESS), \ hae_register: (unsigned long *) CAT(UP,_HAE_ADDRESS), \
iack_sc: CAT(UP,_IACK_SC), \ iack_sc: CAT(UP,_IACK_SC), \
...@@ -91,6 +99,7 @@ ...@@ -91,6 +99,7 @@
#define DO_CIA_IO IO(CIA,cia) #define DO_CIA_IO IO(CIA,cia)
#define DO_IRONGATE_IO IO(IRONGATE,irongate) #define DO_IRONGATE_IO IO(IRONGATE,irongate)
#define DO_LCA_IO IO(LCA,lca) #define DO_LCA_IO IO(LCA,lca)
#define DO_MARVEL_IO IO(MARVEL,marvel)
#define DO_MCPCIA_IO IO(MCPCIA,mcpcia) #define DO_MCPCIA_IO IO(MCPCIA,mcpcia)
#define DO_POLARIS_IO IO(POLARIS,polaris) #define DO_POLARIS_IO IO(POLARIS,polaris)
#define DO_T2_IO IO(T2,t2) #define DO_T2_IO IO(T2,t2)
...@@ -109,6 +118,7 @@ ...@@ -109,6 +118,7 @@
#define DO_CIA_BUS BUS(cia) #define DO_CIA_BUS BUS(cia)
#define DO_IRONGATE_BUS BUS(irongate) #define DO_IRONGATE_BUS BUS(irongate)
#define DO_LCA_BUS BUS(lca) #define DO_LCA_BUS BUS(lca)
#define DO_MARVEL_BUS BUS(marvel)
#define DO_MCPCIA_BUS BUS(mcpcia) #define DO_MCPCIA_BUS BUS(mcpcia)
#define DO_POLARIS_BUS BUS(polaris) #define DO_POLARIS_BUS BUS(polaris)
#define DO_T2_BUS BUS(t2) #define DO_T2_BUS BUS(t2)
...@@ -116,7 +126,6 @@ ...@@ -116,7 +126,6 @@
#define DO_TITAN_BUS BUS(titan) #define DO_TITAN_BUS BUS(titan)
#define DO_WILDFIRE_BUS BUS(wildfire) #define DO_WILDFIRE_BUS BUS(wildfire)
/* /*
* In a GENERIC kernel, we have lots of these vectors floating about, * In a GENERIC kernel, we have lots of these vectors floating about,
* all but one of which we want to go away. In a non-GENERIC kernel, * all but one of which we want to go away. In a non-GENERIC kernel,
......
...@@ -41,6 +41,18 @@ extern void lca_init_arch(void); ...@@ -41,6 +41,18 @@ extern void lca_init_arch(void);
extern void lca_machine_check(u64, u64, struct pt_regs *); extern void lca_machine_check(u64, u64, struct pt_regs *);
extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_marvel.c */
extern struct pci_ops marvel_pci_ops;
extern void marvel_init_arch(void);
extern void marvel_kill_arch(int);
extern void marvel_machine_check(u64, u64, struct pt_regs *);
extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
extern int marvel_pa_to_nid(unsigned long);
extern int marvel_cpuid_to_nid(int);
extern unsigned long marvel_node_mem_start(int);
extern unsigned long marvel_node_mem_size(int);
extern int marvel_srmcons_allowed(void);
/* core_mcpcia.c */ /* core_mcpcia.c */
extern struct pci_ops mcpcia_pci_ops; extern struct pci_ops mcpcia_pci_ops;
extern void mcpcia_init_arch(void); extern void mcpcia_init_arch(void);
......
...@@ -155,6 +155,7 @@ WEAK(eb66p_mv); ...@@ -155,6 +155,7 @@ WEAK(eb66p_mv);
WEAK(eiger_mv); WEAK(eiger_mv);
WEAK(jensen_mv); WEAK(jensen_mv);
WEAK(lx164_mv); WEAK(lx164_mv);
WEAK(marvel_ev7_mv);
WEAK(miata_mv); WEAK(miata_mv);
WEAK(mikasa_mv); WEAK(mikasa_mv);
WEAK(mikasa_primo_mv); WEAK(mikasa_primo_mv);
...@@ -696,7 +697,7 @@ static char systype_names[][16] = { ...@@ -696,7 +697,7 @@ static char systype_names[][16] = {
"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
"Cortex", "29", "Miata", "XXM", "Takara", "Yukon", "Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan" "Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel"
}; };
static char unofficial_names[][8] = {"100", "Ruffian"}; static char unofficial_names[][8] = {"100", "Ruffian"};
...@@ -715,6 +716,11 @@ static int eb64p_indices[] = {0,0,1,2}; ...@@ -715,6 +716,11 @@ static int eb64p_indices[] = {0,0,1,2};
static char eb66_names[][8] = {"EB66", "EB66+"}; static char eb66_names[][8] = {"EB66", "EB66+"};
static int eb66_indices[] = {0,0,1}; static int eb66_indices[] = {0,0,1};
static char marvel_names[][16] = {
"Marvel/EV7"
};
static int marvel_indices[] = { 0 };
static char rawhide_names[][16] = { static char rawhide_names[][16] = {
"Dodge", "Wrangler", "Durango", "Tincup", "DaVinci" "Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
}; };
...@@ -776,6 +782,7 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu) ...@@ -776,6 +782,7 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
NULL, /* CUSCO */ NULL, /* CUSCO */
&eiger_mv, /* Eiger */ &eiger_mv, /* Eiger */
NULL, /* Titan */ NULL, /* Titan */
NULL, /* Marvel */
}; };
static struct alpha_machine_vector *unofficial_vecs[] __initdata = static struct alpha_machine_vector *unofficial_vecs[] __initdata =
...@@ -813,6 +820,11 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu) ...@@ -813,6 +820,11 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
&eb66p_mv &eb66p_mv
}; };
static struct alpha_machine_vector *marvel_vecs[] __initdata =
{
&marvel_ev7_mv,
};
static struct alpha_machine_vector *titan_vecs[] __initdata = static struct alpha_machine_vector *titan_vecs[] __initdata =
{ {
&titan_mv, /* default */ &titan_mv, /* default */
...@@ -883,6 +895,10 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu) ...@@ -883,6 +895,10 @@ get_sysvec(unsigned long type, unsigned long variation, unsigned long cpu)
if (member < N(eb66_indices)) if (member < N(eb66_indices))
vec = eb66_vecs[eb66_indices[member]]; vec = eb66_vecs[eb66_indices[member]];
break; break;
case ST_DEC_MARVEL:
if (member < N(marvel_indices))
vec = marvel_vecs[marvel_indices[member]];
break;
case ST_DEC_TITAN: case ST_DEC_TITAN:
vec = titan_vecs[0]; /* default */ vec = titan_vecs[0]; /* default */
if (member < N(titan_indices)) if (member < N(titan_indices))
...@@ -1023,6 +1039,10 @@ get_sysnames(unsigned long type, unsigned long variation, unsigned long cpu, ...@@ -1023,6 +1039,10 @@ get_sysnames(unsigned long type, unsigned long variation, unsigned long cpu,
if (member < N(eb66_indices)) if (member < N(eb66_indices))
*variation_name = eb66_names[eb66_indices[member]]; *variation_name = eb66_names[eb66_indices[member]];
break; break;
case ST_DEC_MARVEL:
if (member < N(marvel_indices))
*variation_name = marvel_names[marvel_indices[member]];
break;
case ST_DEC_RAWHIDE: case ST_DEC_RAWHIDE:
if (member < N(rawhide_indices)) if (member < N(rawhide_indices))
*variation_name = rawhide_names[rawhide_indices[member]]; *variation_name = rawhide_names[rawhide_indices[member]];
......
/*
* linux/arch/alpha/kernel/sys_io7.c
*
* Marvel / IO7 support
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/core_marvel.h>
#include <asm/hwrpb.h>
#include <asm/tlbflush.h>
#include "proto.h"
#include "err_impl.h"
#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"
/*
* private functions in core_marvel.c
*/
struct io7 *marvel_find_io7(int pe);
struct io7 *marvel_next_io7(struct io7 *prev);
void io7_clear_errors(struct io7 *io7);
/*
* Interrupt handling
*/
#define IRQ_VEC_PE_SHIFT (10)
#define IRQ_VEC_IRQ_MASK ((1 << IRQ_VEC_PE_SHIFT) - 1)
static void
io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
{
unsigned int pid;
unsigned int irq;
/*
* Vector is 0x800 + (interrupt)
*
* where (interrupt) is:
*
* ...16|15 14|13 4|3 0
* -----+-----+--------+---
* PE | 0 | irq | 0
*
* where (irq) is
*
* 0x0800 - 0x0ff0 - 0x0800 + (LSI id << 4)
* 0x1000 - 0x2ff0 - 0x1000 + (MSI_DAT<8:0> << 4)
*/
pid = vector >> 16;
irq = ((vector & 0xffff) - 0x800) >> 4;
irq += 16; /* offset for legacy */
irq &= IRQ_VEC_IRQ_MASK; /* not too many bits */
irq |= pid << IRQ_VEC_PE_SHIFT; /* merge the pid */
handle_irq(irq, regs);
}
static volatile unsigned long *
io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
{
volatile unsigned long *ctl;
unsigned int pid;
struct io7 *io7;
pid = irq >> IRQ_VEC_PE_SHIFT;
if (!(io7 = marvel_find_io7(pid))) {
printk(KERN_ERR
"%s for nonexistent io7 -- vec %x, pid %d\n",
__FUNCTION__, irq, pid);
return NULL;
}
irq &= IRQ_VEC_IRQ_MASK; /* isolate the vector */
irq -= 16; /* subtract legacy bias */
if (irq >= 0x180) {
printk(KERN_ERR
"%s for invalid irq -- pid %d adjusted irq %x\n",
__FUNCTION__, pid, irq);
return NULL;
}
ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
if (irq >= 0x80) /* MSI */
ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
if (pio7) *pio7 = io7;
return ctl;
}
static void
io7_enable_irq(unsigned int irq)
{
volatile unsigned long *ctl;
struct io7 *io7;
ctl = io7_get_irq_ctl(irq, &io7);
if (!ctl || !io7) {
printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
__FUNCTION__, irq);
return;
}
spin_lock(&io7->irq_lock);
*ctl |= 1UL << 24;
mb();
*ctl;
spin_unlock(&io7->irq_lock);
}
static void
io7_disable_irq(unsigned int irq)
{
volatile unsigned long *ctl;
struct io7 *io7;
ctl = io7_get_irq_ctl(irq, &io7);
if (!ctl || !io7) {
printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
__FUNCTION__, irq);
return;
}
spin_lock(&io7->irq_lock);
*ctl &= ~(1UL << 24);
mb();
*ctl;
spin_unlock(&io7->irq_lock);
}
static unsigned int
io7_startup_irq(unsigned int irq)
{
io7_enable_irq(irq);
return 0; /* never anything pending */
}
static void
io7_end_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
io7_enable_irq(irq);
}
static void marvel_irq_noop(unsigned int irq)
{
return;
}
static unsigned int marvel_irq_noop_return(unsigned int irq)
{
return 0;
}
static struct hw_interrupt_type marvel_legacy_irq_type = {
.typename = "LEGACY",
.startup = marvel_irq_noop_return,
.shutdown = marvel_irq_noop,
.enable = marvel_irq_noop,
.disable = marvel_irq_noop,
.ack = marvel_irq_noop,
.end = marvel_irq_noop,
};
static struct hw_interrupt_type io7_lsi_irq_type = {
.typename = "LSI",
.startup = io7_startup_irq,
.shutdown = io7_disable_irq,
.enable = io7_enable_irq,
.disable = io7_disable_irq,
.ack = io7_disable_irq,
.end = io7_end_irq,
};
static struct hw_interrupt_type io7_msi_irq_type = {
.typename = "MSI",
.startup = io7_startup_irq,
.shutdown = io7_disable_irq,
.enable = io7_enable_irq,
.disable = io7_disable_irq,
.ack = marvel_irq_noop,
.end = io7_end_irq,
};
static void
io7_redirect_irq(struct io7 *io7,
volatile unsigned long *csr,
unsigned int where)
{
unsigned long val;
val = *csr;
val &= ~(0x1ffUL << 24); /* clear the target pid */
val |= ((unsigned long)where << 24); /* set the new target pid */
*csr = val;
mb();
*csr;
}
static void
io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
{
unsigned long val;
/*
* LSI_CTL has target PID @ 14
*/
val = io7->csrs->PO7_LSI_CTL[which].csr;
val &= ~(0x1ffUL << 14); /* clear the target pid */
val |= ((unsigned long)where << 14); /* set teh new target pid */
io7->csrs->PO7_LSI_CTL[which].csr = val;
mb();
io7->csrs->PO7_LSI_CTL[which].csr;
}
static void
io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
{
unsigned long val;
/*
* MSI_CTL has target PID @ 14
*/
val = io7->csrs->PO7_MSI_CTL[which].csr;
val &= ~(0x1ffUL << 14); /* clear the target pid */
val |= ((unsigned long)where << 14); /* set teh new target pid */
io7->csrs->PO7_MSI_CTL[which].csr = val;
mb();
io7->csrs->PO7_MSI_CTL[which].csr;
}
static void __init
init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
{
/*
* LSI_CTL has target PID @ 14
*/
io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
mb();
io7->csrs->PO7_LSI_CTL[which].csr;
}
static void __init
init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
{
/*
* MSI_CTL has target PID @ 14
*/
io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
mb();
io7->csrs->PO7_MSI_CTL[which].csr;
}
static void __init
init_io7_irqs(struct io7 *io7,
struct hw_interrupt_type *lsi_ops,
struct hw_interrupt_type *msi_ops)
{
long base = (io7->pe << IRQ_VEC_PE_SHIFT) + 16;
long i;
printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
io7->pe, base);
/*
* Where should interrupts from this IO7 go?
*
* They really should be sent to the local CPU to avoid having to
* traverse the mesh, but if it's not an SMP kernel, they have to
* go to the boot CPU. Send them all to the boot CPU for now,
* as each secondary starts, it can redirect it's local device
* interrupts
*/
printk(" Interrupts reported to CPU at PE %u\n", boot_cpuid);
spin_lock(&io7->irq_lock);
/* set up the error irqs */
io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
/* set up the lsi irqs */
for(i = 0; i < 128; ++i) {
irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[base + i].handler = lsi_ops;
}
/* disable the implemented irqs in hardware */
for(i = 0; i < 0x60; ++i)
init_one_io7_lsi(io7, i, boot_cpuid);
init_one_io7_lsi(io7, 0x74, boot_cpuid);
init_one_io7_lsi(io7, 0x75, boot_cpuid);
/* set up the msi irqs */
for(i = 128; i < (128 + 512); ++i) {
irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
irq_desc[base + i].handler = msi_ops;
}
for(i = 0; i < 16; ++i)
init_one_io7_msi(io7, i, boot_cpuid);
spin_unlock(&io7->irq_lock);
}
static void __init
marvel_init_irq(void)
{
int i;
struct io7 *io7 = NULL;
/* reserve the legacy irqs */
for(i = 0; i < 16; ++i) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].handler = &marvel_legacy_irq_type;
}
/* init the io7 irqs */
for(io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
}
}
static int
marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_controller *hose = dev->sysdata;
struct io7_port *io7_port = hose->sysdata;
struct io7 *io7 = io7_port->io7;
int msi_loc, msi_data_off;
u16 msg_ctl;
u16 msg_dat;
u8 intline;
int irq;
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
irq = intline;
msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
msg_ctl = 0;
if (msi_loc)
pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
msi_data_off = PCI_MSI_DATA_32;
if (msg_ctl & PCI_MSI_FLAGS_64BIT)
msi_data_off = PCI_MSI_DATA_64;
pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
irq = msg_dat & 0x1ff; /* we use msg_data<8:0> */
irq += 0x80; /* offset for lsi */
#if 1
printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
dev->bus->number,
PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn),
hose->index,
dev->dev.name);
printk(" %d message(s) from 0x%04x\n",
1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
msg_dat);
printk(" reporting on %d IRQ(s) from %d (0x%x)\n",
1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
(irq + 16) | (io7->pe << IRQ_VEC_PE_SHIFT),
(irq + 16) | (io7->pe << IRQ_VEC_PE_SHIFT));
#endif
#if 0
pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
irq = intline;
printk(" forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
#endif
}
irq += 16; /* offset for legacy */
irq |= io7->pe << IRQ_VEC_PE_SHIFT; /* merge the pid */
return irq;
}
static void __init
marvel_init_pci(void)
{
extern int pci_probe_only;
struct io7 *io7;
marvel_register_error_handlers();
pci_probe_only = 1;
common_init_pci();
#ifdef CONFIG_VGA_HOSE
locate_and_init_vga(NULL);
#endif
/* clear any io7 errors */
for(io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
io7_clear_errors(io7);
}
static void
marvel_init_rtc(void)
{
init_rtc_irq();
}
static void
marvel_smp_callin(void)
{
int cpuid = hard_smp_processor_id();
struct io7 *io7 = marvel_find_io7(cpuid);
unsigned int i;
if (io7) {
/*
* There is a local IO7 - redirect all of it's interrupts here
*/
printk("Redirecting IO7 interrupts to local CPU at PE %u\n",
cpuid);
/* redirect the error IRQS here */
io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
/* redirect the implemented LSIs here */
for(i = 0; i < 0x60; ++i)
io7_redirect_one_lsi(io7, i, cpuid);
io7_redirect_one_lsi(io7, 0x74, cpuid);
io7_redirect_one_lsi(io7, 0x75, cpuid);
/* redirect the MSIs here */
for(i = 0; i < 16; ++i)
io7_redirect_one_msi(io7, i, cpuid);
}
}
/*
* System Vectors
*/
extern void *marvel_agp_info(void);
struct alpha_machine_vector marvel_ev7_mv __initmv = {
.vector_name = "MARVEL/EV7",
DO_EV7_MMU,
DO_DEFAULT_RTC,
DO_MARVEL_IO,
DO_MARVEL_BUS,
.machine_check = marvel_machine_check,
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
.min_io_address = DEFAULT_IO_BASE,
.min_mem_address = DEFAULT_MEM_BASE,
.pci_dac_offset = IO7_DAC_OFFSET,
.nr_irqs = MARVEL_NR_IRQS,
.device_interrupt = io7_device_interrupt,
.agp_info = marvel_agp_info,
.srmcons_allowed = marvel_srmcons_allowed,
.smp_callin = marvel_smp_callin,
.init_arch = marvel_init_arch,
.init_irq = marvel_init_irq,
.init_rtc = marvel_init_rtc,
.init_pci = marvel_init_pci,
.kill_arch = marvel_kill_arch,
.pci_map_irq = marvel_map_irq,
.pci_swizzle = common_swizzle,
.pa_to_nid = marvel_pa_to_nid,
.cpuid_to_nid = marvel_cpuid_to_nid,
.node_mem_start = marvel_node_mem_start,
.node_mem_size = marvel_node_mem_size,
};
ALIAS_MV(marvel_ev7)
/*
* Marvel systems use the IO7 I/O chip provides PCI/PCIX/AGP access
*
* This file is based on:
*
* Marvel / EV7 System Programmer's Manual
* Revision 1.00
* 14 May 2001
*/
#ifndef __ALPHA_MARVEL__H__
#define __ALPHA_MARVEL__H__
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <asm/compiler.h>
#define MARVEL_MAX_PIDS 128
#define MARVEL_MAX_LSIS_PER_PID 256
#define MARVEL_NR_IRQS (MARVEL_MAX_PIDS * MARVEL_MAX_LSIS_PER_PID)
/*
* EV7 RBOX Registers
*/
typedef struct {
volatile unsigned long csr __attribute__((aligned(16)));
} ev7_csr;
typedef struct {
ev7_csr RBOX_CFG; /* 0x0000 */
ev7_csr RBOX_NSVC;
ev7_csr RBOX_EWVC;
ev7_csr RBOX_WHAMI;
ev7_csr RBOX_TCTL; /* 0x0040 */
ev7_csr RBOX_INT;
ev7_csr RBOX_IMASK;
ev7_csr RBOX_IREQ;
ev7_csr RBOX_INTQ; /* 0x0080 */
ev7_csr RBOX_INTA;
ev7_csr RBOX_IT;
ev7_csr RBOX_SCRATCH1;
ev7_csr RBOX_SCRATCH2; /* 0x00c0 */
ev7_csr RBOX_L_ERR;
} ev7_csrs;
/*
* EV7 CSR addressing macros
*/
#define EV7_MASK40(addr) ((addr) & ((1UL << 41) - 1))
#define EV7_KERN_ADDR(addr) ((void *)(IDENT_ADDR | EV7_MASK40(addr)))
#define EV7_PE_MASK 0x1ffUL /* 9 bits ( 256 + mem/io ) */
#define EV7_IPE(pe) ((~((long)(pe)) & EV7_PE_MASK) << 35)
#define EV7_CSR_PHYS(pe, off) (EV7_IPE(pe) | (0x7FFCUL << 20) | (off))
#define EV7_CSRS_PHYS(pe) (EV7_CSR_PHYS(pe, 0UL))
#define EV7_CSR_KERN(pe, off) (EV7_KERN_ADDR(EV7_CSR_PHYS(pe, off)))
#define EV7_CSRS_KERN(pe) (EV7_KERN_ADDR(EV7_CSRS_PHYS(pe)))
#define EV7_CSR_OFFSET(name) ((unsigned long)&((ev7_csrs *)NULL)->name.csr)
/*
* IO7 registers
*/
typedef struct {
volatile unsigned long csr __attribute__((aligned(64)));
} io7_csr;
typedef struct {
/* I/O Port Control Registers */
io7_csr POx_CTRL; /* 0x0000 */
io7_csr POx_CACHE_CTL;
io7_csr POx_TIMER;
io7_csr POx_IO_ADR_EXT;
io7_csr POx_MEM_ADR_EXT; /* 0x0100 */
io7_csr POx_XCAL_CTRL;
io7_csr rsvd1[2]; /* ?? spec doesn't show 0x180 */
io7_csr POx_DM_SOURCE; /* ox0200 */
io7_csr POx_DM_DEST;
io7_csr POx_DM_SIZE;
io7_csr POx_DM_STATE;
io7_csr rsvd2[4]; /* 0x0300 */
/* AGP Control Registers -- port 3 only */
io7_csr AGP_CAP_ID; /* 0x0400 */
io7_csr AGP_STAT;
io7_csr AGP_CMD;
io7_csr rsvd3;
/* I/O Port Monitor Registers */
io7_csr POx_MONCTL; /* 0x0500 */
io7_csr POx_CTRA;
io7_csr POx_CTRB;
io7_csr POx_CTR56;
io7_csr POx_SCRATCH; /* 0x0600 */
io7_csr POx_XTRA_A;
io7_csr POx_XTRA_TS;
io7_csr POx_XTRA_Z;
io7_csr rsvd4; /* 0x0700 */
io7_csr POx_THRESHA;
io7_csr POx_THRESHB;
io7_csr rsvd5[33];
/* System Address Space Window Control Registers */
io7_csr POx_WBASE[4]; /* 0x1000 */
io7_csr POx_WMASK[4];
io7_csr POx_TBASE[4];
io7_csr POx_SG_TBIA;
io7_csr POx_MSI_WBASE;
io7_csr rsvd6[50];
/* I/O Port Error Registers */
io7_csr POx_ERR_SUM;
io7_csr POx_FIRST_ERR;
io7_csr POx_MSK_HEI;
io7_csr POx_TLB_ERR;
io7_csr POx_SPL_COMPLT;
io7_csr POx_TRANS_SUM;
io7_csr POx_FRC_PCI_ERR;
io7_csr POx_MULT_ERR;
io7_csr rsvd7[8];
/* I/O Port End of Interrupt Registers */
io7_csr EOI_DAT;
io7_csr rsvd8[7];
io7_csr POx_IACK_SPECIAL;
io7_csr rsvd9[103];
} io7_ioport_csrs;
typedef struct {
io7_csr IO_ASIC_REV; /* 0x30.0000 */
io7_csr IO_SYS_REV;
io7_csr SER_CHAIN3;
io7_csr PO7_RST1;
io7_csr PO7_RST2; /* 0x30.0100 */
io7_csr POx_RST[4];
io7_csr IO7_DWNH;
io7_csr IO7_MAF;
io7_csr IO7_MAF_TO;
io7_csr IO7_ACC_CLUMP; /* 0x30.0300 */
io7_csr IO7_PMASK;
io7_csr IO7_IOMASK;
io7_csr IO7_UPH;
io7_csr IO7_UPH_TO; /* 0x30.0400 */
io7_csr RBX_IREQ_OFF;
io7_csr RBX_INTA_OFF;
io7_csr INT_RTY;
io7_csr PO7_MONCTL; /* 0x30.0500 */
io7_csr PO7_CTRA;
io7_csr PO7_CTRB;
io7_csr PO7_CTR56;
io7_csr PO7_SCRATCH; /* 0x30.0600 */
io7_csr PO7_XTRA_A;
io7_csr PO7_XTRA_TS;
io7_csr PO7_XTRA_Z;
io7_csr PO7_PMASK; /* 0x30.0700 */
io7_csr PO7_THRESHA;
io7_csr PO7_THRESHB;
io7_csr rsvd1[97];
io7_csr PO7_ERROR_SUM; /* 0x30.2000 */
io7_csr PO7_BHOLE_MASK;
io7_csr PO7_HEI_MSK;
io7_csr PO7_CRD_MSK;
io7_csr PO7_UNCRR_SYM; /* 0x30.2100 */
io7_csr PO7_CRRCT_SYM;
io7_csr PO7_ERR_PKT[2];
io7_csr PO7_UGBGE_SYM; /* 0x30.2200 */
io7_csr rsbv2[887];
io7_csr PO7_LSI_CTL[128]; /* 0x31.0000 */
io7_csr rsvd3[123];
io7_csr HLT_CTL; /* 0x31.3ec0 */
io7_csr HPI_CTL; /* 0x31.3f00 */
io7_csr CRD_CTL;
io7_csr STV_CTL;
io7_csr HEI_CTL;
io7_csr PO7_MSI_CTL[16]; /* 0x31.4000 */
io7_csr rsvd4[240];
/*
* Interrupt Diagnostic / Test
*/
struct {
io7_csr INT_PND;
io7_csr INT_CLR;
io7_csr INT_EOI;
io7_csr rsvd[29];
} INT_DIAG[4];
io7_csr rsvd5[125]; /* 0x31.a000 */
io7_csr MISC_PND; /* 0x31.b800 */
io7_csr rsvd6[31];
io7_csr MSI_PND[16]; /* 0x31.c000 */
io7_csr rsvd7[16];
io7_csr MSI_CLR[16]; /* 0x31.c800 */
} io7_port7_csrs;
/*
* IO7 DMA Window Base register (POx_WBASEx)
*/
#define wbase_m_ena 0x1
#define wbase_m_sg 0x2
#define wbase_m_dac 0x4
#define wbase_m_addr 0xFFF00000
union IO7_POx_WBASE {
struct {
unsigned ena : 1; /* <0> */
unsigned sg : 1; /* <1> */
unsigned dac : 1; /* <2> -- window 3 only */
unsigned rsvd1 : 17;
unsigned addr : 12; /* <31:20> */
unsigned rsvd2 : 32;
} bits;
unsigned as_long[2];
unsigned as_quad;
};
/*
* IO7 IID (Interrupt IDentifier) format
*
* For level-sensative interupts, int_num is encoded as:
*
* bus/port slot/device INTx
* <7:5> <4:2> <1:0>
*/
union IO7_IID {
struct {
unsigned int_num : 9; /* <8:0> */
unsigned tpu_mask : 4; /* <12:9> rsvd */
unsigned msi : 1; /* 13 */
unsigned ipe : 10; /* <23:14> */
unsigned long rsvd : 40;
} bits;
unsigned int as_long[2];
unsigned long as_quad;
};
/*
* IO7 addressing macros
*/
#define IO7_KERN_ADDR(addr) (EV7_KERN_ADDR(addr))
#define IO7_PORT_MASK 0x07UL /* 3 bits of port */
#define IO7_IPE(pe) (EV7_IPE(pe))
#define IO7_IPORT(port) ((~((long)(port)) & IO7_PORT_MASK) << 32)
#define IO7_HOSE(pe, port) (IO7_IPE(pe) | IO7_IPORT(port))
#define IO7_MEM_PHYS(pe, port) (IO7_HOSE(pe, port) | 0x00000000UL)
#define IO7_CONF_PHYS(pe, port) (IO7_HOSE(pe, port) | 0xFE000000UL)
#define IO7_IO_PHYS(pe, port) (IO7_HOSE(pe, port) | 0xFF000000UL)
#define IO7_CSR_PHYS(pe, port, off) \
(IO7_HOSE(pe, port) | 0xFF800000UL | (off))
#define IO7_CSRS_PHYS(pe, port) (IO7_CSR_PHYS(pe, port, 0UL))
#define IO7_PORT7_CSRS_PHYS(pe) (IO7_CSR_PHYS(pe, 7, 0x300000UL))
#define IO7_MEM_KERN(pe, port) (IO7_KERN_ADDR(IO7_MEM_PHYS(pe, port)))
#define IO7_CONF_KERN(pe, port) (IO7_KERN_ADDR(IO7_CONF_PHYS(pe, port)))
#define IO7_IO_KERN(pe, port) (IO7_KERN_ADDR(IO7_IO_PHYS(pe, port)))
#define IO7_CSR_KERN(pe, port, off) (IO7_KERN_ADDR(IO7_CSR_PHYS(pe,port,off)))
#define IO7_CSRS_KERN(pe, port) (IO7_KERN_ADDR(IO7_CSRS_PHYS(pe, port)))
#define IO7_PORT7_CSRS_KERN(pe) (IO7_KERN_ADDR(IO7_PORT7_CSRS_PHYS(pe)))
#define IO7_PLL_RNGA(pll) (((pll) >> 3) & 0x7)
#define IO7_PLL_RNGB(pll) (((pll) >> 6) & 0x7)
#define IO7_MEM_SPACE (2UL * 1024 * 1024 * 1024) /* 2GB MEM */
#define IO7_IO_SPACE (8UL * 1024 * 1024) /* 8MB I/O */
/*
* Offset between ram physical addresses and pci64 DAC addresses
*/
#define IO7_DAC_OFFSET (1UL << 49)
/*
* This is needed to satisify the IO() macro used in initializing the machvec
*/
#define MARVEL_IACK_SC \
((unsigned long) \
(&(((io7_ioport_csrs *)IO7_CSRS_KERN(0, 0))->POx_IACK_SPECIAL)))
#ifdef __KERNEL__
/*
* IO7 structs
*/
#define IO7_NUM_PORTS 4
#define IO7_AGP_PORT 3
struct io7_port {
struct io7 *io7;
struct pci_controller *hose;
int enabled;
unsigned int port;
io7_ioport_csrs *csrs;
unsigned long saved_wbase[4];
unsigned long saved_wmask[4];
unsigned long saved_tbase[4];
};
struct io7 {
struct io7 *next;
unsigned int pe;
io7_port7_csrs *csrs;
struct io7_port ports[IO7_NUM_PORTS];
spinlock_t irq_lock;
};
#ifndef __EXTERN_INLINE
# define __EXTERN_INLINE extern inline
# define __IO_EXTERN_INLINE
#endif
/*
* I/O functions. All access through linear space.
*/
#define vucp volatile unsigned char *
#define vusp volatile unsigned short *
#define vuip volatile unsigned int *
#define vulp volatile unsigned long *
#ifdef CONFIG_VGA_HOSE
extern struct pci_controller *pci_vga_hose;
# define __marvel_is_port_vga(a) \
(((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
# define __marvel_is_mem_vga(a) (((a) >= 0xa0000) && ((a) <= 0xc0000))
# define FIXUP_IOADDR_VGA(a) do { \
if (pci_vga_hose && __marvel_is_port_vga(a)) \
a += pci_vga_hose->io_space->start; \
} while(0)
#else
# define FIXUP_IOADDR_VGA(a)
#endif
#define __marvel_is_port_kbd(a) (((a) == 0x60) || ((a) == 0x64))
#define __marvel_is_port_rtc(a) (((a) == 0x70) || ((a) == 0x71))
#define FIXUP_IOADDR_LEGACY(a)
#define FIXUP_IOADDR(a) do { \
FIXUP_IOADDR_VGA(a); \
FIXUP_IOADDR_LEGACY(a); \
} while(0)
#if 0
# define IOBUG(x) printk x
# define IOBUG_FILTER_IOADDR(a, x) \
if (!__marvel_is_port_kbd(a) && !__marvel_is_port_rtc(a)) IOBUG(x)
#else
# define IOBUG(x)
# define IOBUG_FILTER_IOADDR(a, x)
#endif
extern u8 __marvel_rtc_io(int write, u8 b, unsigned long addr);
#define __marvel_rtc_inb(a) __marvel_rtc_io(0, 0, (a))
#define __marvel_rtc_outb(b, a) __marvel_rtc_io(1, (b), (a))
__EXTERN_INLINE int marvel_is_ioaddr(unsigned long addr)
{
return (addr & (1UL << 40)) != 0; /*FIXME - hardwire*/
}
__EXTERN_INLINE u8 marvel_inb(unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
if (__marvel_is_port_kbd(addr)) return (u8)0;
if (__marvel_is_port_rtc(addr)) return __marvel_rtc_inb(addr);
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return (u8)-1;
}
return __kernel_ldbu(*(vucp)addr);
}
__EXTERN_INLINE void marvel_outb(u8 b, unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
if (__marvel_is_port_rtc(addr))
return (void)__marvel_rtc_outb(b, addr);
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return;
}
__kernel_stb(b, *(vucp)addr);
mb();
}
__EXTERN_INLINE u16 marvel_inw(unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return (u16)-1;
}
return __kernel_ldwu(*(vusp)addr);
}
__EXTERN_INLINE void marvel_outw(u16 w, unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return;
}
__kernel_stw(w, *(vusp)addr);
mb();
}
__EXTERN_INLINE u32 marvel_inl(unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return (u32)-1;
}
return *(vuip)addr;
}
__EXTERN_INLINE void marvel_outl(u32 l, unsigned long addr)
{
FIXUP_IOADDR(addr);
if (!marvel_is_ioaddr(addr)) {
IOBUG_FILTER_IOADDR(addr,
("Bad IO addr %lx - reading -1\n", addr));
return;
}
*(vuip)addr = l;
mb();
}
/*
* Memory functions. All accesses through linear space.
*/
extern unsigned long marvel_ioremap(unsigned long addr, unsigned long size);
extern void marvel_iounmap(unsigned long addr);
__EXTERN_INLINE u8 marvel_readb(unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
return (u8)-1;
}
return __kernel_ldbu(*(vucp)addr);
}
__EXTERN_INLINE u16 marvel_readw(unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
return (u16)-1;
}
return __kernel_ldwu(*(vusp)addr);
}
__EXTERN_INLINE u32 marvel_readl(unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
return (u32)-1;
}
return *(vuip)addr;
}
__EXTERN_INLINE u64 marvel_readq(unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
return (u64)-1;
}
return *(vulp)addr;
}
__EXTERN_INLINE void marvel_writeb(u8 b, unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
return;
}
__kernel_stb(b, *(vucp)addr);
}
__EXTERN_INLINE void marvel_writew(u16 w, unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
return;
}
__kernel_stw(w, *(vusp)addr);
}
__EXTERN_INLINE void marvel_writel(u32 l, unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
return;
}
*(vuip)addr = l;
}
__EXTERN_INLINE void marvel_writeq(u64 q, unsigned long addr)
{
if (!marvel_is_ioaddr(addr)) {
IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
return;
}
*(vulp)addr = q;
}
#undef FIXUP_IOADDR
#undef FIXUP_IOADDR_LEGACY
#undef FIXUP_IOADDR_VGA
#undef vucp
#undef vusp
#undef vuip
#undef vulp
#ifdef __WANT_IO_DEF
#define __inb(p) alpha_mv.mv_inb((unsigned long)(p))
#define __inw(p) alpha_mv.mv_inw((unsigned long)(p))
#define __inl(p) alpha_mv.mv_inl((unsigned long)(p))
#define __outb(x,p) alpha_mv.mv_outb((x),(unsigned long)(p))
#define __outw(x,p) alpha_mv.mv_outw((x),(unsigned long)(p))
#define __outl(x,p) alpha_mv.mv_outl((x),(unsigned long)(p))
#define __readb(a) marvel_readb((unsigned long)(a))
#define __readw(a) marvel_readw((unsigned long)(a))
#define __readl(a) marvel_readl((unsigned long)(a))
#define __readq(a) marvel_readq((unsigned long)(a))
#define __writeb(x,a) marvel_writeb((x),(unsigned long)(a))
#define __writew(x,a) marvel_writew((x),(unsigned long)(a))
#define __writel(x,a) marvel_writel((x),(unsigned long)(a))
#define __writeq(x,a) marvel_writeq((x),(unsigned long)(a))
#define __ioremap(a,s) alpha_mv.mv_ioremap((unsigned long)(a),(s))
#define __iounmap(a) alpha_mv.mv_iounmap((unsigned long)(a))
#define __is_ioaddr(a) marvel_is_ioaddr((unsigned long)(a))
#define inb(port) __inb((port))
#define inw(port) __inw((port))
#define inl(port) __inl((port))
#define outb(v, port) __outb((v),(port))
#define outw(v, port) __outw((v),(port))
#define outl(v, port) __outl((v),(port))
#define __raw_readb(a) __readb((unsigned long)(a))
#define __raw_readw(a) __readw((unsigned long)(a))
#define __raw_readl(a) __readl((unsigned long)(a))
#define __raw_readq(a) __readq((unsigned long)(a))
#define __raw_writeb(v,a) __writeb((v),(unsigned long)(a))
#define __raw_writew(v,a) __writew((v),(unsigned long)(a))
#define __raw_writel(v,a) __writel((v),(unsigned long)(a))
#define __raw_writeq(v,a) __writeq((v),(unsigned long)(a))
#endif /* __WANT_IO_DEF */
#ifdef __IO_EXTERN_INLINE
# undef __EXTERN_INLINE
# undef __IO_EXTERN_INLINE
#endif
#endif /* __KERNEL__ */
#endif /* __ALPHA_MARVEL__H__ */
#ifndef __ALPHA_GCT_H
#define __ALPHA_GCT_H
typedef u64 gct_id;
typedef u64 gct6_handle;
typedef struct __gct6_node {
u8 type;
u8 subtype;
u16 size;
u32 hd_extension;
gct6_handle owner;
gct6_handle active_user;
gct_id id;
u64 flags;
u16 rev;
u16 change_counter;
u16 max_child;
u16 reserved1;
gct6_handle saved_owner;
gct6_handle affinity;
gct6_handle parent;
gct6_handle next;
gct6_handle prev;
gct6_handle child;
u64 fw_flags;
u64 os_usage;
u64 fru_id;
u32 checksum;
u32 magic; /* 'GLXY' */
} gct6_node;
typedef struct {
u8 type;
u8 subtype;
void (*callout)(gct6_node *);
} gct6_search_struct;
#define GCT_NODE_MAGIC 0x59584c47 /* 'GLXY' */
/*
* node types
*/
#define GCT_TYPE_HOSE 0x0E
/*
* node subtypes
*/
#define GCT_SUBTYPE_IO_PORT_MODULE 0x2C
#define GCT_NODE_PTR(off) ((gct6_node *)((char *)hwrpb + \
hwrpb->frut_offset + \
(gct6_handle)(off))) \
int gct6_find_nodes(gct6_node *, gct6_search_struct *);
#endif /* __ALPHA_GCT_H */
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#define ST_DEC_CUSCO 36 /* CUSCO systype */ #define ST_DEC_CUSCO 36 /* CUSCO systype */
#define ST_DEC_EIGER 37 /* Eiger systype */ #define ST_DEC_EIGER 37 /* Eiger systype */
#define ST_DEC_TITAN 38 /* Titan systype */ #define ST_DEC_TITAN 38 /* Titan systype */
#define ST_DEC_MARVEL 39 /* Marvel systype */
/* UNOFFICIAL!!! */ /* UNOFFICIAL!!! */
#define ST_UNOFFICIAL_BIAS 100 #define ST_UNOFFICIAL_BIAS 100
......
...@@ -190,6 +190,8 @@ extern void _sethae (unsigned long addr); /* cached version */ ...@@ -190,6 +190,8 @@ extern void _sethae (unsigned long addr); /* cached version */
# include <asm/jensen.h> # include <asm/jensen.h>
#elif defined(CONFIG_ALPHA_LCA) #elif defined(CONFIG_ALPHA_LCA)
# include <asm/core_lca.h> # include <asm/core_lca.h>
#elif defined(CONFIG_ALPHA_MARVEL)
# include <asm/core_marvel.h>
#elif defined(CONFIG_ALPHA_MCPCIA) #elif defined(CONFIG_ALPHA_MCPCIA)
# include <asm/core_mcpcia.h> # include <asm/core_mcpcia.h>
#elif defined(CONFIG_ALPHA_POLARIS) #elif defined(CONFIG_ALPHA_POLARIS)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
many places throughout the kernel to size static arrays. That's ok, many places throughout the kernel to size static arrays. That's ok,
we'll use alpha_mv.nr_irqs when we want the real thing. */ we'll use alpha_mv.nr_irqs when we want the real thing. */
# define NR_IRQS 2048 /* enuff for WILDFIRE with 8 QBBs */ # define NR_IRQS (32768 + 16) /* enough for MARVEL with 128 PIDs */
#elif defined(CONFIG_ALPHA_CABRIOLET) || \ #elif defined(CONFIG_ALPHA_CABRIOLET) || \
defined(CONFIG_ALPHA_EB66P) || \ defined(CONFIG_ALPHA_EB66P) || \
...@@ -56,6 +56,9 @@ ...@@ -56,6 +56,9 @@
#elif defined(CONFIG_ALPHA_WILDFIRE) #elif defined(CONFIG_ALPHA_WILDFIRE)
# define NR_IRQS 2048 /* enuff for 8 QBBs */ # define NR_IRQS 2048 /* enuff for 8 QBBs */
#elif defined(CONFIG_ALPHA_MARVEL)
# define NR_IRQS (32768 + 16) /* enough for MARVEL with 128 PIDs */
#else /* everyone else */ #else /* everyone else */
# define NR_IRQS 16 # define NR_IRQS 16
#endif #endif
......
...@@ -42,6 +42,8 @@ struct pci_controller { ...@@ -42,6 +42,8 @@ struct pci_controller {
struct pci_iommu_arena *sg_pci; struct pci_iommu_arena *sg_pci;
struct pci_iommu_arena *sg_isa; struct pci_iommu_arena *sg_isa;
void *sysdata;
}; };
/* Override the logic in pci_scan_bus for skipping already-configured /* Override the logic in pci_scan_bus for skipping already-configured
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment