2018-01-29 18:23:07 -06:00
// SPDX-License-Identifier: GPL-2.0+
2012-11-29 14:35:47 +01:00
/*
* PCI Hot Plug Controller Driver for System z
*
* Copyright 2012 IBM Corp .
*
* 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:35:47 +01:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/pci_hotplug.h>
2013-04-16 14:11:14 +02:00
# include <asm/pci_debug.h>
2012-11-29 14:35:47 +01:00
# include <asm/sclp.h>
# define SLOT_NAME_SIZE 10
static int enable_slot ( struct hotplug_slot * hotplug_slot )
{
2020-02-10 17:53:25 +01:00
struct zpci_dev * zdev = container_of ( hotplug_slot , struct zpci_dev ,
hotplug_slot ) ;
2021-03-26 13:58:48 +01:00
int rc ;
2012-11-29 14:35:47 +01:00
2023-11-10 16:27:06 +01:00
mutex_lock ( & zdev - > state_lock ) ;
if ( zdev - > state ! = ZPCI_FN_STATE_STANDBY ) {
rc = - EIO ;
goto out ;
}
2012-11-29 14:35:47 +01:00
2021-03-26 13:58:48 +01:00
rc = sclp_pci_configure ( zdev - > fid ) ;
zpci_dbg ( 3 , " conf fid:%x, rc:%d \n " , zdev - > fid , rc ) ;
if ( rc )
2023-11-10 16:27:06 +01:00
goto out ;
2021-03-26 13:58:48 +01:00
zdev - > state = ZPCI_FN_STATE_CONFIGURED ;
2023-11-10 16:27:06 +01:00
rc = zpci_scan_configured_device ( zdev , zdev - > fh ) ;
out :
mutex_unlock ( & zdev - > state_lock ) ;
return rc ;
2012-11-29 14:35:47 +01:00
}
static int disable_slot ( struct hotplug_slot * hotplug_slot )
{
2020-02-10 17:53:25 +01:00
struct zpci_dev * zdev = container_of ( hotplug_slot , struct zpci_dev ,
hotplug_slot ) ;
2023-11-10 16:27:06 +01:00
struct pci_dev * pdev = NULL ;
int rc ;
2012-11-29 14:35:47 +01:00
2023-11-10 16:27:06 +01:00
mutex_lock ( & zdev - > state_lock ) ;
if ( zdev - > state ! = ZPCI_FN_STATE_CONFIGURED ) {
rc = - EIO ;
goto out ;
}
2012-11-29 14:35:47 +01:00
2020-08-03 17:46:32 +02:00
pdev = pci_get_slot ( zdev - > zbus - > bus , zdev - > devfn ) ;
if ( pdev & & pci_num_vf ( pdev ) ) {
2016-01-29 15:13:30 +01:00
pci_dev_put ( pdev ) ;
2023-11-10 16:27:06 +01:00
rc = - EBUSY ;
goto out ;
2016-01-29 15:13:30 +01:00
}
2013-06-05 16:07:28 +02:00
2023-11-10 16:27:06 +01:00
rc = zpci_deconfigure_device ( zdev ) ;
out :
mutex_unlock ( & zdev - > state_lock ) ;
if ( pdev )
pci_dev_put ( pdev ) ;
return rc ;
2012-11-29 14:35:47 +01:00
}
2021-07-01 15:49:11 +02:00
static int reset_slot ( struct hotplug_slot * hotplug_slot , bool probe )
{
struct zpci_dev * zdev = container_of ( hotplug_slot , struct zpci_dev ,
hotplug_slot ) ;
2023-11-10 16:27:06 +01:00
int rc = - EIO ;
2021-07-01 15:49:11 +02:00
/*
2023-11-10 16:27:06 +01:00
* If we can ' t get the zdev - > state_lock the device state is
* currently undergoing a transition and we bail out - just
* the same as if the device ' s state is not configured at all .
2021-07-01 15:49:11 +02:00
*/
2023-11-10 16:27:06 +01:00
if ( ! mutex_trylock ( & zdev - > state_lock ) )
return rc ;
2021-07-01 15:49:11 +02:00
2023-11-10 16:27:06 +01:00
/* We can reset only if the function is configured */
if ( zdev - > state ! = ZPCI_FN_STATE_CONFIGURED )
goto out ;
if ( probe ) {
rc = 0 ;
goto out ;
}
2021-07-01 15:49:11 +02:00
2023-11-10 16:27:06 +01:00
rc = zpci_hot_reset_device ( zdev ) ;
out :
mutex_unlock ( & zdev - > state_lock ) ;
return rc ;
2021-07-01 15:49:11 +02:00
}
2012-11-29 14:35:47 +01:00
static int get_power_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
2020-02-10 17:53:25 +01:00
struct zpci_dev * zdev = container_of ( hotplug_slot , struct zpci_dev ,
hotplug_slot ) ;
2012-11-29 14:35:47 +01:00
2021-09-22 15:55:12 +02:00
* value = zpci_is_device_configured ( zdev ) ? 1 : 0 ;
2012-11-29 14:35:47 +01:00
return 0 ;
}
static int get_adapter_status ( struct hotplug_slot * hotplug_slot , u8 * value )
{
/* if the slot exits it always contains a function */
* value = 1 ;
return 0 ;
}
2018-09-08 09:59:01 +02:00
static const struct hotplug_slot_ops s390_hotplug_slot_ops = {
2012-11-29 14:35:47 +01:00
. enable_slot = enable_slot ,
. disable_slot = disable_slot ,
2021-07-01 15:49:11 +02:00
. reset_slot = reset_slot ,
2012-11-29 14:35:47 +01:00
. get_power_status = get_power_status ,
. get_adapter_status = get_adapter_status ,
} ;
2013-08-29 19:33:16 +02:00
int zpci_init_slot ( struct zpci_dev * zdev )
2012-11-29 14:35:47 +01:00
{
char name [ SLOT_NAME_SIZE ] ;
2020-03-23 10:45:43 +01:00
struct zpci_bus * zbus = zdev - > zbus ;
2012-11-29 14:35:47 +01:00
2020-02-10 17:53:25 +01:00
zdev - > hotplug_slot . ops = & s390_hotplug_slot_ops ;
2012-11-29 14:35:47 +01:00
snprintf ( name , SLOT_NAME_SIZE , " %08x " , zdev - > fid ) ;
2020-03-23 10:45:43 +01:00
return pci_hp_register ( & zdev - > hotplug_slot , zbus - > bus ,
2020-04-22 15:15:23 +02:00
zdev - > devfn , name ) ;
2012-11-29 14:35:47 +01:00
}
2013-08-29 19:33:16 +02:00
void zpci_exit_slot ( struct zpci_dev * zdev )
2012-11-29 14:35:47 +01:00
{
2020-02-10 17:53:25 +01:00
pci_hp_deregister ( & zdev - > hotplug_slot ) ;
2012-11-29 14:35:47 +01:00
}