Skip to content

Commit 4fe2049

Browse files
niklas88Vasily Gorbik
authored andcommitted
s390/pci: refresh function handle in iomap
The function handle of a PCI function is updated when disabling or enabling it as well as when the function's availability changes or it enters the error state. Until now this only occurred either while there is no struct pci_dev associated with the function yet or the function became unavailable. This meant that leaving a stale function handle in the iomap either didn't happen because there was no iomap yet or it lead to errors on PCI access but so would the correct disabled function handle. In the future a CLP Set PCI Function Disable/Enable cycle during PCI device recovery may be done while the device is bound to a driver. In this case we must update the iomap associated with the now-stale function handle to ensure that the resulting zPCI instruction references an accurate function handle. Since the function handle is accessed by the PCI accessor helpers without locking use READ_ONCE()/WRITE_ONCE() to mark this access and prevent compiler optimizations that would move the load/store. With that infrastructure in place let's also properly update the function handle in the existing cases. This makes sure that in the future debugging of a zPCI function access through the handle will show an up to date handle reducing the chance of confusion. Also it makes sure we have one single place where a zPCI function handle is updated after initialization. Reviewed-by: Pierre Morel <[email protected]> Reviewed-by: Matthew Rosato <[email protected]> Signed-off-by: Niklas Schnelle <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]>
1 parent 0b707e5 commit 4fe2049

File tree

4 files changed

+38
-9
lines changed

4 files changed

+38
-9
lines changed

arch/s390/include/asm/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ bool zpci_is_device_configured(struct zpci_dev *zdev);
213213
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
214214
int zpci_unregister_ioat(struct zpci_dev *, u8);
215215
void zpci_remove_reserved_devices(void);
216+
void zpci_update_fh(struct zpci_dev *zdev, u32 fh);
216217

217218
/* CLP */
218219
int clp_setup_writeback_mio(void);

arch/s390/pci/pci.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,34 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)
481481
spin_unlock(&zpci_iomap_lock);
482482
}
483483

484+
static void zpci_do_update_iomap_fh(struct zpci_dev *zdev, u32 fh)
485+
{
486+
int bar, idx;
487+
488+
spin_lock(&zpci_iomap_lock);
489+
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
490+
if (!zdev->bars[bar].size)
491+
continue;
492+
idx = zdev->bars[bar].map_idx;
493+
if (!zpci_iomap_start[idx].count)
494+
continue;
495+
WRITE_ONCE(zpci_iomap_start[idx].fh, zdev->fh);
496+
}
497+
spin_unlock(&zpci_iomap_lock);
498+
}
499+
500+
void zpci_update_fh(struct zpci_dev *zdev, u32 fh)
501+
{
502+
if (!fh || zdev->fh == fh)
503+
return;
504+
505+
zdev->fh = fh;
506+
if (zpci_use_mio(zdev))
507+
return;
508+
if (zdev->has_resources && zdev_enabled(zdev))
509+
zpci_do_update_iomap_fh(zdev, fh);
510+
}
511+
484512
static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start,
485513
unsigned long size, unsigned long flags)
486514
{
@@ -668,7 +696,7 @@ int zpci_enable_device(struct zpci_dev *zdev)
668696
if (clp_enable_fh(zdev, &fh, ZPCI_NR_DMA_SPACES))
669697
rc = -EIO;
670698
else
671-
zdev->fh = fh;
699+
zpci_update_fh(zdev, fh);
672700
return rc;
673701
}
674702

@@ -679,14 +707,14 @@ int zpci_disable_device(struct zpci_dev *zdev)
679707

680708
cc = clp_disable_fh(zdev, &fh);
681709
if (!cc) {
682-
zdev->fh = fh;
710+
zpci_update_fh(zdev, fh);
683711
} else if (cc == CLP_RC_SETPCIFN_ALRDY) {
684712
pr_info("Disabling PCI function %08x had no effect as it was already disabled\n",
685713
zdev->fid);
686714
/* Function is already disabled - update handle */
687715
rc = clp_refresh_fh(zdev->fid, &fh);
688716
if (!rc) {
689-
zdev->fh = fh;
717+
zpci_update_fh(zdev, fh);
690718
rc = -EINVAL;
691719
}
692720
} else {
@@ -776,7 +804,7 @@ int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh)
776804
{
777805
int rc;
778806

779-
zdev->fh = fh;
807+
zpci_update_fh(zdev, fh);
780808
/* the PCI function will be scanned once function 0 appears */
781809
if (!zdev->zbus->bus)
782810
return 0;

arch/s390/pci/pci_event.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void zpci_event_error(void *data)
7878

7979
static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
8080
{
81-
zdev->fh = fh;
81+
zpci_update_fh(zdev, fh);
8282
/* Give the driver a hint that the function is
8383
* already unusable.
8484
*/
@@ -121,7 +121,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
121121
if (!zdev)
122122
zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
123123
else
124-
zdev->fh = ccdf->fh;
124+
zpci_update_fh(zdev, ccdf->fh);
125125
break;
126126
case 0x0303: /* Deconfiguration requested */
127127
if (zdev) {
@@ -130,7 +130,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
130130
*/
131131
if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
132132
break;
133-
zdev->fh = ccdf->fh;
133+
zpci_update_fh(zdev, ccdf->fh);
134134
zpci_deconfigure_device(zdev);
135135
}
136136
break;

arch/s390/pci/pci_insn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr,
163163
unsigned long len)
164164
{
165165
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
166-
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
166+
u64 req = ZPCI_CREATE_REQ(READ_ONCE(entry->fh), entry->bar, len);
167167

168168
return __zpci_load(data, req, ZPCI_OFFSET(addr));
169169
}
@@ -244,7 +244,7 @@ static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data,
244244
unsigned long len)
245245
{
246246
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];
247-
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, len);
247+
u64 req = ZPCI_CREATE_REQ(READ_ONCE(entry->fh), entry->bar, len);
248248

249249
return __zpci_store(data, req, ZPCI_OFFSET(addr));
250250
}

0 commit comments

Comments
 (0)