2006-08-29 18:22:51 +04:00
/*
* Aic94xx SAS / SATA driver register access .
*
* Copyright ( C ) 2005 Adaptec , Inc . All rights reserved .
* Copyright ( C ) 2005 Luben Tuikov < luben_tuikov @ adaptec . com >
*
* This file is licensed under GPLv2 .
*
* This file is part of the aic94xx driver .
*
* The aic94xx driver is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; version 2 of the
* License .
*
* The aic94xx driver is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
*/
# include <linux/pci.h>
# include "aic94xx_reg.h"
# include "aic94xx.h"
/* Writing to device address space.
* Offset comes before value to remind that the operation of
* this function is * offs = val .
*/
2008-03-29 00:48:34 +03:00
static void asd_write_byte ( struct asd_ha_struct * asd_ha ,
unsigned long offs , u8 val )
2006-08-29 18:22:51 +04:00
{
if ( unlikely ( asd_ha - > iospace ) )
outb ( val ,
( unsigned long ) asd_ha - > io_handle [ 0 ] . addr + ( offs & 0xFF ) ) ;
else
writeb ( val , asd_ha - > io_handle [ 0 ] . addr + offs ) ;
wmb ( ) ;
}
2008-03-29 00:48:34 +03:00
static void asd_write_word ( struct asd_ha_struct * asd_ha ,
unsigned long offs , u16 val )
2006-08-29 18:22:51 +04:00
{
if ( unlikely ( asd_ha - > iospace ) )
outw ( val ,
( unsigned long ) asd_ha - > io_handle [ 0 ] . addr + ( offs & 0xFF ) ) ;
else
writew ( val , asd_ha - > io_handle [ 0 ] . addr + offs ) ;
wmb ( ) ;
}
2008-03-29 00:48:34 +03:00
static void asd_write_dword ( struct asd_ha_struct * asd_ha ,
unsigned long offs , u32 val )
2006-08-29 18:22:51 +04:00
{
if ( unlikely ( asd_ha - > iospace ) )
outl ( val ,
( unsigned long ) asd_ha - > io_handle [ 0 ] . addr + ( offs & 0xFF ) ) ;
else
writel ( val , asd_ha - > io_handle [ 0 ] . addr + offs ) ;
wmb ( ) ;
}
/* Reading from device address space.
*/
2008-03-29 00:48:34 +03:00
static u8 asd_read_byte ( struct asd_ha_struct * asd_ha , unsigned long offs )
2006-08-29 18:22:51 +04:00
{
u8 val ;
if ( unlikely ( asd_ha - > iospace ) )
val = inb ( ( unsigned long ) asd_ha - > io_handle [ 0 ] . addr
+ ( offs & 0xFF ) ) ;
else
val = readb ( asd_ha - > io_handle [ 0 ] . addr + offs ) ;
rmb ( ) ;
return val ;
}
2008-03-29 00:48:34 +03:00
static u16 asd_read_word ( struct asd_ha_struct * asd_ha ,
unsigned long offs )
2006-08-29 18:22:51 +04:00
{
u16 val ;
if ( unlikely ( asd_ha - > iospace ) )
val = inw ( ( unsigned long ) asd_ha - > io_handle [ 0 ] . addr
+ ( offs & 0xFF ) ) ;
else
val = readw ( asd_ha - > io_handle [ 0 ] . addr + offs ) ;
rmb ( ) ;
return val ;
}
2008-03-29 00:48:34 +03:00
static u32 asd_read_dword ( struct asd_ha_struct * asd_ha ,
unsigned long offs )
2006-08-29 18:22:51 +04:00
{
u32 val ;
if ( unlikely ( asd_ha - > iospace ) )
val = inl ( ( unsigned long ) asd_ha - > io_handle [ 0 ] . addr
+ ( offs & 0xFF ) ) ;
else
val = readl ( asd_ha - > io_handle [ 0 ] . addr + offs ) ;
rmb ( ) ;
return val ;
}
static inline u32 asd_mem_offs_swa ( void )
{
return 0 ;
}
static inline u32 asd_mem_offs_swc ( void )
{
return asd_mem_offs_swa ( ) + MBAR0_SWA_SIZE ;
}
static inline u32 asd_mem_offs_swb ( void )
{
return asd_mem_offs_swc ( ) + MBAR0_SWC_SIZE + 0x20 ;
}
/* We know that the register wanted is in the range
* of the sliding window .
*/
2008-03-29 00:48:34 +03:00
# define ASD_READ_SW(ww, type, ord) \
static type asd_read_ # # ww # # _ # # ord ( struct asd_ha_struct * asd_ha , \
u32 reg ) \
{ \
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ; \
u32 map_offs = ( reg - io_handle - > ww # # _base ) + asd_mem_offs_ # # ww ( ) ; \
return asd_read_ # # ord ( asd_ha , ( unsigned long ) map_offs ) ; \
2006-08-29 18:22:51 +04:00
}
2008-03-29 00:48:34 +03:00
# define ASD_WRITE_SW(ww, type, ord) \
static void asd_write_ # # ww # # _ # # ord ( struct asd_ha_struct * asd_ha , \
u32 reg , type val ) \
{ \
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ; \
u32 map_offs = ( reg - io_handle - > ww # # _base ) + asd_mem_offs_ # # ww ( ) ; \
asd_write_ # # ord ( asd_ha , ( unsigned long ) map_offs , val ) ; \
2006-08-29 18:22:51 +04:00
}
ASD_READ_SW ( swa , u8 , byte ) ;
ASD_READ_SW ( swa , u16 , word ) ;
ASD_READ_SW ( swa , u32 , dword ) ;
ASD_READ_SW ( swb , u8 , byte ) ;
ASD_READ_SW ( swb , u16 , word ) ;
ASD_READ_SW ( swb , u32 , dword ) ;
ASD_READ_SW ( swc , u8 , byte ) ;
ASD_READ_SW ( swc , u16 , word ) ;
ASD_READ_SW ( swc , u32 , dword ) ;
ASD_WRITE_SW ( swa , u8 , byte ) ;
ASD_WRITE_SW ( swa , u16 , word ) ;
ASD_WRITE_SW ( swa , u32 , dword ) ;
ASD_WRITE_SW ( swb , u8 , byte ) ;
ASD_WRITE_SW ( swb , u16 , word ) ;
ASD_WRITE_SW ( swb , u32 , dword ) ;
ASD_WRITE_SW ( swc , u8 , byte ) ;
ASD_WRITE_SW ( swc , u16 , word ) ;
ASD_WRITE_SW ( swc , u32 , dword ) ;
/*
* A word about sliding windows :
* MBAR0 is divided into sliding windows A , C and B , in that order .
* SWA starts at offset 0 of MBAR0 , up to 0x57 , with size 0x58 bytes .
* SWC starts at offset 0x58 of MBAR0 , up to 0x60 , with size 0x8 bytes .
* From 0x60 to 0x7F , we have a copy of PCI config space 0x60 - 0x7F .
* SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0 .
* See asd_init_sw ( ) in aic94xx_hwi . c
*
* We map the most common registers we ' d access of the internal 4 GB
* host adapter memory space . If a register / internal memory location
* is wanted which is not mapped , we slide SWB , by paging it ,
* see asd_move_swb ( ) in aic94xx_reg . c .
*/
/**
* asd_move_swb - - move sliding window B
* @ asd_ha : pointer to host adapter structure
* @ reg : register desired to be within range of the new window
*/
2008-03-29 00:48:34 +03:00
static void asd_move_swb ( struct asd_ha_struct * asd_ha , u32 reg )
2006-08-29 18:22:51 +04:00
{
u32 base = reg & ~ ( MBAR0_SWB_SIZE - 1 ) ;
pci_write_config_dword ( asd_ha - > pcidev , PCI_CONF_MBAR0_SWB , base ) ;
asd_ha - > io_handle [ 0 ] . swb_base = base ;
}
static void __asd_write_reg_byte ( struct asd_ha_struct * asd_ha , u32 reg , u8 val )
{
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ;
BUG_ON ( reg > = 0xC0000000 | | reg < ALL_BASE_ADDR ) ;
if ( io_handle - > swa_base < = reg
& & reg < io_handle - > swa_base + MBAR0_SWA_SIZE )
asd_write_swa_byte ( asd_ha , reg , val ) ;
else if ( io_handle - > swb_base < = reg
& & reg < io_handle - > swb_base + MBAR0_SWB_SIZE )
asd_write_swb_byte ( asd_ha , reg , val ) ;
else if ( io_handle - > swc_base < = reg
& & reg < io_handle - > swc_base + MBAR0_SWC_SIZE )
asd_write_swc_byte ( asd_ha , reg , val ) ;
else {
/* Ok, we have to move SWB */
asd_move_swb ( asd_ha , reg ) ;
asd_write_swb_byte ( asd_ha , reg , val ) ;
}
}
# define ASD_WRITE_REG(type, ord) \
void asd_write_reg_ # # ord ( struct asd_ha_struct * asd_ha , u32 reg , type val ) \
{ \
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ; \
unsigned long flags ; \
BUG_ON ( reg > = 0xC0000000 | | reg < ALL_BASE_ADDR ) ; \
spin_lock_irqsave ( & asd_ha - > iolock , flags ) ; \
if ( io_handle - > swa_base < = reg \
& & reg < io_handle - > swa_base + MBAR0_SWA_SIZE ) \
asd_write_swa_ # # ord ( asd_ha , reg , val ) ; \
else if ( io_handle - > swb_base < = reg \
& & reg < io_handle - > swb_base + MBAR0_SWB_SIZE ) \
asd_write_swb_ # # ord ( asd_ha , reg , val ) ; \
else if ( io_handle - > swc_base < = reg \
& & reg < io_handle - > swc_base + MBAR0_SWC_SIZE ) \
asd_write_swc_ # # ord ( asd_ha , reg , val ) ; \
else { \
/* Ok, we have to move SWB */ \
asd_move_swb ( asd_ha , reg ) ; \
asd_write_swb_ # # ord ( asd_ha , reg , val ) ; \
} \
spin_unlock_irqrestore ( & asd_ha - > iolock , flags ) ; \
}
ASD_WRITE_REG ( u8 , byte ) ;
ASD_WRITE_REG ( u16 , word ) ;
ASD_WRITE_REG ( u32 , dword ) ;
static u8 __asd_read_reg_byte ( struct asd_ha_struct * asd_ha , u32 reg )
{
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ;
u8 val ;
BUG_ON ( reg > = 0xC0000000 | | reg < ALL_BASE_ADDR ) ;
if ( io_handle - > swa_base < = reg
& & reg < io_handle - > swa_base + MBAR0_SWA_SIZE )
val = asd_read_swa_byte ( asd_ha , reg ) ;
else if ( io_handle - > swb_base < = reg
& & reg < io_handle - > swb_base + MBAR0_SWB_SIZE )
val = asd_read_swb_byte ( asd_ha , reg ) ;
else if ( io_handle - > swc_base < = reg
& & reg < io_handle - > swc_base + MBAR0_SWC_SIZE )
val = asd_read_swc_byte ( asd_ha , reg ) ;
else {
/* Ok, we have to move SWB */
asd_move_swb ( asd_ha , reg ) ;
val = asd_read_swb_byte ( asd_ha , reg ) ;
}
return val ;
}
# define ASD_READ_REG(type, ord) \
type asd_read_reg_ # # ord ( struct asd_ha_struct * asd_ha , u32 reg ) \
{ \
struct asd_ha_addrspace * io_handle = & asd_ha - > io_handle [ 0 ] ; \
type val ; \
unsigned long flags ; \
BUG_ON ( reg > = 0xC0000000 | | reg < ALL_BASE_ADDR ) ; \
spin_lock_irqsave ( & asd_ha - > iolock , flags ) ; \
if ( io_handle - > swa_base < = reg \
& & reg < io_handle - > swa_base + MBAR0_SWA_SIZE ) \
val = asd_read_swa_ # # ord ( asd_ha , reg ) ; \
else if ( io_handle - > swb_base < = reg \
& & reg < io_handle - > swb_base + MBAR0_SWB_SIZE ) \
val = asd_read_swb_ # # ord ( asd_ha , reg ) ; \
else if ( io_handle - > swc_base < = reg \
& & reg < io_handle - > swc_base + MBAR0_SWC_SIZE ) \
val = asd_read_swc_ # # ord ( asd_ha , reg ) ; \
else { \
/* Ok, we have to move SWB */ \
asd_move_swb ( asd_ha , reg ) ; \
val = asd_read_swb_ # # ord ( asd_ha , reg ) ; \
} \
spin_unlock_irqrestore ( & asd_ha - > iolock , flags ) ; \
return val ; \
}
ASD_READ_REG ( u8 , byte ) ;
ASD_READ_REG ( u16 , word ) ;
ASD_READ_REG ( u32 , dword ) ;
/**
* asd_read_reg_string - - read a string of bytes from io space memory
* @ asd_ha : pointer to host adapter structure
* @ dst : pointer to a destination buffer where data will be written to
* @ offs : start offset ( register ) to read from
* @ count : number of bytes to read
*/
void asd_read_reg_string ( struct asd_ha_struct * asd_ha , void * dst ,
u32 offs , int count )
{
u8 * p = dst ;
unsigned long flags ;
spin_lock_irqsave ( & asd_ha - > iolock , flags ) ;
for ( ; count > 0 ; count - - , offs + + , p + + )
* p = __asd_read_reg_byte ( asd_ha , offs ) ;
spin_unlock_irqrestore ( & asd_ha - > iolock , flags ) ;
}
/**
* asd_write_reg_string - - write a string of bytes to io space memory
* @ asd_ha : pointer to host adapter structure
* @ src : pointer to source buffer where data will be read from
* @ offs : start offset ( register ) to write to
* @ count : number of bytes to write
*/
void asd_write_reg_string ( struct asd_ha_struct * asd_ha , void * src ,
u32 offs , int count )
{
u8 * p = src ;
unsigned long flags ;
spin_lock_irqsave ( & asd_ha - > iolock , flags ) ;
for ( ; count > 0 ; count - - , offs + + , p + + )
__asd_write_reg_byte ( asd_ha , offs , * p ) ;
spin_unlock_irqrestore ( & asd_ha - > iolock , flags ) ;
}