mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
s390/pci: Recover handle in clp_set_pci_fn()
When we try to recover a PCI function using echo 1 > /sys/bus/pci/devices/<id>/recover or manually with echo 1 > /sys/bus/pci/devices/<id>/remove echo 0 > /sys/bus/pci/slots/<slot>/power echo 1 > /sys/bus/pci/slots/<slot>/power clp_disable_fn() / clp_enable_fn() call clp_set_pci_fn() to first disable and then reenable the function. When the function is already in the requested state we may be left with an invalid function handle. To get a new valid handle we do a clp_list_pci() call. For this we need both the function ID and function handle in clp_set_pci_fn() so pass the zdev and get both. To simplify things also pull setting the refreshed function handle into clp_set_pci_fn() Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
d1eef1c619
commit
17cdec960c
3 changed files with 31 additions and 21 deletions
|
@ -180,7 +180,7 @@ void zpci_remove_reserved_devices(void);
|
|||
/* CLP */
|
||||
int clp_scan_pci_devices(void);
|
||||
int clp_rescan_pci_devices(void);
|
||||
int clp_rescan_pci_devices_simple(void);
|
||||
int clp_rescan_pci_devices_simple(u32 *fid);
|
||||
int clp_add_pci_device(u32, u32, int);
|
||||
int clp_enable_fh(struct zpci_dev *, u8);
|
||||
int clp_disable_fh(struct zpci_dev *);
|
||||
|
|
|
@ -939,5 +939,5 @@ subsys_initcall_sync(pci_base_init);
|
|||
void zpci_rescan(void)
|
||||
{
|
||||
if (zpci_is_enabled())
|
||||
clp_rescan_pci_devices_simple();
|
||||
clp_rescan_pci_devices_simple(NULL);
|
||||
}
|
||||
|
|
|
@ -240,12 +240,14 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)
|
|||
}
|
||||
|
||||
/*
|
||||
* Enable/Disable a given PCI function defined by its function handle.
|
||||
* Enable/Disable a given PCI function and update its function handle if
|
||||
* necessary
|
||||
*/
|
||||
static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
|
||||
static int clp_set_pci_fn(struct zpci_dev *zdev, u8 nr_dma_as, u8 command)
|
||||
{
|
||||
struct clp_req_rsp_set_pci *rrb;
|
||||
int rc, retries = 100;
|
||||
u32 fid = zdev->fid;
|
||||
|
||||
rrb = clp_alloc_block(GFP_KERNEL);
|
||||
if (!rrb)
|
||||
|
@ -256,7 +258,7 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
|
|||
rrb->request.hdr.len = sizeof(rrb->request);
|
||||
rrb->request.hdr.cmd = CLP_SET_PCI_FN;
|
||||
rrb->response.hdr.len = sizeof(rrb->response);
|
||||
rrb->request.fh = *fh;
|
||||
rrb->request.fh = zdev->fh;
|
||||
rrb->request.oc = command;
|
||||
rrb->request.ndas = nr_dma_as;
|
||||
|
||||
|
@ -269,12 +271,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
|
|||
}
|
||||
} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
|
||||
|
||||
if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
|
||||
*fh = rrb->response.fh;
|
||||
else {
|
||||
if (rc || rrb->response.hdr.rsp != CLP_RC_OK) {
|
||||
zpci_err("Set PCI FN:\n");
|
||||
zpci_err_clp(rrb->response.hdr.rsp, rc);
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) {
|
||||
zdev->fh = rrb->response.fh;
|
||||
} else if (!rc && rrb->response.hdr.rsp == CLP_RC_SETPCIFN_ALRDY &&
|
||||
rrb->response.fh == 0) {
|
||||
/* Function is already in desired state - update handle */
|
||||
rc = clp_rescan_pci_devices_simple(&fid);
|
||||
}
|
||||
clp_free_block(rrb);
|
||||
return rc;
|
||||
|
@ -282,18 +289,17 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
|
|||
|
||||
int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
|
||||
{
|
||||
u32 fh = zdev->fh;
|
||||
int rc;
|
||||
|
||||
rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
|
||||
zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
|
||||
rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_PCI_FN);
|
||||
zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
zdev->fh = fh;
|
||||
if (zpci_use_mio(zdev)) {
|
||||
rc = clp_set_pci_fn(&fh, nr_dma_as, CLP_SET_ENABLE_MIO);
|
||||
zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
|
||||
rc = clp_set_pci_fn(zdev, nr_dma_as, CLP_SET_ENABLE_MIO);
|
||||
zpci_dbg(3, "ena mio fid:%x, fh:%x, rc:%d\n",
|
||||
zdev->fid, zdev->fh, rc);
|
||||
if (rc)
|
||||
clp_disable_fh(zdev);
|
||||
}
|
||||
|
@ -309,11 +315,8 @@ int clp_disable_fh(struct zpci_dev *zdev)
|
|||
if (!zdev_enabled(zdev))
|
||||
return 0;
|
||||
|
||||
rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
|
||||
rc = clp_set_pci_fn(zdev, 0, CLP_SET_DISABLE_PCI_FN);
|
||||
zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, fh, rc);
|
||||
if (!rc)
|
||||
zdev->fh = fh;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -370,10 +373,14 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
|
|||
static void __clp_update(struct clp_fh_list_entry *entry, void *data)
|
||||
{
|
||||
struct zpci_dev *zdev;
|
||||
u32 *fid = data;
|
||||
|
||||
if (!entry->vendor_id)
|
||||
return;
|
||||
|
||||
if (fid && *fid != entry->fid)
|
||||
return;
|
||||
|
||||
zdev = get_zdev_by_fid(entry->fid);
|
||||
if (!zdev)
|
||||
return;
|
||||
|
@ -413,7 +420,10 @@ int clp_rescan_pci_devices(void)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int clp_rescan_pci_devices_simple(void)
|
||||
/* Rescan PCI functions and refresh function handles. If fid is non-NULL only
|
||||
* refresh the handle of the function matching @fid
|
||||
*/
|
||||
int clp_rescan_pci_devices_simple(u32 *fid)
|
||||
{
|
||||
struct clp_req_rsp_list_pci *rrb;
|
||||
int rc;
|
||||
|
@ -422,7 +432,7 @@ int clp_rescan_pci_devices_simple(void)
|
|||
if (!rrb)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = clp_list_pci(rrb, NULL, __clp_update);
|
||||
rc = clp_list_pci(rrb, fid, __clp_update);
|
||||
|
||||
clp_free_block(rrb);
|
||||
return rc;
|
||||
|
|
Loading…
Reference in a new issue