Skip to content

Commit c6f1ea1

Browse files
committed
Merge: s390/pci: Fix immediate re-add of PCI function after remove
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6968 JIRA: https://issues.redhat.com/browse/RHEL-94952 Depends: !6695 commit ids: ``` 0d48566 # included via !6695 bcb5d6c # included via !6695 6ee600b # included via !6695 c4a585e # included via !6695 42420c5 05a2538 # included via !6695 d76f963 47c3978 4b1815a 774a1fa ``` This fix is urgent! Signed-off-by: Mete Durlu <mdurlu@redhat.com> Approved-by: Tony Camuso <tcamuso@redhat.com> Approved-by: Thomas Huth <thuth@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents ee100f3 + a2b51a3 commit c6f1ea1

File tree

5 files changed

+55
-23
lines changed

5 files changed

+55
-23
lines changed

arch/s390/pci/pci.c

Lines changed: 29 additions & 16 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,35 +932,35 @@ 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);
943955

956+
lockdep_assert_held(&zpci_add_remove_lock);
944957
WARN_ON(zdev->state != ZPCI_FN_STATE_RESERVED);
945-
946-
if (zdev->zbus->bus)
947-
zpci_bus_remove_device(zdev, false);
948-
949-
if (zdev_enabled(zdev))
950-
zpci_disable_device(zdev);
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);
951964

952965
if (zdev->has_hp_slot)
953966
zpci_exit_slot(zdev);

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
@@ -423,6 +423,8 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
423423
return;
424424
}
425425
zdev = zpci_create_device(entry->fid, entry->fh, entry->config_state);
426+
if (IS_ERR(zdev))
427+
return;
426428
list_add_tail(&zdev->entry, scan_list);
427429
}
428430

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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
6565

6666
rc = zpci_deconfigure_device(zdev);
6767
out:
68-
mutex_unlock(&zdev->state_lock);
6968
if (pdev)
7069
pci_dev_put(pdev);
70+
mutex_unlock(&zdev->state_lock);
7171
return rc;
7272
}
7373

0 commit comments

Comments
 (0)