2012-11-29 14:34:48 +01:00
/*
* Copyright IBM Corp . 2012
*
* Author ( s ) :
* Jan Glauber < jang @ linux . vnet . ibm . com >
*/
2014-07-16 17:21:01 +02:00
# define KMSG_COMPONENT "zpci"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2012-11-29 14:34:48 +01:00
# include <linux/kernel.h>
# include <linux/pci.h>
2013-10-22 15:17:19 +02:00
# include <asm/pci_debug.h>
2013-11-15 13:56:08 +01:00
# include <asm/sclp.h>
2012-11-29 14:34:48 +01:00
/* Content Code Description for PCI Function Error */
struct zpci_ccdf_err {
u32 reserved1 ;
u32 fh ; /* function handle */
u32 fid ; /* function id */
u32 ett : 4 ; /* expected table type */
u32 mvn : 12 ; /* MSI vector number */
u32 dmaas : 8 ; /* DMA address space */
u32 : 6 ;
u32 q : 1 ; /* event qualifier */
u32 rw : 1 ; /* read/write */
u64 faddr ; /* failing address */
u32 reserved3 ;
u16 reserved4 ;
u16 pec ; /* PCI event code */
} __packed ;
/* Content Code Description for PCI Function Availability */
struct zpci_ccdf_avail {
u32 reserved1 ;
u32 fh ; /* function handle */
u32 fid ; /* function id */
u32 reserved2 ;
u32 reserved3 ;
u32 reserved4 ;
u32 reserved5 ;
u16 reserved6 ;
u16 pec ; /* PCI event code */
} __packed ;
2013-12-12 17:48:32 +01:00
static void __zpci_event_error ( struct zpci_ccdf_err * ccdf )
2012-11-29 14:34:48 +01:00
{
2013-11-15 13:56:08 +01:00
struct zpci_dev * zdev = get_zdev_by_fid ( ccdf - > fid ) ;
zpci_err ( " error CCDF: \n " ) ;
zpci_err_hex ( ccdf , sizeof ( * ccdf ) ) ;
if ( ! zdev )
return ;
pr_err ( " %s: Event 0x%x reports an error for PCI function 0x%x \n " ,
pci_name ( zdev - > pdev ) , ccdf - > pec , ccdf - > fid ) ;
}
2013-12-12 17:48:32 +01:00
void zpci_event_error ( void * data )
{
if ( zpci_is_enabled ( ) )
__zpci_event_error ( data ) ;
}
static void __zpci_event_availability ( struct zpci_ccdf_avail * ccdf )
2013-11-15 13:56:08 +01:00
{
2012-11-29 14:34:48 +01:00
struct zpci_dev * zdev = get_zdev_by_fid ( ccdf - > fid ) ;
2013-10-22 15:17:19 +02:00
struct pci_dev * pdev = zdev ? zdev - > pdev : NULL ;
2013-11-15 13:56:08 +01:00
int ret ;
2012-11-29 14:34:48 +01:00
2013-10-22 15:17:19 +02:00
pr_info ( " %s: Event 0x%x reconfigured PCI function 0x%x \n " ,
pdev ? pci_name ( pdev ) : " n/a " , ccdf - > pec , ccdf - > fid ) ;
zpci_err ( " avail CCDF: \n " ) ;
zpci_err_hex ( ccdf , sizeof ( * ccdf ) ) ;
2012-11-29 14:34:48 +01:00
switch ( ccdf - > pec ) {
2013-11-15 13:56:08 +01:00
case 0x0301 : /* Standby -> Configured */
2014-04-16 16:09:23 +02:00
if ( ! zdev | | zdev - > state ! = ZPCI_FN_STATE_STANDBY )
2013-11-15 13:56:08 +01:00
break ;
zdev - > state = ZPCI_FN_STATE_CONFIGURED ;
2013-12-18 16:46:02 +01:00
zdev - > fh = ccdf - > fh ;
2013-11-15 13:56:08 +01:00
ret = zpci_enable_device ( zdev ) ;
if ( ret )
break ;
pci_rescan_bus ( zdev - > bus ) ;
2012-11-29 14:34:48 +01:00
break ;
2013-11-15 13:56:08 +01:00
case 0x0302 : /* Reserved -> Standby */
2014-04-16 16:09:23 +02:00
if ( ! zdev )
clp_add_pci_device ( ccdf - > fid , ccdf - > fh , 0 ) ;
2012-11-29 14:34:48 +01:00
break ;
2013-11-15 13:56:08 +01:00
case 0x0303 : /* Deconfiguration requested */
if ( pdev )
pci_stop_and_remove_bus_device ( pdev ) ;
ret = zpci_disable_device ( zdev ) ;
if ( ret )
break ;
ret = sclp_pci_deconfigure ( zdev - > fid ) ;
zpci_dbg ( 3 , " deconf fid:%x, rc:%d \n " , zdev - > fid , ret ) ;
if ( ! ret )
zdev - > state = ZPCI_FN_STATE_STANDBY ;
break ;
case 0x0304 : /* Configured -> Standby */
2013-12-12 17:53:11 +01:00
if ( pdev ) {
/* Give the driver a hint that the function is
* already unusable . */
pdev - > error_state = pci_channel_io_perm_failure ;
2013-11-15 13:56:08 +01:00
pci_stop_and_remove_bus_device ( pdev ) ;
2013-12-12 17:53:11 +01:00
}
2013-11-15 13:56:08 +01:00
2013-12-18 16:46:02 +01:00
zdev - > fh = ccdf - > fh ;
2013-11-15 13:56:08 +01:00
zpci_disable_device ( zdev ) ;
zdev - > state = ZPCI_FN_STATE_STANDBY ;
break ;
case 0x0306 : /* 0x308 or 0x302 for multiple devices */
2013-08-29 19:37:28 +02:00
clp_rescan_pci_devices ( ) ;
2012-11-29 14:34:48 +01:00
break ;
2013-11-15 13:56:08 +01:00
case 0x0308 : /* Standby -> Reserved */
2013-12-12 17:50:53 +01:00
if ( ! zdev )
break ;
2013-11-15 13:56:08 +01:00
pci_stop_root_bus ( zdev - > bus ) ;
pci_remove_root_bus ( zdev - > bus ) ;
break ;
2012-11-29 14:34:48 +01:00
default :
break ;
}
}
2013-12-12 17:48:32 +01:00
void zpci_event_availability ( void * data )
{
if ( zpci_is_enabled ( ) )
__zpci_event_availability ( data ) ;
}