Skip to content

Commit 88fc10b

Browse files
author
CKI KWF Bot
committed
Merge: s390/pci: Fix immediate re-add of PCI function after remove
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1001 JIRA: https://issues.redhat.com/browse/RHEL-94944 commit ids: ``` c4a585e 42420c5 05a2538 d76f963 47c3978 4b1815a 774a1fa ``` This fix is urgent! Signed-off-by: Mete Durlu <mdurlu@redhat.com> Approved-by: Steve Best <sbest@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 8db5002 + 3cbfa66 commit 88fc10b

File tree

5 files changed

+61
-46
lines changed

5 files changed

+61
-46
lines changed

arch/s390/pci/pci.c

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
/* list of all detected zpci devices */
4545
static LIST_HEAD(zpci_list);
4646
static DEFINE_SPINLOCK(zpci_list_lock);
47+
static DEFINE_MUTEX(zpci_add_remove_lock);
4748

4849
static DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE);
4950
static DEFINE_SPINLOCK(zpci_domain_lock);
@@ -69,6 +70,15 @@ EXPORT_SYMBOL_GPL(zpci_aipb);
6970
struct airq_iv *zpci_aif_sbv;
7071
EXPORT_SYMBOL_GPL(zpci_aif_sbv);
7172

73+
void zpci_zdev_put(struct zpci_dev *zdev)
74+
{
75+
if (!zdev)
76+
return;
77+
mutex_lock(&zpci_add_remove_lock);
78+
kref_put_lock(&zdev->kref, zpci_release_device, &zpci_list_lock);
79+
mutex_unlock(&zpci_add_remove_lock);
80+
}
81+
7282
struct zpci_dev *get_zdev_by_fid(u32 fid)
7383
{
7484
struct zpci_dev *tmp, *zdev = NULL;
@@ -831,6 +841,7 @@ int zpci_add_device(struct zpci_dev *zdev)
831841
{
832842
int rc;
833843

844+
mutex_lock(&zpci_add_remove_lock);
834845
zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", zdev->fid, zdev->fh, zdev->state);
835846
rc = zpci_init_iommu(zdev);
836847
if (rc)
@@ -844,12 +855,14 @@ int zpci_add_device(struct zpci_dev *zdev)
844855
spin_lock(&zpci_list_lock);
845856
list_add_tail(&zdev->entry, &zpci_list);
846857
spin_unlock(&zpci_list_lock);
858+
mutex_unlock(&zpci_add_remove_lock);
847859
return 0;
848860

849861
error_destroy_iommu:
850862
zpci_destroy_iommu(zdev);
851863
error:
852864
zpci_dbg(0, "add fid:%x, rc:%d\n", zdev->fid, rc);
865+
mutex_unlock(&zpci_add_remove_lock);
853866
return rc;
854867
}
855868

@@ -919,60 +932,44 @@ int zpci_deconfigure_device(struct zpci_dev *zdev)
919932
* @zdev: the zpci_dev that was reserved
920933
*
921934
* Handle the case that a given zPCI function was reserved by another system.
922-
* After a call to this function the zpci_dev can not be found via
923-
* get_zdev_by_fid() anymore but may still be accessible via existing
924-
* references though it will not be functional anymore.
925935
*/
926936
void zpci_device_reserved(struct zpci_dev *zdev)
927937
{
928-
/*
929-
* Remove device from zpci_list as it is going away. This also
930-
* makes sure we ignore subsequent zPCI events for this device.
931-
*/
932-
spin_lock(&zpci_list_lock);
933-
list_del(&zdev->entry);
934-
spin_unlock(&zpci_list_lock);
938+
lockdep_assert_held(&zdev->state_lock);
939+
/* We may declare the device reserved multiple times */
940+
if (zdev->state == ZPCI_FN_STATE_RESERVED)
941+
return;
935942
zdev->state = ZPCI_FN_STATE_RESERVED;
936943
zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
944+
/*
945+
* The underlying device is gone. Allow the zdev to be freed
946+
* as soon as all other references are gone by accounting for
947+
* the removal as a dropped reference.
948+
*/
937949
zpci_zdev_put(zdev);
938950
}
939951

940952
void zpci_release_device(struct kref *kref)
941953
{
942954
struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
943-
int ret;
955+
956+
lockdep_assert_held(&zpci_add_remove_lock);
957+
WARN_ON(zdev->state != ZPCI_FN_STATE_RESERVED);
958+
/*
959+
* We already hold zpci_list_lock thanks to kref_put_lock().
960+
* This makes sure no new reference can be taken from the list.
961+
*/
962+
list_del(&zdev->entry);
963+
spin_unlock(&zpci_list_lock);
944964

945965
if (zdev->has_hp_slot)
946966
zpci_exit_slot(zdev);
947967

948-
if (zdev->zbus->bus)
949-
zpci_bus_remove_device(zdev, false);
950-
951-
if (zdev_enabled(zdev))
952-
zpci_disable_device(zdev);
968+
if (zdev->has_resources)
969+
zpci_cleanup_bus_resources(zdev);
953970

954-
switch (zdev->state) {
955-
case ZPCI_FN_STATE_CONFIGURED:
956-
ret = sclp_pci_deconfigure(zdev->fid);
957-
zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret);
958-
fallthrough;
959-
case ZPCI_FN_STATE_STANDBY:
960-
if (zdev->has_hp_slot)
961-
zpci_exit_slot(zdev);
962-
spin_lock(&zpci_list_lock);
963-
list_del(&zdev->entry);
964-
spin_unlock(&zpci_list_lock);
965-
zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
966-
fallthrough;
967-
case ZPCI_FN_STATE_RESERVED:
968-
if (zdev->has_resources)
969-
zpci_cleanup_bus_resources(zdev);
970-
zpci_bus_device_unregister(zdev);
971-
zpci_destroy_iommu(zdev);
972-
fallthrough;
973-
default:
974-
break;
975-
}
971+
zpci_bus_device_unregister(zdev);
972+
zpci_destroy_iommu(zdev);
976973
zpci_dbg(3, "rem fid:%x\n", zdev->fid);
977974
kfree_rcu(zdev, rcu);
978975
}

arch/s390/pci/pci_bus.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ int zpci_bus_scan_device(struct zpci_dev *zdev);
1717
void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);
1818

1919
void zpci_release_device(struct kref *kref);
20-
static inline void zpci_zdev_put(struct zpci_dev *zdev)
21-
{
22-
if (zdev)
23-
kref_put(&zdev->kref, zpci_release_device);
24-
}
20+
21+
void zpci_zdev_put(struct zpci_dev *zdev);
2522

2623
static inline void zpci_zdev_get(struct zpci_dev *zdev)
2724
{

arch/s390/pci/pci_clp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
427427
return;
428428
}
429429
zdev = zpci_create_device(entry->fid, entry->fh, entry->config_state);
430+
if (IS_ERR(zdev))
431+
return;
430432
list_add_tail(&zdev->entry, scan_list);
431433
}
432434

arch/s390/pci/pci_event.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,22 @@ static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
335335
zdev->state = ZPCI_FN_STATE_STANDBY;
336336
}
337337

338+
static void zpci_event_reappear(struct zpci_dev *zdev)
339+
{
340+
lockdep_assert_held(&zdev->state_lock);
341+
/*
342+
* The zdev is in the reserved state. This means that it was presumed to
343+
* go away but there are still undropped references. Now, the platform
344+
* announced its availability again. Bring back the lingering zdev
345+
* to standby. This is safe because we hold a temporary reference
346+
* now so that it won't go away. Account for the re-appearance of the
347+
* underlying device by incrementing the reference count.
348+
*/
349+
zdev->state = ZPCI_FN_STATE_STANDBY;
350+
zpci_zdev_get(zdev);
351+
zpci_dbg(1, "rea fid:%x, fh:%x\n", zdev->fid, zdev->fh);
352+
}
353+
338354
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
339355
{
340356
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
@@ -358,8 +374,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
358374
break;
359375
}
360376
} else {
377+
if (zdev->state == ZPCI_FN_STATE_RESERVED)
378+
zpci_event_reappear(zdev);
361379
/* the configuration request may be stale */
362-
if (zdev->state != ZPCI_FN_STATE_STANDBY)
380+
else if (zdev->state != ZPCI_FN_STATE_STANDBY)
363381
break;
364382
zdev->state = ZPCI_FN_STATE_CONFIGURED;
365383
}
@@ -375,6 +393,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
375393
break;
376394
}
377395
} else {
396+
if (zdev->state == ZPCI_FN_STATE_RESERVED)
397+
zpci_event_reappear(zdev);
378398
zpci_update_fh(zdev, ccdf->fh);
379399
}
380400
break;

drivers/pci/hotplug/s390_pci_hpc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,15 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
5959

6060
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
6161
if (pdev && pci_num_vf(pdev)) {
62-
pci_dev_put(pdev);
6362
rc = -EBUSY;
6463
goto out;
6564
}
6665

6766
rc = zpci_deconfigure_device(zdev);
6867
out:
69-
mutex_unlock(&zdev->state_lock);
7068
if (pdev)
7169
pci_dev_put(pdev);
70+
mutex_unlock(&zdev->state_lock);
7271
return rc;
7372
}
7473

0 commit comments

Comments
 (0)