Skip to content

Commit 0467cdd

Browse files
niklas88hcahca
authored andcommitted
s390/pci: Sort PCI functions prior to creating virtual busses
Instead of relying on the observed but not architected firmware behavior that PCI functions from the same card are listed in ascending RID order in clp_list_pci() ensure this by sorting. To allow for sorting separate the initial clp_list_pci() and creation of the virtual PCI busses. Note that fundamentally in our per-PCI function hotplug design non RID order of discovery is still possible. For example when the two PFs of a two port NIC are hotplugged after initial boot and in descending RID order. In this case the virtual PCI bus would be created by the second PF using that PF's UID as domain number instead of that of the first PF. Thus the domain number would then change from the UID of the second PF to that of the first PF on reboot but there is really nothing we can do about that since changing domain numbers at runtime seems even worse. This only impacts the domain number as the RIDs are consistent and thus even with just the second PF visible it will show up in the correct position on the virtual bus. Reviewed-by: Gerd Bayer <[email protected]> Signed-off-by: Niklas Schnelle <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent 8cf0b93 commit 0467cdd

File tree

4 files changed

+82
-17
lines changed

4 files changed

+82
-17
lines changed

arch/s390/include/asm/pci.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ struct zpci_dev {
130130
u16 vfn; /* virtual function number */
131131
u16 pchid; /* physical channel ID */
132132
u16 maxstbl; /* Maximum store block size */
133+
u16 rid; /* RID as supplied by firmware */
133134
u8 pfgid; /* function group ID */
134135
u8 pft; /* pci function type */
135136
u8 port;
@@ -210,12 +211,14 @@ extern struct airq_iv *zpci_aif_sbv;
210211
----------------------------------------------------------------------------- */
211212
/* Base stuff */
212213
struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
214+
int zpci_add_device(struct zpci_dev *zdev);
213215
int zpci_enable_device(struct zpci_dev *);
214216
int zpci_disable_device(struct zpci_dev *);
215217
int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh);
216218
int zpci_deconfigure_device(struct zpci_dev *zdev);
217219
void zpci_device_reserved(struct zpci_dev *zdev);
218220
bool zpci_is_device_configured(struct zpci_dev *zdev);
221+
int zpci_scan_devices(void);
219222

220223
int zpci_hot_reset_device(struct zpci_dev *zdev);
221224
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64, u8 *);
@@ -225,7 +228,7 @@ void zpci_update_fh(struct zpci_dev *zdev, u32 fh);
225228

226229
/* CLP */
227230
int clp_setup_writeback_mio(void);
228-
int clp_scan_pci_devices(void);
231+
int clp_scan_pci_devices(struct list_head *scan_list);
229232
int clp_query_pci_fn(struct zpci_dev *zdev);
230233
int clp_enable_fh(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as);
231234
int clp_disable_fh(struct zpci_dev *zdev, u32 *fh);

arch/s390/pci/pci.c

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/pci.h>
3030
#include <linux/printk.h>
3131
#include <linux/lockdep.h>
32+
#include <linux/list_sort.h>
3233

3334
#include <asm/isc.h>
3435
#include <asm/airq.h>
@@ -785,7 +786,6 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
785786
struct zpci_dev *zdev;
786787
int rc;
787788

788-
zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", fid, fh, state);
789789
zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
790790
if (!zdev)
791791
return ERR_PTR(-ENOMEM);
@@ -805,6 +805,19 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
805805
mutex_init(&zdev->fmb_lock);
806806
mutex_init(&zdev->kzdev_lock);
807807

808+
return zdev;
809+
810+
error:
811+
zpci_dbg(0, "crt fid:%x, rc:%d\n", fid, rc);
812+
kfree(zdev);
813+
return ERR_PTR(rc);
814+
}
815+
816+
int zpci_add_device(struct zpci_dev *zdev)
817+
{
818+
int rc;
819+
820+
zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", zdev->fid, zdev->fh, zdev->state);
808821
rc = zpci_init_iommu(zdev);
809822
if (rc)
810823
goto error;
@@ -816,15 +829,13 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
816829
spin_lock(&zpci_list_lock);
817830
list_add_tail(&zdev->entry, &zpci_list);
818831
spin_unlock(&zpci_list_lock);
819-
820-
return zdev;
832+
return 0;
821833

822834
error_destroy_iommu:
823835
zpci_destroy_iommu(zdev);
824836
error:
825-
zpci_dbg(0, "add fid:%x, rc:%d\n", fid, rc);
826-
kfree(zdev);
827-
return ERR_PTR(rc);
837+
zpci_dbg(0, "add fid:%x, rc:%d\n", zdev->fid, rc);
838+
return rc;
828839
}
829840

830841
bool zpci_is_device_configured(struct zpci_dev *zdev)
@@ -1082,6 +1093,49 @@ bool zpci_is_enabled(void)
10821093
return s390_pci_initialized;
10831094
}
10841095

1096+
static int zpci_cmp_rid(void *priv, const struct list_head *a,
1097+
const struct list_head *b)
1098+
{
1099+
struct zpci_dev *za = container_of(a, struct zpci_dev, entry);
1100+
struct zpci_dev *zb = container_of(b, struct zpci_dev, entry);
1101+
1102+
/*
1103+
* PCI functions without RID available maintain original order
1104+
* between themselves but sort before those with RID.
1105+
*/
1106+
if (za->rid == zb->rid)
1107+
return za->rid_available > zb->rid_available;
1108+
/*
1109+
* PCI functions with RID sort by RID ascending.
1110+
*/
1111+
return za->rid > zb->rid;
1112+
}
1113+
1114+
static void zpci_add_devices(struct list_head *scan_list)
1115+
{
1116+
struct zpci_dev *zdev, *tmp;
1117+
1118+
list_sort(NULL, scan_list, &zpci_cmp_rid);
1119+
list_for_each_entry_safe(zdev, tmp, scan_list, entry) {
1120+
list_del_init(&zdev->entry);
1121+
zpci_add_device(zdev);
1122+
}
1123+
}
1124+
1125+
int zpci_scan_devices(void)
1126+
{
1127+
LIST_HEAD(scan_list);
1128+
int rc;
1129+
1130+
rc = clp_scan_pci_devices(&scan_list);
1131+
if (rc)
1132+
return rc;
1133+
1134+
zpci_add_devices(&scan_list);
1135+
zpci_bus_scan_busses();
1136+
return 0;
1137+
}
1138+
10851139
static int __init pci_base_init(void)
10861140
{
10871141
int rc;
@@ -1111,10 +1165,9 @@ static int __init pci_base_init(void)
11111165
if (rc)
11121166
goto out_irq;
11131167

1114-
rc = clp_scan_pci_devices();
1168+
rc = zpci_scan_devices();
11151169
if (rc)
11161170
goto out_find;
1117-
zpci_bus_scan_busses();
11181171

11191172
s390_pci_initialized = 1;
11201173
return 0;

arch/s390/pci/pci_clp.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,10 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,
164164
zdev->port = response->port;
165165
zdev->uid = response->uid;
166166
zdev->fmb_length = sizeof(u32) * response->fmb_len;
167-
zdev->rid_available = response->rid_avail;
168167
zdev->is_physfn = response->is_physfn;
168+
zdev->rid_available = response->rid_avail;
169+
if (zdev->rid_available)
170+
zdev->rid = response->rid;
169171
if (!s390_pci_no_rid && zdev->rid_available)
170172
zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN;
171173

@@ -407,6 +409,7 @@ static int clp_find_pci(struct clp_req_rsp_list_pci *rrb, u32 fid,
407409

408410
static void __clp_add(struct clp_fh_list_entry *entry, void *data)
409411
{
412+
struct list_head *scan_list = data;
410413
struct zpci_dev *zdev;
411414

412415
if (!entry->vendor_id)
@@ -417,10 +420,11 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data)
417420
zpci_zdev_put(zdev);
418421
return;
419422
}
420-
zpci_create_device(entry->fid, entry->fh, entry->config_state);
423+
zdev = zpci_create_device(entry->fid, entry->fh, entry->config_state);
424+
list_add_tail(&zdev->entry, scan_list);
421425
}
422426

423-
int clp_scan_pci_devices(void)
427+
int clp_scan_pci_devices(struct list_head *scan_list)
424428
{
425429
struct clp_req_rsp_list_pci *rrb;
426430
int rc;
@@ -429,7 +433,7 @@ int clp_scan_pci_devices(void)
429433
if (!rrb)
430434
return -ENOMEM;
431435

432-
rc = clp_list_pci(rrb, NULL, __clp_add);
436+
rc = clp_list_pci(rrb, scan_list, __clp_add);
433437

434438
clp_free_block(rrb);
435439
return rc;

arch/s390/pci/pci_event.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
339339
zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
340340
if (IS_ERR(zdev))
341341
break;
342+
zpci_add_device(zdev);
342343
} else {
343344
/* the configuration request may be stale */
344345
if (zdev->state != ZPCI_FN_STATE_STANDBY)
@@ -348,10 +349,14 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
348349
zpci_scan_configured_device(zdev, ccdf->fh);
349350
break;
350351
case 0x0302: /* Reserved -> Standby */
351-
if (!zdev)
352-
zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
353-
else
352+
if (!zdev) {
353+
zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
354+
if (IS_ERR(zdev))
355+
break;
356+
zpci_add_device(zdev);
357+
} else {
354358
zpci_update_fh(zdev, ccdf->fh);
359+
}
355360
break;
356361
case 0x0303: /* Deconfiguration requested */
357362
if (zdev) {
@@ -380,7 +385,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
380385
break;
381386
case 0x0306: /* 0x308 or 0x302 for multiple devices */
382387
zpci_remove_reserved_devices();
383-
clp_scan_pci_devices();
388+
zpci_scan_devices();
384389
break;
385390
case 0x0308: /* Standby -> Reserved */
386391
if (!zdev)

0 commit comments

Comments
 (0)