Commit 17cdec96 authored by Niklas Schnelle's avatar Niklas Schnelle Committed by Vasily Gorbik
Browse files

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: default avatarNiklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: default avatarPeter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent d1eef1c6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 *);
+1 −1
Original line number Diff line number Diff line
@@ -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);
}
+29 −19
Original line number Diff line number Diff line
@@ -240,12 +240,14 @@ error:
}

/*
 * 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;