mirror of https://gitee.com/openkylin/linux.git
s390/pci: improve pci hotplug
PCI hotplug events basically notify about the new state of a function. Unfortunately some hypervisors implement hotplug events in a way where it is not clear what the new state of the function should be. Use clp_get_state to find the current state of the function and handle accordingly. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
783684f1f6
commit
623bd44d3f
|
@ -158,6 +158,7 @@ extern const struct attribute_group *zpci_attr_groups[];
|
||||||
----------------------------------------------------------------------------- */
|
----------------------------------------------------------------------------- */
|
||||||
/* Base stuff */
|
/* Base stuff */
|
||||||
int zpci_create_device(struct zpci_dev *);
|
int zpci_create_device(struct zpci_dev *);
|
||||||
|
void zpci_remove_device(struct zpci_dev *zdev);
|
||||||
int zpci_enable_device(struct zpci_dev *);
|
int zpci_enable_device(struct zpci_dev *);
|
||||||
int zpci_disable_device(struct zpci_dev *);
|
int zpci_disable_device(struct zpci_dev *);
|
||||||
void zpci_stop_device(struct zpci_dev *);
|
void zpci_stop_device(struct zpci_dev *);
|
||||||
|
|
|
@ -855,6 +855,15 @@ void zpci_stop_device(struct zpci_dev *zdev)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(zpci_stop_device);
|
EXPORT_SYMBOL_GPL(zpci_stop_device);
|
||||||
|
|
||||||
|
void zpci_remove_device(struct zpci_dev *zdev)
|
||||||
|
{
|
||||||
|
if (!zdev->bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_stop_root_bus(zdev->bus);
|
||||||
|
pci_remove_root_bus(zdev->bus);
|
||||||
|
}
|
||||||
|
|
||||||
int zpci_report_error(struct pci_dev *pdev,
|
int zpci_report_error(struct pci_dev *pdev,
|
||||||
struct zpci_report_error_header *report)
|
struct zpci_report_error_header *report)
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||||
{
|
{
|
||||||
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
|
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
|
||||||
struct pci_dev *pdev = NULL;
|
struct pci_dev *pdev = NULL;
|
||||||
|
enum zpci_state state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (zdev)
|
if (zdev)
|
||||||
|
@ -108,6 +109,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||||
clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
|
clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
|
||||||
break;
|
break;
|
||||||
case 0x0303: /* Deconfiguration requested */
|
case 0x0303: /* Deconfiguration requested */
|
||||||
|
if (!zdev)
|
||||||
|
break;
|
||||||
if (pdev)
|
if (pdev)
|
||||||
pci_stop_and_remove_bus_device_locked(pdev);
|
pci_stop_and_remove_bus_device_locked(pdev);
|
||||||
|
|
||||||
|
@ -121,7 +124,9 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||||
zdev->state = ZPCI_FN_STATE_STANDBY;
|
zdev->state = ZPCI_FN_STATE_STANDBY;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x0304: /* Configured -> Standby */
|
case 0x0304: /* Configured -> Standby|Reserved */
|
||||||
|
if (!zdev)
|
||||||
|
break;
|
||||||
if (pdev) {
|
if (pdev) {
|
||||||
/* Give the driver a hint that the function is
|
/* Give the driver a hint that the function is
|
||||||
* already unusable. */
|
* already unusable. */
|
||||||
|
@ -132,6 +137,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||||
zdev->fh = ccdf->fh;
|
zdev->fh = ccdf->fh;
|
||||||
zpci_disable_device(zdev);
|
zpci_disable_device(zdev);
|
||||||
zdev->state = ZPCI_FN_STATE_STANDBY;
|
zdev->state = ZPCI_FN_STATE_STANDBY;
|
||||||
|
if (!clp_get_state(ccdf->fid, &state) &&
|
||||||
|
state == ZPCI_FN_STATE_RESERVED) {
|
||||||
|
zpci_remove_device(zdev);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0306: /* 0x308 or 0x302 for multiple devices */
|
case 0x0306: /* 0x308 or 0x302 for multiple devices */
|
||||||
clp_rescan_pci_devices();
|
clp_rescan_pci_devices();
|
||||||
|
@ -139,8 +148,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||||
case 0x0308: /* Standby -> Reserved */
|
case 0x0308: /* Standby -> Reserved */
|
||||||
if (!zdev)
|
if (!zdev)
|
||||||
break;
|
break;
|
||||||
pci_stop_root_bus(zdev->bus);
|
zpci_remove_device(zdev);
|
||||||
pci_remove_root_bus(zdev->bus);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue