2013-02-05 14:15:02 +01:00
/*
* Filename : config . c
*
*
* Authors : Joshua Morris < josh . h . morris @ us . ibm . com >
* Philip Kelleher < pjk1939 @ linux . vnet . ibm . com >
*
* ( C ) Copyright 2013 IBM Corporation
*
* This program 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 ; either version 2 of the
* License , or ( at your option ) any later version .
*
* This program 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 this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/types.h>
# include <linux/crc32.h>
# include <linux/swab.h>
# include "rsxx_priv.h"
# include "rsxx_cfg.h"
2013-02-25 12:27:46 -06:00
static void initialize_config ( struct rsxx_card_cfg * cfg )
2013-02-05 14:15:02 +01:00
{
cfg - > hdr . version = RSXX_CFG_VERSION ;
cfg - > data . block_size = RSXX_HW_BLK_SIZE ;
cfg - > data . stripe_size = RSXX_HW_BLK_SIZE ;
2013-02-27 09:24:59 -06:00
cfg - > data . vendor_id = RSXX_VENDOR_ID_IBM ;
2013-02-05 14:15:02 +01:00
cfg - > data . cache_order = ( - 1 ) ;
cfg - > data . intr_coal . mode = RSXX_INTR_COAL_DISABLED ;
cfg - > data . intr_coal . count = 0 ;
cfg - > data . intr_coal . latency = 0 ;
}
static u32 config_data_crc32 ( struct rsxx_card_cfg * cfg )
{
/*
* Return the compliment of the CRC to ensure compatibility
* ( i . e . this is how early rsxx drivers did it . )
*/
return ~ crc32 ( ~ 0 , & cfg - > data , sizeof ( cfg - > data ) ) ;
}
/*----------------- Config Byte Swap Functions -------------------*/
static void config_hdr_be_to_cpu ( struct card_cfg_hdr * hdr )
{
hdr - > version = be32_to_cpu ( ( __force __be32 ) hdr - > version ) ;
hdr - > crc = be32_to_cpu ( ( __force __be32 ) hdr - > crc ) ;
}
static void config_hdr_cpu_to_be ( struct card_cfg_hdr * hdr )
{
hdr - > version = ( __force u32 ) cpu_to_be32 ( hdr - > version ) ;
hdr - > crc = ( __force u32 ) cpu_to_be32 ( hdr - > crc ) ;
}
static void config_data_swab ( struct rsxx_card_cfg * cfg )
{
u32 * data = ( u32 * ) & cfg - > data ;
int i ;
for ( i = 0 ; i < ( sizeof ( cfg - > data ) / 4 ) ; i + + )
data [ i ] = swab32 ( data [ i ] ) ;
}
static void config_data_le_to_cpu ( struct rsxx_card_cfg * cfg )
{
u32 * data = ( u32 * ) & cfg - > data ;
int i ;
for ( i = 0 ; i < ( sizeof ( cfg - > data ) / 4 ) ; i + + )
data [ i ] = le32_to_cpu ( ( __force __le32 ) data [ i ] ) ;
}
static void config_data_cpu_to_le ( struct rsxx_card_cfg * cfg )
{
u32 * data = ( u32 * ) & cfg - > data ;
int i ;
for ( i = 0 ; i < ( sizeof ( cfg - > data ) / 4 ) ; i + + )
data [ i ] = ( __force u32 ) cpu_to_le32 ( data [ i ] ) ;
}
/*----------------- Config Operations ------------------*/
2013-02-18 21:35:59 +01:00
static int rsxx_save_config ( struct rsxx_cardinfo * card )
2013-02-05 14:15:02 +01:00
{
struct rsxx_card_cfg cfg ;
int st ;
memcpy ( & cfg , & card - > config , sizeof ( cfg ) ) ;
if ( unlikely ( cfg . hdr . version ! = RSXX_CFG_VERSION ) ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Cannot save config with invalid version %d \n " ,
cfg . hdr . version ) ;
return - EINVAL ;
}
/* Convert data to little endian for the CRC calculation. */
config_data_cpu_to_le ( & cfg ) ;
cfg . hdr . crc = config_data_crc32 ( & cfg ) ;
/*
* Swap the data from little endian to big endian so it can be
* stored .
*/
config_data_swab ( & cfg ) ;
config_hdr_cpu_to_be ( & cfg . hdr ) ;
st = rsxx_creg_write ( card , CREG_ADD_CONFIG , sizeof ( cfg ) , & cfg , 1 ) ;
if ( st )
return st ;
return 0 ;
}
int rsxx_load_config ( struct rsxx_cardinfo * card )
{
int st ;
u32 crc ;
st = rsxx_creg_read ( card , CREG_ADD_CONFIG , sizeof ( card - > config ) ,
& card - > config , 1 ) ;
if ( st ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Failed reading card config. \n " ) ;
return st ;
}
config_hdr_be_to_cpu ( & card - > config . hdr ) ;
if ( card - > config . hdr . version = = RSXX_CFG_VERSION ) {
/*
* We calculate the CRC with the data in little endian , because
* early drivers did not take big endian CPUs into account .
* The data is always stored in big endian , so we need to byte
* swap it before calculating the CRC .
*/
config_data_swab ( & card - > config ) ;
/* Check the CRC */
crc = config_data_crc32 ( & card - > config ) ;
if ( crc ! = card - > config . hdr . crc ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Config corruption detected! \n " ) ;
dev_info ( CARD_TO_DEV ( card ) ,
" CRC (sb x%08x is x%08x) \n " ,
card - > config . hdr . crc , crc ) ;
return - EIO ;
}
/* Convert the data to CPU byteorder */
config_data_le_to_cpu ( & card - > config ) ;
} else if ( card - > config . hdr . version ! = 0 ) {
dev_err ( CARD_TO_DEV ( card ) ,
" Invalid config version %d. \n " ,
card - > config . hdr . version ) ;
/*
* Config version changes require special handling from the
* user
*/
return - EINVAL ;
} else {
dev_info ( CARD_TO_DEV ( card ) ,
" Initializing card configuration. \n " ) ;
2013-02-25 12:27:46 -06:00
initialize_config ( & card - > config ) ;
2013-02-05 14:15:02 +01:00
st = rsxx_save_config ( card ) ;
if ( st )
return st ;
}
card - > config_valid = 1 ;
dev_dbg ( CARD_TO_DEV ( card ) , " version: x%08x \n " ,
card - > config . hdr . version ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " crc: x%08x \n " ,
card - > config . hdr . crc ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " block_size: x%08x \n " ,
card - > config . data . block_size ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " stripe_size: x%08x \n " ,
card - > config . data . stripe_size ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " vendor_id: x%08x \n " ,
card - > config . data . vendor_id ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " cache_order: x%08x \n " ,
card - > config . data . cache_order ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " mode: x%08x \n " ,
card - > config . data . intr_coal . mode ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " count: x%08x \n " ,
card - > config . data . intr_coal . count ) ;
dev_dbg ( CARD_TO_DEV ( card ) , " latency: x%08x \n " ,
card - > config . data . intr_coal . latency ) ;
return 0 ;
}