Merge branch 'pci/vga'

- Return vga_get_uninterruptible() back to userspace in the
  /dev/vga_arbiter path so user can tell whether VGA routing was updated
  (Simon Richter)

- Make pci_set_vga_state() fail if bridge doesn't support VGA routing,
  i.e., PCI_BRIDGE_CTL_VGA is not writable, and return errors up to
  vga_get() callers (Simon Richter)

* pci/vga:
  PCI/VGA: Fail pci_set_vga_state() if VGA decoding not supported
  PCI/VGA: Pass errors from pci_set_vga_state() up
  PCI/VGA: Pass vga_get_uninterruptible() errors to userspace
This commit is contained in:
Bjorn Helgaas 2026-04-13 12:50:06 -05:00
commit a09007a782
2 changed files with 29 additions and 3 deletions

View File

@ -6202,6 +6202,18 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
cmd &= ~PCI_BRIDGE_CTL_VGA;
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
cmd);
/*
* VGA Enable may not be writable if bridge doesn't
* support it.
*/
if (decode) {
pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
&cmd);
if (!(cmd & PCI_BRIDGE_CTL_VGA))
return -EIO;
}
}
bus = bus->parent;
}

View File

@ -215,6 +215,7 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
struct vga_device *conflict;
unsigned int pci_bits;
u32 flags = 0;
int err;
/*
* Account for "normal" resources to lock. If we decode the legacy,
@ -307,7 +308,9 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
if (change_bridge)
flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
err = pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
if (err)
return ERR_PTR(err);
conflict->owns &= ~match;
/* If we disabled normal decoding, reflect it in owns */
@ -337,7 +340,9 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
if (wants & VGA_RSRC_LEGACY_MASK)
flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
err = pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
if (err)
return ERR_PTR(err);
vgadev->owns |= wants;
lock_them:
@ -455,6 +460,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
}
conflict = __vga_tryget(vgadev, rsrc);
spin_unlock_irqrestore(&vga_lock, flags);
if (IS_ERR(conflict)) {
rc = PTR_ERR(conflict);
break;
}
if (conflict == NULL)
break;
@ -1134,6 +1143,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf,
char kbuf[64], *curr_pos;
size_t remaining = count;
int err;
int ret_val;
int i;
@ -1165,7 +1175,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user *buf,
goto done;
}
vga_get_uninterruptible(pdev, io_state);
err = vga_get_uninterruptible(pdev, io_state);
if (err) {
ret_val = err;
goto done;
}
/* Update the client's locks lists */
for (i = 0; i < MAX_USER_CARDS; i++) {