mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
passthrough: allow to suppress SERR and PERR signaling altogether
This is just to have a workaround at hand in case other chipsets (not
covered by the previous two patches) also have similar issues.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Don Dugger <donald.d.dugger@intel.com>
Acked-by: Tim Deegan <tim@xen.org>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
master commit: 1a2a390a56
master date: 2014-04-25 12:13:31 +0200
This commit is contained in:
1 parent
b206157e9c
commit
22fe8bdf66
3 files changed
+123
-1
No files matched your search
@@ -725,6 +725,14 @@ Defaults to booting secondary processors.
|
||||
|
||||
Default: `on`
|
||||
|
||||
### pci
|
||||
> `= {no-}serr | {no-}perr`
|
||||
|
||||
Disable signaling of SERR (system errors) and/or PERR (parity errors)
|
||||
on all PCI devices.
|
||||
|
||||
Default: Signaling left as set by firmware.
|
||||
|
||||
### pci-phantom
|
||||
> `=[<seg>:]<bus>:<device>,<stride>`
|
||||
|
||||
|
||||
@@ -163,6 +163,115 @@ static void __init parse_phantom_dev(char *str) {
|
||||
}
|
||||
custom_param("pci-phantom", parse_phantom_dev);
|
||||
|
||||
static u16 __read_mostly command_mask;
|
||||
static u16 __read_mostly bridge_ctl_mask;
|
||||
|
||||
/*
|
||||
* The 'pci' parameter controls certain PCI device aspects.
|
||||
* Optional comma separated value may contain:
|
||||
*
|
||||
* serr don't suppress system errors (default)
|
||||
* no-serr suppress system errors
|
||||
* perr don't suppress parity errors (default)
|
||||
* no-perr suppress parity errors
|
||||
*/
|
||||
static void __init parse_pci_param(char *s)
|
||||
{
|
||||
char *ss;
|
||||
|
||||
do {
|
||||
bool_t on = !!strncmp(s, "no-", 3);
|
||||
u16 cmd_mask = 0, brctl_mask = 0;
|
||||
|
||||
if ( !on )
|
||||
s += 3;
|
||||
|
||||
ss = strchr(s, ',');
|
||||
if ( ss )
|
||||
*ss = '\0';
|
||||
|
||||
if ( !strcmp(s, "serr") )
|
||||
{
|
||||
cmd_mask = PCI_COMMAND_SERR;
|
||||
brctl_mask = PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_DTMR_SERR;
|
||||
}
|
||||
else if ( !strcmp(s, "perr") )
|
||||
{
|
||||
cmd_mask = PCI_COMMAND_PARITY;
|
||||
brctl_mask = PCI_BRIDGE_CTL_PARITY;
|
||||
}
|
||||
|
||||
if ( on )
|
||||
{
|
||||
command_mask &= ~cmd_mask;
|
||||
bridge_ctl_mask &= ~brctl_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_mask |= cmd_mask;
|
||||
bridge_ctl_mask |= brctl_mask;
|
||||
}
|
||||
|
||||
s = ss + 1;
|
||||
} while ( ss );
|
||||
}
|
||||
custom_param("pci", parse_pci_param);
|
||||
|
||||
static void check_pdev(const struct pci_dev *pdev)
|
||||
{
|
||||
#define PCI_STATUS_CHECK \
|
||||
(PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | \
|
||||
PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | \
|
||||
PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)
|
||||
u16 seg = pdev->seg;
|
||||
u8 bus = pdev->bus;
|
||||
u8 dev = PCI_SLOT(pdev->devfn);
|
||||
u8 func = PCI_FUNC(pdev->devfn);
|
||||
u16 val;
|
||||
|
||||
if ( command_mask )
|
||||
{
|
||||
val = pci_conf_read16(seg, bus, dev, func, PCI_COMMAND);
|
||||
if ( val & command_mask )
|
||||
pci_conf_write16(seg, bus, dev, func, PCI_COMMAND,
|
||||
val & ~command_mask);
|
||||
val = pci_conf_read16(seg, bus, dev, func, PCI_STATUS);
|
||||
if ( val & PCI_STATUS_CHECK )
|
||||
{
|
||||
printk(XENLOG_INFO "%04x:%02x:%02x.%u status %04x -> %04x\n",
|
||||
seg, bus, dev, func, val, val & ~PCI_STATUS_CHECK);
|
||||
pci_conf_write16(seg, bus, dev, func, PCI_STATUS,
|
||||
val & PCI_STATUS_CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
switch ( pci_conf_read8(seg, bus, dev, func, PCI_HEADER_TYPE) & 0x7f )
|
||||
{
|
||||
case PCI_HEADER_TYPE_BRIDGE:
|
||||
if ( !bridge_ctl_mask )
|
||||
break;
|
||||
val = pci_conf_read16(seg, bus, dev, func, PCI_BRIDGE_CONTROL);
|
||||
if ( val & bridge_ctl_mask )
|
||||
pci_conf_write16(seg, bus, dev, func, PCI_BRIDGE_CONTROL,
|
||||
val & ~bridge_ctl_mask);
|
||||
val = pci_conf_read16(seg, bus, dev, func, PCI_SEC_STATUS);
|
||||
if ( val & PCI_STATUS_CHECK )
|
||||
{
|
||||
printk(XENLOG_INFO
|
||||
"%04x:%02x:%02x.%u secondary status %04x -> %04x\n",
|
||||
seg, bus, dev, func, val, val & ~PCI_STATUS_CHECK);
|
||||
pci_conf_write16(seg, bus, dev, func, PCI_SEC_STATUS,
|
||||
val & PCI_STATUS_CHECK);
|
||||
}
|
||||
break;
|
||||
|
||||
case PCI_HEADER_TYPE_CARDBUS:
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
#undef PCI_STATUS_CHECK
|
||||
}
|
||||
|
||||
static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
@@ -248,6 +357,8 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
|
||||
break;
|
||||
}
|
||||
|
||||
check_pdev(pdev);
|
||||
|
||||
return pdev;
|
||||
}
|
||||
|
||||
@@ -561,6 +672,8 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, const struct pci_dev_info *info)
|
||||
seg, bus, slot, func, ctrl);
|
||||
}
|
||||
|
||||
check_pdev(pdev);
|
||||
|
||||
ret = 0;
|
||||
if ( !pdev->domain )
|
||||
{
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
#define PCI_IO_RANGE_TYPE_16 0x00
|
||||
#define PCI_IO_RANGE_TYPE_32 0x01
|
||||
#define PCI_IO_RANGE_MASK (~0x0fUL)
|
||||
#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
|
||||
#define PCI_SEC_STATUS 0x1e /* Secondary status register */
|
||||
#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
|
||||
#define PCI_MEMORY_LIMIT 0x22
|
||||
#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
|
||||
@@ -152,6 +152,7 @@
|
||||
#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
|
||||
#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
|
||||
#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
|
||||
#define PCI_BRIDGE_CTL_DTMR_SERR 0x800 /* SERR upon discard timer expiry */
|
||||
|
||||
/* Header type 2 (CardBus bridges) */
|
||||
#define PCI_CB_CAPABILITY_LIST 0x14
|
||||
|
||||