2011-03-08 20:52:49 +03:00
/*
* This file is provided under a dual BSD / GPLv2 license . When using or
* redistributing this file , you may do so under either license .
*
* GPL LICENSE SUMMARY
*
* Copyright ( c ) 2008 - 2011 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* 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 . , 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
* The full GNU General Public License is included in this distribution
* in the file called LICENSE . GPL .
*/
/* probe_roms - scan for oem parameters */
# include <linux/kernel.h>
# include <linux/firmware.h>
# include <linux/uaccess.h>
2011-02-23 11:02:24 +03:00
# include <linux/efi.h>
2011-03-08 20:52:49 +03:00
# include <asm/probe_roms.h>
# include "isci.h"
# include "task.h"
# include "probe_roms.h"
2011-07-03 23:14:45 +04:00
static efi_char16_t isci_efivar_name [ ] = {
' R ' , ' s ' , ' t ' , ' S ' , ' c ' , ' u ' , ' O '
} ;
2011-02-23 11:02:24 +03:00
2011-03-08 20:52:49 +03:00
struct isci_orom * isci_request_oprom ( struct pci_dev * pdev )
{
void __iomem * oprom = pci_map_biosrom ( pdev ) ;
struct isci_orom * rom = NULL ;
size_t len , i ;
2011-03-08 20:53:51 +03:00
int j ;
char oem_sig [ 4 ] ;
struct isci_oem_hdr oem_hdr ;
u8 * tmp , sum ;
2011-03-08 20:52:49 +03:00
if ( ! oprom )
return NULL ;
len = pci_biosrom_size ( pdev ) ;
rom = devm_kzalloc ( & pdev - > dev , sizeof ( * rom ) , GFP_KERNEL ) ;
2011-03-12 01:04:43 +03:00
if ( ! rom ) {
dev_warn ( & pdev - > dev ,
" Unable to allocate memory for orom \n " ) ;
return NULL ;
}
2011-03-08 20:52:49 +03:00
2011-03-08 20:53:51 +03:00
for ( i = 0 ; i < len & & rom ; i + = ISCI_OEM_SIG_SIZE ) {
memcpy_fromio ( oem_sig , oprom + i , ISCI_OEM_SIG_SIZE ) ;
2011-03-08 20:52:49 +03:00
2011-03-08 20:53:51 +03:00
/* we think we found the OEM table */
if ( memcmp ( oem_sig , ISCI_OEM_SIG , ISCI_OEM_SIG_SIZE ) = = 0 ) {
size_t copy_len ;
memcpy_fromio ( & oem_hdr , oprom + i , sizeof ( oem_hdr ) ) ;
copy_len = min ( oem_hdr . len - sizeof ( oem_hdr ) ,
sizeof ( * rom ) ) ;
memcpy_fromio ( rom ,
oprom + i + sizeof ( oem_hdr ) ,
copy_len ) ;
/* calculate checksum */
tmp = ( u8 * ) & oem_hdr ;
for ( j = 0 , sum = 0 ; j < sizeof ( oem_hdr ) ; j + + , tmp + + )
sum + = * tmp ;
tmp = ( u8 * ) rom ;
for ( j = 0 ; j < sizeof ( * rom ) ; j + + , tmp + + )
sum + = * tmp ;
if ( sum ! = 0 ) {
dev_warn ( & pdev - > dev ,
" OEM table checksum failed \n " ) ;
continue ;
}
/* keep going if that's not the oem param table */
if ( memcmp ( rom - > hdr . signature ,
ISCI_ROM_SIG ,
ISCI_ROM_SIG_SIZE ) ! = 0 )
continue ;
dev_info ( & pdev - > dev ,
" OEM parameter table found in OROM \n " ) ;
2011-03-08 20:52:49 +03:00
break ;
}
}
if ( i > = len ) {
dev_err ( & pdev - > dev , " oprom parse error \n " ) ;
rom = NULL ;
}
pci_unmap_biosrom ( oprom ) ;
return rom ;
}
struct isci_orom * isci_request_firmware ( struct pci_dev * pdev , const struct firmware * fw )
{
struct isci_orom * orom = NULL , * data ;
2011-06-02 02:31:03 +04:00
int i , j ;
2011-03-08 20:52:49 +03:00
if ( request_firmware ( & fw , ISCI_FW_NAME , & pdev - > dev ) ! = 0 )
return NULL ;
if ( fw - > size < sizeof ( * orom ) )
goto out ;
data = ( struct isci_orom * ) fw - > data ;
if ( strncmp ( ISCI_ROM_SIG , data - > hdr . signature ,
strlen ( ISCI_ROM_SIG ) ) ! = 0 )
goto out ;
orom = devm_kzalloc ( & pdev - > dev , fw - > size , GFP_KERNEL ) ;
if ( ! orom )
goto out ;
memcpy ( orom , fw - > data , fw - > size ) ;
2012-01-04 13:32:39 +04:00
if ( is_c0 ( pdev ) | | is_c1 ( pdev ) )
2011-07-01 22:41:21 +04:00
goto out ;
2011-06-02 02:31:03 +04:00
/*
* deprecated : override default amp_control for pre - preproduction
* silicon revisions
*/
for ( i = 0 ; i < ARRAY_SIZE ( orom - > ctrl ) ; i + + )
for ( j = 0 ; j < ARRAY_SIZE ( orom - > ctrl [ i ] . phys ) ; j + + ) {
orom - > ctrl [ i ] . phys [ j ] . afe_tx_amp_control0 = 0xe7c03 ;
orom - > ctrl [ i ] . phys [ j ] . afe_tx_amp_control1 = 0xe7c03 ;
orom - > ctrl [ i ] . phys [ j ] . afe_tx_amp_control2 = 0xe7c03 ;
orom - > ctrl [ i ] . phys [ j ] . afe_tx_amp_control3 = 0xe7c03 ;
}
2011-03-08 20:52:49 +03:00
out :
release_firmware ( fw ) ;
return orom ;
}
2011-02-23 11:02:24 +03:00
static struct efi * get_efi ( void )
{
2011-05-25 09:04:35 +04:00
# ifdef CONFIG_EFI
2011-02-23 11:02:24 +03:00
return & efi ;
2011-05-25 09:04:35 +04:00
# else
2011-02-23 11:02:24 +03:00
return NULL ;
2011-05-25 09:04:35 +04:00
# endif
2011-02-23 11:02:24 +03:00
}
struct isci_orom * isci_get_efi_var ( struct pci_dev * pdev )
{
efi_status_t status ;
2011-05-25 09:04:35 +04:00
struct isci_orom * rom ;
2011-03-12 01:04:43 +03:00
struct isci_oem_hdr * oem_hdr ;
u8 * tmp , sum ;
int j ;
2011-07-03 23:14:45 +04:00
unsigned long data_len ;
2011-05-25 09:04:35 +04:00
u8 * efi_data ;
u32 efi_attrib = 0 ;
2011-02-23 11:02:24 +03:00
2011-05-25 09:04:35 +04:00
data_len = 1024 ;
efi_data = devm_kzalloc ( & pdev - > dev , data_len , GFP_KERNEL ) ;
if ( ! efi_data ) {
2011-02-23 11:02:24 +03:00
dev_warn ( & pdev - > dev ,
2011-05-25 09:04:35 +04:00
" Unable to allocate memory for EFI data \n " ) ;
2011-02-23 11:02:24 +03:00
return NULL ;
}
2011-05-25 09:04:35 +04:00
rom = ( struct isci_orom * ) ( efi_data + sizeof ( struct isci_oem_hdr ) ) ;
2011-02-23 11:02:24 +03:00
if ( get_efi ( ) )
2011-05-25 09:04:35 +04:00
status = get_efi ( ) - > get_variable ( isci_efivar_name ,
& ISCI_EFI_VENDOR_GUID ,
& efi_attrib ,
& data_len ,
efi_data ) ;
2011-02-23 11:02:24 +03:00
else
status = EFI_NOT_FOUND ;
2011-03-12 01:04:43 +03:00
if ( status ! = EFI_SUCCESS ) {
2011-02-23 11:02:24 +03:00
dev_warn ( & pdev - > dev ,
2011-05-25 09:04:35 +04:00
" Unable to obtain EFI var data for OEM parms \n " ) ;
2011-03-12 01:04:43 +03:00
return NULL ;
}
2011-05-25 09:04:35 +04:00
oem_hdr = ( struct isci_oem_hdr * ) efi_data ;
2011-02-23 11:02:24 +03:00
2011-03-12 01:04:43 +03:00
if ( memcmp ( oem_hdr - > sig , ISCI_OEM_SIG , ISCI_OEM_SIG_SIZE ) ! = 0 ) {
2011-02-23 11:02:24 +03:00
dev_warn ( & pdev - > dev ,
2011-03-12 01:04:43 +03:00
" Invalid OEM header signature \n " ) ;
return NULL ;
}
2011-02-23 11:02:24 +03:00
2011-03-12 01:04:43 +03:00
/* calculate checksum */
2011-05-25 09:04:35 +04:00
tmp = ( u8 * ) efi_data ;
for ( j = 0 , sum = 0 ; j < ( sizeof ( * oem_hdr ) + sizeof ( * rom ) ) ; j + + , tmp + + )
2011-03-12 01:04:43 +03:00
sum + = * tmp ;
if ( sum ! = 0 ) {
dev_warn ( & pdev - > dev ,
" OEM table checksum failed \n " ) ;
return NULL ;
}
if ( memcmp ( rom - > hdr . signature ,
ISCI_ROM_SIG ,
ISCI_ROM_SIG_SIZE ) ! = 0 ) {
dev_warn ( & pdev - > dev ,
" Invalid OEM table signature \n " ) ;
return NULL ;
}
return rom ;
2011-02-23 11:02:24 +03:00
}