diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-02-14 16:37:18 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-02-14 16:37:18 -0500 |
commit | c80ef97ae4848c4592f0fac9c06d7f436862a28d (patch) | |
tree | d2b05cf6beae20f967afe4a20a6403f8e2e6caac | |
parent | 25a712a49fade142b78a1c55166ad8a19cb53aba (diff) | |
parent | d99321b63b1f2cd386cdf20aefe4d8d3d414cb5b (diff) |
Merge branch 'pci/virtualization' into next
* pci/virtualization:
PCI: Enable quirks for PCIe ACS on Intel PCH root ports
PCI: Add pci_dev_flag for ACS enable quirks
PCI: Add device-specific PCI ACS enable
-rw-r--r-- | drivers/pci/pci.c | 26 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 185 | ||||
-rw-r--r-- | include/linux/pci.h | 4 |
3 files changed, 209 insertions, 6 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1febe90831b4..b89502ff3139 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -2180,21 +2180,18 @@ void pci_request_acs(void) | |||
2180 | } | 2180 | } |
2181 | 2181 | ||
2182 | /** | 2182 | /** |
2183 | * pci_enable_acs - enable ACS if hardware support it | 2183 | * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites |
2184 | * @dev: the PCI device | 2184 | * @dev: the PCI device |
2185 | */ | 2185 | */ |
2186 | void pci_enable_acs(struct pci_dev *dev) | 2186 | static int pci_std_enable_acs(struct pci_dev *dev) |
2187 | { | 2187 | { |
2188 | int pos; | 2188 | int pos; |
2189 | u16 cap; | 2189 | u16 cap; |
2190 | u16 ctrl; | 2190 | u16 ctrl; |
2191 | 2191 | ||
2192 | if (!pci_acs_enable) | ||
2193 | return; | ||
2194 | |||
2195 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); | 2192 | pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); |
2196 | if (!pos) | 2193 | if (!pos) |
2197 | return; | 2194 | return -ENODEV; |
2198 | 2195 | ||
2199 | pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); | 2196 | pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); |
2200 | pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); | 2197 | pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); |
@@ -2212,6 +2209,23 @@ void pci_enable_acs(struct pci_dev *dev) | |||
2212 | ctrl |= (cap & PCI_ACS_UF); | 2209 | ctrl |= (cap & PCI_ACS_UF); |
2213 | 2210 | ||
2214 | pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); | 2211 | pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); |
2212 | |||
2213 | return 0; | ||
2214 | } | ||
2215 | |||
2216 | /** | ||
2217 | * pci_enable_acs - enable ACS if hardware support it | ||
2218 | * @dev: the PCI device | ||
2219 | */ | ||
2220 | void pci_enable_acs(struct pci_dev *dev) | ||
2221 | { | ||
2222 | if (!pci_acs_enable) | ||
2223 | return; | ||
2224 | |||
2225 | if (!pci_std_enable_acs(dev)) | ||
2226 | return; | ||
2227 | |||
2228 | pci_dev_specific_enable_acs(dev); | ||
2215 | } | 2229 | } |
2216 | 2230 | ||
2217 | static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) | 2231 | static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5cb726c193de..ed2ed867c34c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -3423,6 +3423,61 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags) | |||
3423 | #endif | 3423 | #endif |
3424 | } | 3424 | } |
3425 | 3425 | ||
3426 | /* | ||
3427 | * Many Intel PCH root ports do provide ACS-like features to disable peer | ||
3428 | * transactions and validate bus numbers in requests, but do not provide an | ||
3429 | * actual PCIe ACS capability. This is the list of device IDs known to fall | ||
3430 | * into that category as provided by Intel in Red Hat bugzilla 1037684. | ||
3431 | */ | ||
3432 | static const u16 pci_quirk_intel_pch_acs_ids[] = { | ||
3433 | /* Ibexpeak PCH */ | ||
3434 | 0x3b42, 0x3b43, 0x3b44, 0x3b45, 0x3b46, 0x3b47, 0x3b48, 0x3b49, | ||
3435 | 0x3b4a, 0x3b4b, 0x3b4c, 0x3b4d, 0x3b4e, 0x3b4f, 0x3b50, 0x3b51, | ||
3436 | /* Cougarpoint PCH */ | ||
3437 | 0x1c10, 0x1c11, 0x1c12, 0x1c13, 0x1c14, 0x1c15, 0x1c16, 0x1c17, | ||
3438 | 0x1c18, 0x1c19, 0x1c1a, 0x1c1b, 0x1c1c, 0x1c1d, 0x1c1e, 0x1c1f, | ||
3439 | /* Pantherpoint PCH */ | ||
3440 | 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17, | ||
3441 | 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f, | ||
3442 | /* Lynxpoint-H PCH */ | ||
3443 | 0x8c10, 0x8c11, 0x8c12, 0x8c13, 0x8c14, 0x8c15, 0x8c16, 0x8c17, | ||
3444 | 0x8c18, 0x8c19, 0x8c1a, 0x8c1b, 0x8c1c, 0x8c1d, 0x8c1e, 0x8c1f, | ||
3445 | /* Lynxpoint-LP PCH */ | ||
3446 | 0x9c10, 0x9c11, 0x9c12, 0x9c13, 0x9c14, 0x9c15, 0x9c16, 0x9c17, | ||
3447 | 0x9c18, 0x9c19, 0x9c1a, 0x9c1b, | ||
3448 | /* Wildcat PCH */ | ||
3449 | 0x9c90, 0x9c91, 0x9c92, 0x9c93, 0x9c94, 0x9c95, 0x9c96, 0x9c97, | ||
3450 | 0x9c98, 0x9c99, 0x9c9a, 0x9c9b, | ||
3451 | }; | ||
3452 | |||
3453 | static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev) | ||
3454 | { | ||
3455 | int i; | ||
3456 | |||
3457 | /* Filter out a few obvious non-matches first */ | ||
3458 | if (!pci_is_pcie(dev) || pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) | ||
3459 | return false; | ||
3460 | |||
3461 | for (i = 0; i < ARRAY_SIZE(pci_quirk_intel_pch_acs_ids); i++) | ||
3462 | if (pci_quirk_intel_pch_acs_ids[i] == dev->device) | ||
3463 | return true; | ||
3464 | |||
3465 | return false; | ||
3466 | } | ||
3467 | |||
3468 | #define INTEL_PCH_ACS_FLAGS (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_SV) | ||
3469 | |||
3470 | static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) | ||
3471 | { | ||
3472 | u16 flags = dev->dev_flags & PCI_DEV_FLAGS_ACS_ENABLED_QUIRK ? | ||
3473 | INTEL_PCH_ACS_FLAGS : 0; | ||
3474 | |||
3475 | if (!pci_quirk_intel_pch_acs_match(dev)) | ||
3476 | return -ENOTTY; | ||
3477 | |||
3478 | return acs_flags & ~flags ? 0 : 1; | ||
3479 | } | ||
3480 | |||
3426 | static const struct pci_dev_acs_enabled { | 3481 | static const struct pci_dev_acs_enabled { |
3427 | u16 vendor; | 3482 | u16 vendor; |
3428 | u16 device; | 3483 | u16 device; |
@@ -3434,6 +3489,7 @@ static const struct pci_dev_acs_enabled { | |||
3434 | { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs }, | 3489 | { PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs }, |
3435 | { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs }, | 3490 | { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs }, |
3436 | { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs }, | 3491 | { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs }, |
3492 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, | ||
3437 | { 0 } | 3493 | { 0 } |
3438 | }; | 3494 | }; |
3439 | 3495 | ||
@@ -3461,3 +3517,132 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) | |||
3461 | 3517 | ||
3462 | return -ENOTTY; | 3518 | return -ENOTTY; |
3463 | } | 3519 | } |
3520 | |||
3521 | /* Config space offset of Root Complex Base Address register */ | ||
3522 | #define INTEL_LPC_RCBA_REG 0xf0 | ||
3523 | /* 31:14 RCBA address */ | ||
3524 | #define INTEL_LPC_RCBA_MASK 0xffffc000 | ||
3525 | /* RCBA Enable */ | ||
3526 | #define INTEL_LPC_RCBA_ENABLE (1 << 0) | ||
3527 | |||
3528 | /* Backbone Scratch Pad Register */ | ||
3529 | #define INTEL_BSPR_REG 0x1104 | ||
3530 | /* Backbone Peer Non-Posted Disable */ | ||
3531 | #define INTEL_BSPR_REG_BPNPD (1 << 8) | ||
3532 | /* Backbone Peer Posted Disable */ | ||
3533 | #define INTEL_BSPR_REG_BPPD (1 << 9) | ||
3534 | |||
3535 | /* Upstream Peer Decode Configuration Register */ | ||
3536 | #define INTEL_UPDCR_REG 0x1114 | ||
3537 | /* 5:0 Peer Decode Enable bits */ | ||
3538 | #define INTEL_UPDCR_REG_MASK 0x3f | ||
3539 | |||
3540 | static int pci_quirk_enable_intel_lpc_acs(struct pci_dev *dev) | ||
3541 | { | ||
3542 | u32 rcba, bspr, updcr; | ||
3543 | void __iomem *rcba_mem; | ||
3544 | |||
3545 | /* | ||
3546 | * Read the RCBA register from the LPC (D31:F0). PCH root ports | ||
3547 | * are D28:F* and therefore get probed before LPC, thus we can't | ||
3548 | * use pci_get_slot/pci_read_config_dword here. | ||
3549 | */ | ||
3550 | pci_bus_read_config_dword(dev->bus, PCI_DEVFN(31, 0), | ||
3551 | INTEL_LPC_RCBA_REG, &rcba); | ||
3552 | if (!(rcba & INTEL_LPC_RCBA_ENABLE)) | ||
3553 | return -EINVAL; | ||
3554 | |||
3555 | rcba_mem = ioremap_nocache(rcba & INTEL_LPC_RCBA_MASK, | ||
3556 | PAGE_ALIGN(INTEL_UPDCR_REG)); | ||
3557 | if (!rcba_mem) | ||
3558 | return -ENOMEM; | ||
3559 | |||
3560 | /* | ||
3561 | * The BSPR can disallow peer cycles, but it's set by soft strap and | ||
3562 | * therefore read-only. If both posted and non-posted peer cycles are | ||
3563 | * disallowed, we're ok. If either are allowed, then we need to use | ||
3564 | * the UPDCR to disable peer decodes for each port. This provides the | ||
3565 | * PCIe ACS equivalent of PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | ||
3566 | */ | ||
3567 | bspr = readl(rcba_mem + INTEL_BSPR_REG); | ||
3568 | bspr &= INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD; | ||
3569 | if (bspr != (INTEL_BSPR_REG_BPNPD | INTEL_BSPR_REG_BPPD)) { | ||
3570 | updcr = readl(rcba_mem + INTEL_UPDCR_REG); | ||
3571 | if (updcr & INTEL_UPDCR_REG_MASK) { | ||
3572 | dev_info(&dev->dev, "Disabling UPDCR peer decodes\n"); | ||
3573 | updcr &= ~INTEL_UPDCR_REG_MASK; | ||
3574 | writel(updcr, rcba_mem + INTEL_UPDCR_REG); | ||
3575 | } | ||
3576 | } | ||
3577 | |||
3578 | iounmap(rcba_mem); | ||
3579 | return 0; | ||
3580 | } | ||
3581 | |||
3582 | /* Miscellaneous Port Configuration register */ | ||
3583 | #define INTEL_MPC_REG 0xd8 | ||
3584 | /* MPC: Invalid Receive Bus Number Check Enable */ | ||
3585 | #define INTEL_MPC_REG_IRBNCE (1 << 26) | ||
3586 | |||
3587 | static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev) | ||
3588 | { | ||
3589 | u32 mpc; | ||
3590 | |||
3591 | /* | ||
3592 | * When enabled, the IRBNCE bit of the MPC register enables the | ||
3593 | * equivalent of PCI ACS Source Validation (PCI_ACS_SV), which | ||
3594 | * ensures that requester IDs fall within the bus number range | ||
3595 | * of the bridge. Enable if not already. | ||
3596 | */ | ||
3597 | pci_read_config_dword(dev, INTEL_MPC_REG, &mpc); | ||
3598 | if (!(mpc & INTEL_MPC_REG_IRBNCE)) { | ||
3599 | dev_info(&dev->dev, "Enabling MPC IRBNCE\n"); | ||
3600 | mpc |= INTEL_MPC_REG_IRBNCE; | ||
3601 | pci_write_config_word(dev, INTEL_MPC_REG, mpc); | ||
3602 | } | ||
3603 | } | ||
3604 | |||
3605 | static int pci_quirk_enable_intel_pch_acs(struct pci_dev *dev) | ||
3606 | { | ||
3607 | if (!pci_quirk_intel_pch_acs_match(dev)) | ||
3608 | return -ENOTTY; | ||
3609 | |||
3610 | if (pci_quirk_enable_intel_lpc_acs(dev)) { | ||
3611 | dev_warn(&dev->dev, "Failed to enable Intel PCH ACS quirk\n"); | ||
3612 | return 0; | ||
3613 | } | ||
3614 | |||
3615 | pci_quirk_enable_intel_rp_mpc_acs(dev); | ||
3616 | |||
3617 | dev->dev_flags |= PCI_DEV_FLAGS_ACS_ENABLED_QUIRK; | ||
3618 | |||
3619 | dev_info(&dev->dev, "Intel PCH root port ACS workaround enabled\n"); | ||
3620 | |||
3621 | return 0; | ||
3622 | } | ||
3623 | |||
3624 | static const struct pci_dev_enable_acs { | ||
3625 | u16 vendor; | ||
3626 | u16 device; | ||
3627 | int (*enable_acs)(struct pci_dev *dev); | ||
3628 | } pci_dev_enable_acs[] = { | ||
3629 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_enable_intel_pch_acs }, | ||
3630 | { 0 } | ||
3631 | }; | ||
3632 | |||
3633 | void pci_dev_specific_enable_acs(struct pci_dev *dev) | ||
3634 | { | ||
3635 | const struct pci_dev_enable_acs *i; | ||
3636 | int ret; | ||
3637 | |||
3638 | for (i = pci_dev_enable_acs; i->enable_acs; i++) { | ||
3639 | if ((i->vendor == dev->vendor || | ||
3640 | i->vendor == (u16)PCI_ANY_ID) && | ||
3641 | (i->device == dev->device || | ||
3642 | i->device == (u16)PCI_ANY_ID)) { | ||
3643 | ret = i->enable_acs(dev); | ||
3644 | if (ret >= 0) | ||
3645 | return; | ||
3646 | } | ||
3647 | } | ||
3648 | } | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index fb57c892b214..60ab8d782f8c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -170,6 +170,8 @@ enum pci_dev_flags { | |||
170 | PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, | 170 | PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2, |
171 | /* Provide indication device is assigned by a Virtual Machine Manager */ | 171 | /* Provide indication device is assigned by a Virtual Machine Manager */ |
172 | PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, | 172 | PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4, |
173 | /* Flag for quirk use to store if quirk-specific ACS is enabled */ | ||
174 | PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) 8, | ||
173 | }; | 175 | }; |
174 | 176 | ||
175 | enum pci_irq_reroute_variant { | 177 | enum pci_irq_reroute_variant { |
@@ -1510,6 +1512,7 @@ enum pci_fixup_pass { | |||
1510 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); | 1512 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); |
1511 | struct pci_dev *pci_get_dma_source(struct pci_dev *dev); | 1513 | struct pci_dev *pci_get_dma_source(struct pci_dev *dev); |
1512 | int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); | 1514 | int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); |
1515 | void pci_dev_specific_enable_acs(struct pci_dev *dev); | ||
1513 | #else | 1516 | #else |
1514 | static inline void pci_fixup_device(enum pci_fixup_pass pass, | 1517 | static inline void pci_fixup_device(enum pci_fixup_pass pass, |
1515 | struct pci_dev *dev) { } | 1518 | struct pci_dev *dev) { } |
@@ -1522,6 +1525,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, | |||
1522 | { | 1525 | { |
1523 | return -ENOTTY; | 1526 | return -ENOTTY; |
1524 | } | 1527 | } |
1528 | static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { } | ||
1525 | #endif | 1529 | #endif |
1526 | 1530 | ||
1527 | void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); | 1531 | void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); |