Skip to content

Commit 38d42a6

Browse files
committed
Merge branch 'pci/resource'
- Use pci_resource_n() to simplify BAR/window resource lookup (Ilpo Järvinen) - Fix typo that repeatedly distributed resources to a bridge instead of iterating over subordinate bridges, which resulted in too little space to assign some BARs (Kai-Heng Feng) - Relax bridge window tail sizing for optional resources, e.g., IOV BARs, to avoid failures when removing and re-adding devices (Ilpo Järvinen) - Fix a double counting error for I/O resources, as we previously did for memory resources (Ilpo Järvinen) - Use resource_set_{range,size}() helpers in more places (Ilpo Järvinen) - Add pci_resource_is_iov() to identify IOV resources (Ilpo Järvinen) - Add pci_resource_num() to look up the BAR number from the resource pointer (Ilpo Järvinen) - Add restore_dev_resource() to simplify code that resources saved device resources (Ilpo Järvinen) - Allow drivers to enable devices even if we haven't assigned optional IOV resources to them (Ilpo Järvinen) - Improve debug output during resource reallocation (Ilpo Järvinen) - Rework handling of optional resources (IOV BARs, ROMs) to reduce failures if we can't allocate them (Ilpo Järvinen) - Move declarations of pci_rescan_bus_bridge_resize(), pci_reassign_bridge_resources(), and CardBus-related sizes from include/linux/pci.h to drivers/pci/pci.h since they're not used outside the PCI core (Ilpo Järvinen) - Make pci_setup_bridge() static (Ilpo Järvinen) - Fix a NULL dereference in the SR-IOV VF creation error path (Shay Drory) - Fix s390 mmio_read/write syscalls, which didn't cause page faults in some cases, which broke vfio-pci lazy mapping on first access (Niklas Schnelle) - Add pdev->non_mappable_bars to replace CONFIG_VFIO_PCI_MMAP, which was disabled only for s390 (Niklas Schnelle) - Support mmap of PCI resources on s390 except for ISM devices (Niklas Schnelle) * pci/resource: s390/pci: Support mmap() of PCI resources except for ISM devices s390/pci: Introduce pdev->non_mappable_bars and replace VFIO_PCI_MMAP s390/pci: Fix s390_mmio_read/write syscall page fault handling PCI: Fix NULL dereference in SR-IOV VF creation error path PCI: Move cardbus IO size declarations into pci/pci.h PCI: Make pci_setup_bridge() static PCI: Move resource reassignment func declarations into pci/pci.h PCI: Move pci_rescan_bus_bridge_resize() declaration to pci/pci.h PCI: Fix BAR resizing when VF BARs are assigned PCI: Do not claim to release resource falsely PCI: Increase Resizable BAR support from 512 GB to 128 TB PCI: Rework optional resource handling PCI: Perform reset_resource() and build fail list in sync PCI: Use res->parent to check if resource is assigned PCI: Add debug print when releasing resources before retry PCI: Indicate optional resource assignment failures PCI: Always have realloc_head in __assign_resources_sorted() PCI: Extend enable to check for any optional resource PCI: Add restore_dev_resource() PCI: Remove incorrect comment from pci_reassign_resource() PCI: Consolidate assignment loop next round preparation PCI: Rename retval to ret PCI: Use while loop and break instead of gotos PCI: Refactor pdev_sort_resources() & __dev_sort_resources() PCI: Converge return paths in __assign_resources_sorted() PCI: Add dev & res local variables to resource assignment funcs PCI: Add pci_resource_num() helper PCI: Check resource_size() separately PCI: Add pci_resource_is_iov() to identify IOV resources PCI: Use resource_set_{range,size}() helpers PCI: Use SZ_* instead of literals in setup-bus.c PCI: Fix old_size lower bound in calculate_iosize() too PCI: Allow relaxed bridge window tail sizing for optional resources PCI: Simplify size1 assignment logic PCI: Use min_align, not unrelated add_align, for size0 PCI: Remove add_align overwrite unrelated to size0 PCI: Use downstream bridges for distributing resources PCI: Cleanup dev->resource + resno to use pci_resource_n()
2 parents a7a8e79 + aa9f168 commit 38d42a6

File tree

19 files changed

+476
-310
lines changed

19 files changed

+476
-310
lines changed

arch/s390/Kconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ config AUDIT_ARCH
4141
config NO_IOPORT_MAP
4242
def_bool y
4343

44-
config PCI_QUIRKS
45-
def_bool n
46-
4744
config ARCH_SUPPORTS_UPROBES
4845
def_bool y
4946

@@ -258,6 +255,7 @@ config S390
258255
select PCI_DOMAINS if PCI
259256
select PCI_MSI if PCI
260257
select PCI_MSI_ARCH_FALLBACKS if PCI_MSI
258+
select PCI_QUIRKS if PCI
261259
select SPARSE_IRQ
262260
select SWIOTLB
263261
select SYSCTL_EXCEPTION_TRACE

arch/s390/include/asm/pci.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include <asm/pci_insn.h>
1212
#include <asm/sclp.h>
1313

14+
#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
15+
#define arch_can_pci_mmap_wc() 1
16+
1417
#define PCIBIOS_MIN_IO 0x1000
1518
#define PCIBIOS_MIN_MEM 0x10000000
1619

arch/s390/pci/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
obj-$(CONFIG_PCI) += pci.o pci_irq.o pci_clp.o \
77
pci_event.o pci_debug.o pci_insn.o pci_mmio.o \
8-
pci_bus.o pci_kvm_hook.o pci_report.o
8+
pci_bus.o pci_kvm_hook.o pci_report.o pci_fixup.o
99
obj-$(CONFIG_PCI_IOV) += pci_iov.o
1010
obj-$(CONFIG_SYSFS) += pci_sysfs.o

arch/s390/pci/pci_fixup.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Exceptions for specific devices,
4+
*
5+
* Copyright IBM Corp. 2025
6+
*
7+
* Author(s):
8+
* Niklas Schnelle <[email protected]>
9+
*/
10+
#include <linux/pci.h>
11+
12+
static void zpci_ism_bar_no_mmap(struct pci_dev *pdev)
13+
{
14+
/*
15+
* ISM's BAR is special. Drivers written for ISM know
16+
* how to handle this but others need to be aware of their
17+
* special nature e.g. to prevent attempts to mmap() it.
18+
*/
19+
pdev->non_mappable_bars = 1;
20+
}
21+
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_IBM,
22+
PCI_DEVICE_ID_IBM_ISM,
23+
zpci_ism_bar_no_mmap);

arch/s390/pci/pci_mmio.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,12 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
175175
args.address = mmio_addr;
176176
args.vma = vma;
177177
ret = follow_pfnmap_start(&args);
178-
if (ret)
179-
goto out_unlock_mmap;
178+
if (ret) {
179+
fixup_user_fault(current->mm, mmio_addr, FAULT_FLAG_WRITE, NULL);
180+
ret = follow_pfnmap_start(&args);
181+
if (ret)
182+
goto out_unlock_mmap;
183+
}
180184

181185
io_addr = (void __iomem *)((args.pfn << PAGE_SHIFT) |
182186
(mmio_addr & ~PAGE_MASK));
@@ -315,14 +319,18 @@ SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
315319
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
316320
goto out_unlock_mmap;
317321
ret = -EACCES;
318-
if (!(vma->vm_flags & VM_WRITE))
322+
if (!(vma->vm_flags & VM_READ))
319323
goto out_unlock_mmap;
320324

321325
args.vma = vma;
322326
args.address = mmio_addr;
323327
ret = follow_pfnmap_start(&args);
324-
if (ret)
325-
goto out_unlock_mmap;
328+
if (ret) {
329+
fixup_user_fault(current->mm, mmio_addr, 0, NULL);
330+
ret = follow_pfnmap_start(&args);
331+
if (ret)
332+
goto out_unlock_mmap;
333+
}
326334

327335
io_addr = (void __iomem *)((args.pfn << PAGE_SHIFT) |
328336
(mmio_addr & ~PAGE_MASK));

drivers/pci/iov.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -285,23 +285,16 @@ const struct attribute_group sriov_vf_dev_attr_group = {
285285
.is_visible = sriov_vf_attrs_are_visible,
286286
};
287287

288-
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
288+
static struct pci_dev *pci_iov_scan_device(struct pci_dev *dev, int id,
289+
struct pci_bus *bus)
289290
{
290-
int i;
291-
int rc = -ENOMEM;
292-
u64 size;
293-
struct pci_dev *virtfn;
294-
struct resource *res;
295291
struct pci_sriov *iov = dev->sriov;
296-
struct pci_bus *bus;
297-
298-
bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
299-
if (!bus)
300-
goto failed;
292+
struct pci_dev *virtfn;
293+
int rc;
301294

302295
virtfn = pci_alloc_dev(bus);
303296
if (!virtfn)
304-
goto failed0;
297+
return ERR_PTR(-ENOMEM);
305298

306299
virtfn->devfn = pci_iov_virtfn_devfn(dev, id);
307300
virtfn->vendor = dev->vendor;
@@ -314,8 +307,35 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
314307
pci_read_vf_config_common(virtfn);
315308

316309
rc = pci_setup_device(virtfn);
317-
if (rc)
318-
goto failed1;
310+
if (rc) {
311+
pci_dev_put(dev);
312+
pci_bus_put(virtfn->bus);
313+
kfree(virtfn);
314+
return ERR_PTR(rc);
315+
}
316+
317+
return virtfn;
318+
}
319+
320+
int pci_iov_add_virtfn(struct pci_dev *dev, int id)
321+
{
322+
struct pci_bus *bus;
323+
struct pci_dev *virtfn;
324+
struct resource *res;
325+
int rc, i;
326+
u64 size;
327+
328+
bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
329+
if (!bus) {
330+
rc = -ENOMEM;
331+
goto failed;
332+
}
333+
334+
virtfn = pci_iov_scan_device(dev, id, bus);
335+
if (IS_ERR(virtfn)) {
336+
rc = PTR_ERR(virtfn);
337+
goto failed0;
338+
}
319339

320340
virtfn->dev.parent = dev->dev.parent;
321341
virtfn->multifunction = 0;
@@ -952,7 +972,7 @@ void pci_iov_remove(struct pci_dev *dev)
952972
void pci_iov_update_resource(struct pci_dev *dev, int resno)
953973
{
954974
struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL;
955-
struct resource *res = dev->resource + resno;
975+
struct resource *res = pci_resource_n(dev, resno);
956976
int vf_bar = resno - PCI_IOV_RESOURCES;
957977
struct pci_bus_region region;
958978
u16 cmd;

drivers/pci/pci-sysfs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,10 @@ static int pci_create_resource_files(struct pci_dev *pdev)
12571257
int i;
12581258
int retval;
12591259

1260+
/* Skip devices with non-mappable BARs */
1261+
if (pdev->non_mappable_bars)
1262+
return 0;
1263+
12601264
/* Expose the PCI resources from this device as files */
12611265
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
12621266

@@ -1556,7 +1560,7 @@ static ssize_t __resource_resize_store(struct device *dev, int n,
15561560
return -EINVAL;
15571561

15581562
device_lock(dev);
1559-
if (dev->driver) {
1563+
if (dev->driver || pci_num_vf(pdev)) {
15601564
ret = -EBUSY;
15611565
goto unlock;
15621566
}
@@ -1578,7 +1582,7 @@ static ssize_t __resource_resize_store(struct device *dev, int n,
15781582

15791583
pci_remove_resource_files(pdev);
15801584

1581-
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
1585+
for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
15821586
if (pci_resource_len(pdev, i) &&
15831587
pci_resource_flags(pdev, i) == flags)
15841588
pci_release_resource(pdev, i);

drivers/pci/pci.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1892,7 +1892,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
18921892

18931893
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
18941894
bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
1895-
res = pdev->resource + bar_idx;
1895+
res = pci_resource_n(pdev, bar_idx);
18961896
size = pci_rebar_bytes_to_size(resource_size(res));
18971897
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
18981898
ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
@@ -3770,7 +3770,7 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
37703770
* @bar: BAR to query
37713771
*
37723772
* Get the possible sizes of a resizable BAR as bitmask defined in the spec
3773-
* (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable.
3773+
* (bit 0=1MB, bit 31=128TB). Returns 0 if BAR isn't resizable.
37743774
*/
37753775
u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
37763776
{
@@ -3818,7 +3818,7 @@ int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
38183818
* pci_rebar_set_size - set a new size for a BAR
38193819
* @pdev: PCI device
38203820
* @bar: BAR to set size to
3821-
* @size: new size as defined in the spec (0=1MB, 19=512GB)
3821+
* @size: new size as defined in the spec (0=1MB, 31=128TB)
38223822
*
38233823
* Set the new size of a BAR as defined in the spec.
38243824
* Returns zero if resizing was successful, error code otherwise.

drivers/pci/pci.h

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ extern unsigned long pci_hotplug_io_size;
283283
extern unsigned long pci_hotplug_mmio_size;
284284
extern unsigned long pci_hotplug_mmio_pref_size;
285285
extern unsigned long pci_hotplug_bus_size;
286+
extern unsigned long pci_cardbus_io_size;
287+
extern unsigned long pci_cardbus_mem_size;
286288

287289
/**
288290
* pci_match_one_device - Tell if a PCI device structure has a matching
@@ -326,6 +328,10 @@ enum pci_bar_type {
326328
struct device *pci_get_host_bridge_device(struct pci_dev *dev);
327329
void pci_put_host_bridge_device(struct device *dev);
328330

331+
unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
332+
int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type);
333+
int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
334+
329335
int pci_configure_extended_tags(struct pci_dev *dev, void *ign);
330336
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
331337
int rrs_timeout);
@@ -350,6 +356,29 @@ void pci_walk_bus_locked(struct pci_bus *top,
350356
void *userdata);
351357

352358
const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
359+
bool pci_resource_is_optional(const struct pci_dev *dev, int resno);
360+
361+
/**
362+
* pci_resource_num - Reverse lookup resource number from device resources
363+
* @dev: PCI device
364+
* @res: Resource to lookup index for (MUST be a @dev's resource)
365+
*
366+
* Perform reverse lookup to determine the resource number for @res within
367+
* @dev resource array. NOTE: The caller is responsible for ensuring @res is
368+
* among @dev's resources!
369+
*
370+
* Returns: resource number.
371+
*/
372+
static inline int pci_resource_num(const struct pci_dev *dev,
373+
const struct resource *res)
374+
{
375+
int resno = res - &dev->resource[0];
376+
377+
/* Passing a resource that is not among dev's resources? */
378+
WARN_ON_ONCE(resno >= PCI_NUM_RESOURCES);
379+
380+
return resno;
381+
}
353382

354383
void pci_reassigndev_resource_alignment(struct pci_dev *dev);
355384
void pci_disable_bridge_window(struct pci_dev *dev);
@@ -659,6 +688,10 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno);
659688
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
660689
void pci_restore_iov_state(struct pci_dev *dev);
661690
int pci_iov_bus_range(struct pci_bus *bus);
691+
static inline bool pci_resource_is_iov(int resno)
692+
{
693+
return resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END;
694+
}
662695
extern const struct attribute_group sriov_pf_dev_attr_group;
663696
extern const struct attribute_group sriov_vf_dev_attr_group;
664697
#else
@@ -668,12 +701,21 @@ static inline int pci_iov_init(struct pci_dev *dev)
668701
}
669702
static inline void pci_iov_release(struct pci_dev *dev) { }
670703
static inline void pci_iov_remove(struct pci_dev *dev) { }
704+
static inline void pci_iov_update_resource(struct pci_dev *dev, int resno) { }
705+
static inline resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
706+
int resno)
707+
{
708+
return 0;
709+
}
671710
static inline void pci_restore_iov_state(struct pci_dev *dev) { }
672711
static inline int pci_iov_bus_range(struct pci_bus *bus)
673712
{
674713
return 0;
675714
}
676-
715+
static inline bool pci_resource_is_iov(int resno)
716+
{
717+
return false;
718+
}
677719
#endif /* CONFIG_PCI_IOV */
678720

679721
#ifdef CONFIG_PCIE_TPH
@@ -707,12 +749,10 @@ unsigned long pci_cardbus_resource_alignment(struct resource *);
707749
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
708750
struct resource *res)
709751
{
710-
#ifdef CONFIG_PCI_IOV
711-
int resno = res - dev->resource;
752+
int resno = pci_resource_num(dev, res);
712753

713-
if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)
754+
if (pci_resource_is_iov(resno))
714755
return pci_sriov_resource_alignment(dev, resno);
715-
#endif
716756
if (dev->class >> 8 == PCI_CLASS_BRIDGE_CARDBUS)
717757
return pci_cardbus_resource_alignment(res);
718758
return resource_alignment(res);

drivers/pci/proc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
251251
security_locked_down(LOCKDOWN_PCI_ACCESS))
252252
return -EPERM;
253253

254+
/* Skip devices with non-mappable BARs */
255+
if (dev->non_mappable_bars)
256+
return -EINVAL;
257+
254258
if (fpriv->mmap_state == pci_mmap_io) {
255259
if (!arch_can_pci_mmap_io())
256260
return -EINVAL;

0 commit comments

Comments
 (0)