2005-04-17 02:20:36 +04:00
/*
* linux / arch / alpha / kernel / sys_rawhide . c
*
* Copyright ( C ) 1995 David A Rusling
* Copyright ( C ) 1996 Jay A Estabrook
* Copyright ( C ) 1998 , 1999 Richard Henderson
*
* Code supporting the RAWHIDE .
*/
# 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/dma.h>
# include <asm/irq.h>
# include <asm/mmu_context.h>
# include <asm/io.h>
# include <asm/pgtable.h>
# include <asm/core_mcpcia.h>
# include <asm/tlbflush.h>
# include "proto.h"
# include "irq_impl.h"
# include "pci_impl.h"
# include "machvec_impl.h"
/*
* HACK ALERT ! only the boot cpu is used for interrupts .
*/
/* Note mask bit is true for ENABLED irqs. */
static unsigned int hose_irq_masks [ 4 ] = {
0xff0000 , 0xfe0000 , 0xff0000 , 0xff0000
} ;
static unsigned int cached_irq_masks [ 4 ] ;
DEFINE_SPINLOCK ( rawhide_irq_lock ) ;
static inline void
rawhide_update_irq_hw ( int hose , int mask )
{
* ( vuip ) MCPCIA_INT_MASK0 ( MCPCIA_HOSE2MID ( hose ) ) = mask ;
mb ( ) ;
* ( vuip ) MCPCIA_INT_MASK0 ( MCPCIA_HOSE2MID ( hose ) ) ;
}
2007-04-17 09:53:17 +04:00
# define hose_exists(h) \
( ( ( h ) < MCPCIA_MAX_HOSES ) & & ( cached_irq_masks [ ( h ) ] ! = 0 ) )
2005-04-17 02:20:36 +04:00
static inline void
2011-02-06 17:32:44 +03:00
rawhide_enable_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
unsigned int mask , hose ;
2011-02-06 17:32:44 +03:00
unsigned int irq = d - > irq ;
2005-04-17 02:20:36 +04:00
irq - = 16 ;
hose = irq / 24 ;
2007-04-17 09:53:17 +04:00
if ( ! hose_exists ( hose ) ) /* if hose non-existent, exit */
return ;
2005-04-17 02:20:36 +04:00
irq - = hose * 24 ;
mask = 1 < < irq ;
spin_lock ( & rawhide_irq_lock ) ;
mask | = cached_irq_masks [ hose ] ;
cached_irq_masks [ hose ] = mask ;
rawhide_update_irq_hw ( hose , mask ) ;
spin_unlock ( & rawhide_irq_lock ) ;
}
static void
2011-02-06 17:32:44 +03:00
rawhide_disable_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
unsigned int mask , hose ;
2011-02-06 17:32:44 +03:00
unsigned int irq = d - > irq ;
2005-04-17 02:20:36 +04:00
irq - = 16 ;
hose = irq / 24 ;
2007-04-17 09:53:17 +04:00
if ( ! hose_exists ( hose ) ) /* if hose non-existent, exit */
return ;
2005-04-17 02:20:36 +04:00
irq - = hose * 24 ;
mask = ~ ( 1 < < irq ) | hose_irq_masks [ hose ] ;
spin_lock ( & rawhide_irq_lock ) ;
mask & = cached_irq_masks [ hose ] ;
cached_irq_masks [ hose ] = mask ;
rawhide_update_irq_hw ( hose , mask ) ;
spin_unlock ( & rawhide_irq_lock ) ;
}
static void
2011-02-06 17:32:44 +03:00
rawhide_mask_and_ack_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
unsigned int mask , mask1 , hose ;
2011-02-06 17:32:44 +03:00
unsigned int irq = d - > irq ;
2005-04-17 02:20:36 +04:00
irq - = 16 ;
hose = irq / 24 ;
2007-04-17 09:53:17 +04:00
if ( ! hose_exists ( hose ) ) /* if hose non-existent, exit */
return ;
2005-04-17 02:20:36 +04:00
irq - = hose * 24 ;
mask1 = 1 < < irq ;
mask = ~ mask1 | hose_irq_masks [ hose ] ;
spin_lock ( & rawhide_irq_lock ) ;
mask & = cached_irq_masks [ hose ] ;
cached_irq_masks [ hose ] = mask ;
rawhide_update_irq_hw ( hose , mask ) ;
/* Clear the interrupt. */
* ( vuip ) MCPCIA_INT_REQ ( MCPCIA_HOSE2MID ( hose ) ) = mask1 ;
spin_unlock ( & rawhide_irq_lock ) ;
}
2009-06-17 02:33:25 +04:00
static struct irq_chip rawhide_irq_type = {
2009-12-01 06:51:31 +03:00
. name = " RAWHIDE " ,
2011-02-06 17:32:44 +03:00
. irq_unmask = rawhide_enable_irq ,
. irq_mask = rawhide_disable_irq ,
. irq_mask_ack = rawhide_mask_and_ack_irq ,
2005-04-17 02:20:36 +04:00
} ;
static void
2006-10-08 17:36:08 +04:00
rawhide_srm_device_interrupt ( unsigned long vector )
2005-04-17 02:20:36 +04:00
{
int irq ;
irq = ( vector - 0x800 ) > > 4 ;
/*
* The RAWHIDE SRM console reports PCI interrupts with a vector
* 0x80 * higher * than one might expect , as PCI IRQ 0 ( ie bit 0 )
* shows up as IRQ 24 , etc , etc . We adjust it down by 8 to have
* it line up with the actual bit numbers from the REQ registers ,
* which is how we manage the interrupts / mask . Sigh . . .
*
* Also , PCI # 1 interrupts are offset some more . . . : - (
*/
if ( irq = = 52 ) {
/* SCSI on PCI1 is special. */
irq = 72 ;
}
/* Adjust by which hose it is from. */
irq - = ( ( irq + 16 ) > > 2 ) & 0x38 ;
2006-10-08 17:37:32 +04:00
handle_irq ( irq ) ;
2005-04-17 02:20:36 +04:00
}
static void __init
rawhide_init_irq ( void )
{
struct pci_controller * hose ;
long i ;
mcpcia_init_hoses ( ) ;
2007-04-17 09:53:17 +04:00
/* Clear them all; only hoses that exist will be non-zero. */
for ( i = 0 ; i < MCPCIA_MAX_HOSES ; i + + ) cached_irq_masks [ i ] = 0 ;
2005-04-17 02:20:36 +04:00
for ( hose = hose_head ; hose ; hose = hose - > next ) {
unsigned int h = hose - > index ;
unsigned int mask = hose_irq_masks [ h ] ;
cached_irq_masks [ h ] = mask ;
* ( vuip ) MCPCIA_INT_MASK0 ( MCPCIA_HOSE2MID ( h ) ) = mask ;
* ( vuip ) MCPCIA_INT_MASK1 ( MCPCIA_HOSE2MID ( h ) ) = 0 ;
}
for ( i = 16 ; i < 128 ; + + i ) {
2011-03-26 00:17:31 +03:00
irq_set_chip_and_handler ( i , & rawhide_irq_type ,
handle_level_irq ) ;
2011-02-06 17:32:44 +03:00
irq_set_status_flags ( i , IRQ_LEVEL ) ;
2005-04-17 02:20:36 +04:00
}
init_i8259a_irqs ( ) ;
common_init_isa_dma ( ) ;
}
/*
* PCI Fixup configuration .
*
* Summary @ MCPCIA_PCI0_INT_REQ :
* Bit Meaning
* 0 Interrupt Line A from slot 2 PCI0
* 1 Interrupt Line B from slot 2 PCI0
* 2 Interrupt Line C from slot 2 PCI0
* 3 Interrupt Line D from slot 2 PCI0
* 4 Interrupt Line A from slot 3 PCI0
* 5 Interrupt Line B from slot 3 PCI0
* 6 Interrupt Line C from slot 3 PCI0
* 7 Interrupt Line D from slot 3 PCI0
* 8 Interrupt Line A from slot 4 PCI0
* 9 Interrupt Line B from slot 4 PCI0
* 10 Interrupt Line C from slot 4 PCI0
* 11 Interrupt Line D from slot 4 PCI0
* 12 Interrupt Line A from slot 5 PCI0
* 13 Interrupt Line B from slot 5 PCI0
* 14 Interrupt Line C from slot 5 PCI0
* 15 Interrupt Line D from slot 5 PCI0
* 16 EISA interrupt ( PCI 0 ) or SCSI interrupt ( PCI 1 )
* 17 - 23 NA
*
* IdSel
* 1 EISA bridge ( PCI bus 0 only )
* 2 PCI option slot 2
* 3 PCI option slot 3
* 4 PCI option slot 4
* 5 PCI option slot 5
*
*/
static int __init
2011-06-10 18:30:21 +04:00
rawhide_map_irq ( const struct pci_dev * dev , u8 slot , u8 pin )
2005-04-17 02:20:36 +04:00
{
static char irq_tab [ 5 ] [ 5 ] __initdata = {
/*INT INTA INTB INTC INTD */
{ 16 + 16 , 16 + 16 , 16 + 16 , 16 + 16 , 16 + 16 } , /* IdSel 1 SCSI PCI 1 */
{ 16 + 0 , 16 + 0 , 16 + 1 , 16 + 2 , 16 + 3 } , /* IdSel 2 slot 2 */
{ 16 + 4 , 16 + 4 , 16 + 5 , 16 + 6 , 16 + 7 } , /* IdSel 3 slot 3 */
{ 16 + 8 , 16 + 8 , 16 + 9 , 16 + 10 , 16 + 11 } , /* IdSel 4 slot 4 */
{ 16 + 12 , 16 + 12 , 16 + 13 , 16 + 14 , 16 + 15 } /* IdSel 5 slot 5 */
} ;
const long min_idsel = 1 , max_idsel = 5 , irqs_per_slot = 5 ;
struct pci_controller * hose = dev - > sysdata ;
int irq = COMMON_TABLE_LOOKUP ;
if ( irq > = 0 )
irq + = 24 * hose - > index ;
return irq ;
}
/*
* The System Vector
*/
struct alpha_machine_vector rawhide_mv __initmv = {
. vector_name = " Rawhide " ,
DO_EV5_MMU ,
DO_DEFAULT_RTC ,
DO_MCPCIA_IO ,
. machine_check = mcpcia_machine_check ,
. max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS ,
. min_io_address = DEFAULT_IO_BASE ,
. min_mem_address = MCPCIA_DEFAULT_MEM_BASE ,
. pci_dac_offset = MCPCIA_DAC_OFFSET ,
. nr_irqs = 128 ,
. device_interrupt = rawhide_srm_device_interrupt ,
. init_arch = mcpcia_init_arch ,
. init_irq = rawhide_init_irq ,
. init_rtc = common_init_rtc ,
. init_pci = common_init_pci ,
. kill_arch = NULL ,
. pci_map_irq = rawhide_map_irq ,
. pci_swizzle = common_swizzle ,
} ;
ALIAS_MV ( rawhide )