2005-04-16 15:20:36 -07:00
/*
* linux / arch / alpha / kernel / sys_marvel . 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 <linux/bitops.h>
# include <asm/ptrace.h>
# include <asm/dma.h>
# include <asm/irq.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>
ALPHA: support graphics on non-zero PCI domains
This code replaces earlier and incomplete handling of graphics on non-zero PCI
domains (aka hoses or peer PCI buses).
An option (CONFIG_VGA_HOSE) is set TRUE if configuring a GENERIC kernel, or a
kernel for MARVEL, TITAN, or TSUNAMI machines, as these are the machines whose
SRM consoles are capable of configuring and handling graphics options on
non-zero hoses. All other machines have the option set FALSE.
A routine, "find_console_vga_hose()", is used to find the graphics device
which the machine's firmware believes is the console device, and it sets a
global (pci_vga_hose) for later use in managing access to the device. This is
called in "init_arch" on TITAN and TSUNAMI machines; MARVEL machines use a
custom version of this routine because of extra complexity.
A routine, "locate_and_init_vga()", is used to find the graphics device and
set a global (pci_vga_hose) for later use in managing access to the device, in
the case where "find_console_vga_hose" has failed.
Various adjustments are made to the ioremap and ioportmap routines for
detecting and translating "legacy" VGA register and memory references to the
real PCI domain.
[akpm@linux-foundation.org: don't statically init bss]
[akpm@linux-foundation.org: build fix]
Signed-off-by: Jay Estabrook <jay.estabrook@hp.com>
Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-01 00:47:03 -07:00
# include <asm/vga.h>
2005-04-16 15:20:36 -07:00
# include "proto.h"
# include "err_impl.h"
# include "irq_impl.h"
# include "pci_impl.h"
# include "machvec_impl.h"
# if NR_IRQS < MARVEL_NR_IRQS
# error NR_IRQS < MARVEL_NR_IRQS !!!
# endif
/*
* Interrupt handling .
*/
static void
2006-10-08 14:36:08 +01:00
io7_device_interrupt ( unsigned long vector )
2005-04-16 15:20:36 -07:00
{
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 & = MARVEL_IRQ_VEC_IRQ_MASK ; /* not too many bits */
irq | = pid < < MARVEL_IRQ_VEC_PE_SHIFT ; /* merge the pid */
2006-10-08 14:37:32 +01:00
handle_irq ( irq ) ;
2005-04-16 15:20:36 -07:00
}
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 > > MARVEL_IRQ_VEC_PE_SHIFT ;
if ( ! ( io7 = marvel_find_io7 ( pid ) ) ) {
printk ( KERN_ERR
" %s for nonexistent io7 -- vec %x, pid %d \n " ,
2008-04-28 02:13:46 -07:00
__func__ , irq , pid ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
irq & = MARVEL_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 " ,
2008-04-28 02:13:46 -07:00
__func__ , pid , irq ) ;
2005-04-16 15:20:36 -07:00
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
2011-02-06 14:32:39 +00:00
io7_enable_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
volatile unsigned long * ctl ;
2011-02-06 14:32:39 +00:00
unsigned int irq = d - > irq ;
2005-04-16 15:20:36 -07:00
struct io7 * io7 ;
ctl = io7_get_irq_ctl ( irq , & io7 ) ;
if ( ! ctl | | ! io7 ) {
2008-04-28 02:13:46 -07:00
printk ( KERN_ERR " %s: get_ctl failed for irq %x \n " ,
__func__ , irq ) ;
2005-04-16 15:20:36 -07:00
return ;
}
2011-02-06 14:32:39 +00:00
2017-03-21 17:43:02 -05:00
raw_spin_lock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
* ctl | = 1UL < < 24 ;
mb ( ) ;
* ctl ;
2017-03-21 17:43:02 -05:00
raw_spin_unlock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
}
static void
2011-02-06 14:32:39 +00:00
io7_disable_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
volatile unsigned long * ctl ;
2011-02-06 14:32:39 +00:00
unsigned int irq = d - > irq ;
2005-04-16 15:20:36 -07:00
struct io7 * io7 ;
ctl = io7_get_irq_ctl ( irq , & io7 ) ;
if ( ! ctl | | ! io7 ) {
2008-04-28 02:13:46 -07:00
printk ( KERN_ERR " %s: get_ctl failed for irq %x \n " ,
__func__ , irq ) ;
2005-04-16 15:20:36 -07:00
return ;
}
2011-02-06 14:32:39 +00:00
2017-03-21 17:43:02 -05:00
raw_spin_lock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
* ctl & = ~ ( 1UL < < 24 ) ;
mb ( ) ;
* ctl ;
2017-03-21 17:43:02 -05:00
raw_spin_unlock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
}
static void
2011-02-06 14:32:39 +00:00
marvel_irq_noop ( struct irq_data * d )
{
return ;
2005-04-16 15:20:36 -07:00
}
2009-06-16 15:33:25 -07:00
static struct irq_chip marvel_legacy_irq_type = {
2009-11-30 22:51:31 -05:00
. name = " LEGACY " ,
2011-02-06 14:32:39 +00:00
. irq_mask = marvel_irq_noop ,
. irq_unmask = marvel_irq_noop ,
2005-04-16 15:20:36 -07:00
} ;
2009-06-16 15:33:25 -07:00
static struct irq_chip io7_lsi_irq_type = {
2009-11-30 22:51:31 -05:00
. name = " LSI " ,
2011-02-06 14:32:39 +00:00
. irq_unmask = io7_enable_irq ,
. irq_mask = io7_disable_irq ,
. irq_mask_ack = io7_disable_irq ,
2005-04-16 15:20:36 -07:00
} ;
2009-06-16 15:33:25 -07:00
static struct irq_chip io7_msi_irq_type = {
2009-11-30 22:51:31 -05:00
. name = " MSI " ,
2011-02-06 14:32:39 +00:00
. irq_unmask = io7_enable_irq ,
. irq_mask = io7_disable_irq ,
. irq_ack = marvel_irq_noop ,
2005-04-16 15:20:36 -07:00
} ;
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 the 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 the 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 ,
2009-06-16 15:33:25 -07:00
struct irq_chip * lsi_ops ,
struct irq_chip * msi_ops )
2005-04-16 15:20:36 -07:00
{
long base = ( io7 - > pe < < MARVEL_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 ) ;
2017-03-21 17:43:02 -05:00
raw_spin_lock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
/* 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 ) {
2011-03-25 22:17:31 +01:00
irq_set_chip_and_handler ( base + i , lsi_ops , handle_level_irq ) ;
2011-02-06 14:32:39 +00:00
irq_set_status_flags ( i , IRQ_LEVEL ) ;
2005-04-16 15:20:36 -07:00
}
/* 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 ) {
2011-03-25 22:17:31 +01:00
irq_set_chip_and_handler ( base + i , msi_ops , handle_level_irq ) ;
2011-02-06 14:32:39 +00:00
irq_set_status_flags ( i , IRQ_LEVEL ) ;
2005-04-16 15:20:36 -07:00
}
for ( i = 0 ; i < 16 ; + + i )
init_one_io7_msi ( io7 , i , boot_cpuid ) ;
2017-03-21 17:43:02 -05:00
raw_spin_unlock ( & io7 - > irq_lock ) ;
2005-04-16 15:20:36 -07:00
}
static void __init
marvel_init_irq ( void )
{
int i ;
struct io7 * io7 = NULL ;
/* Reserve the legacy irqs. */
for ( i = 0 ; i < 16 ; + + i ) {
2011-03-25 22:17:31 +01:00
irq_set_chip_and_handler ( i , & marvel_legacy_irq_type ,
handle_level_irq ) ;
2005-04-16 15:20:36 -07:00
}
/* 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
2013-07-13 16:21:05 -07:00
marvel_map_irq ( const struct pci_dev * cdev , u8 slot , u8 pin )
2005-04-16 15:20:36 -07:00
{
2013-07-13 16:21:05 -07:00
struct pci_dev * dev = ( struct pci_dev * ) cdev ;
2005-04-16 15:20:36 -07:00
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 ;
2013-08-08 21:13:54 +08:00
msi_loc = dev - > msi_cap ;
2005-04-16 15:20:36 -07:00
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
2005-07-17 04:22:20 +02:00
printk ( " PCI:%d:%d:%d (hose %d) is using MSI \n " ,
2005-04-16 15:20:36 -07:00
dev - > bus - > number ,
PCI_SLOT ( dev - > devfn ) ,
PCI_FUNC ( dev - > devfn ) ,
2005-07-17 04:22:20 +02:00
hose - > index ) ;
2005-04-16 15:20:36 -07:00
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 < < MARVEL_IRQ_VEC_PE_SHIFT ) ,
( irq + 16 ) | ( io7 - > pe < < MARVEL_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 < < MARVEL_IRQ_VEC_PE_SHIFT ; /* merge the pid */
return irq ;
}
static void __init
marvel_init_pci ( void )
{
struct io7 * io7 ;
marvel_register_error_handlers ( ) ;
2012-02-23 20:18:56 -07:00
/* Indicate that we trust the console to configure things properly */
pci_set_flags ( PCI_PROBE_ONLY ) ;
2005-04-16 15:20:36 -07:00
common_init_pci ( ) ;
locate_and_init_vga ( NULL ) ;
/* Clear any io7 errors. */
for ( io7 = NULL ; ( io7 = marvel_next_io7 ( io7 ) ) ! = NULL ; )
io7_clear_errors ( io7 ) ;
}
2007-07-15 23:38:37 -07:00
static void __init
2005-04-16 15:20:36 -07:00
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 )
return ;
/*
* There is a local IO7 - redirect all of its 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
*/
struct alpha_machine_vector marvel_ev7_mv __initmv = {
. vector_name = " MARVEL/EV7 " ,
DO_EV7_MMU ,
2009-01-15 13:51:19 -08:00
. rtc_port = 0x70 ,
2013-07-13 15:49:45 -07:00
. rtc_boot_cpu_only = 1 ,
2005-04-16 15:20:36 -07:00
DO_MARVEL_IO ,
. 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 ,
. 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 )