diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2017-11-14 13:11:25 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-11-14 13:11:25 -0500 |
| commit | 104d1e40cfcd69934f3f57c6abf13980eb703feb (patch) | |
| tree | b57f657381267187610c1dbc2606de2142ceca7d | |
| parent | 8dceeaf8fff35a0b70a8cf3ca66883ac4bf4c9dd (diff) | |
| parent | a405f191f42ead45a03c000110a16683d30f7333 (diff) | |
Merge branch 'pci/resource' into next
* pci/resource:
PCI: Fail pci_map_rom() if the option ROM is invalid
PCI: Move pci_map_rom() error path
x86/PCI: Enable a 64bit BAR on AMD Family 15h (Models 00-1f, 30-3f, 60-7f)
PCI: Add pci_resize_resource() for resizing BARs
PCI: Add resizable BAR infrastructure
PCI: Add PCI resource type mask #define
| -rw-r--r-- | arch/x86/pci/fixup.c | 85 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 101 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 8 | ||||
| -rw-r--r-- | drivers/pci/rom.c | 19 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 115 | ||||
| -rw-r--r-- | drivers/pci/setup-res.c | 58 | ||||
| -rw-r--r-- | include/linux/pci.h | 3 | ||||
| -rw-r--r-- | include/uapi/linux/pci_regs.h | 8 |
8 files changed, 380 insertions, 17 deletions
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index f2228b150faa..e59378bf37d9 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c | |||
| @@ -635,3 +635,88 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2030, quirk_no_aersid); | |||
| 635 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid); | 635 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2031, quirk_no_aersid); |
| 636 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid); | 636 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2032, quirk_no_aersid); |
| 637 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid); | 637 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2033, quirk_no_aersid); |
| 638 | |||
| 639 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | ||
| 640 | |||
| 641 | #define AMD_141b_MMIO_BASE(x) (0x80 + (x) * 0x8) | ||
| 642 | #define AMD_141b_MMIO_BASE_RE_MASK BIT(0) | ||
| 643 | #define AMD_141b_MMIO_BASE_WE_MASK BIT(1) | ||
| 644 | #define AMD_141b_MMIO_BASE_MMIOBASE_MASK GENMASK(31,8) | ||
| 645 | |||
| 646 | #define AMD_141b_MMIO_LIMIT(x) (0x84 + (x) * 0x8) | ||
| 647 | #define AMD_141b_MMIO_LIMIT_MMIOLIMIT_MASK GENMASK(31,8) | ||
| 648 | |||
| 649 | #define AMD_141b_MMIO_HIGH(x) (0x180 + (x) * 0x4) | ||
| 650 | #define AMD_141b_MMIO_HIGH_MMIOBASE_MASK GENMASK(7,0) | ||
| 651 | #define AMD_141b_MMIO_HIGH_MMIOLIMIT_SHIFT 16 | ||
| 652 | #define AMD_141b_MMIO_HIGH_MMIOLIMIT_MASK GENMASK(23,16) | ||
| 653 | |||
| 654 | /* | ||
| 655 | * The PCI Firmware Spec, rev 3.2, notes that ACPI should optionally allow | ||
| 656 | * configuring host bridge windows using the _PRS and _SRS methods. | ||
| 657 | * | ||
| 658 | * But this is rarely implemented, so we manually enable a large 64bit BAR for | ||
| 659 | * PCIe device on AMD Family 15h (Models 00h-1fh, 30h-3fh, 60h-7fh) Processors | ||
| 660 | * here. | ||
| 661 | */ | ||
| 662 | static void pci_amd_enable_64bit_bar(struct pci_dev *dev) | ||
| 663 | { | ||
| 664 | unsigned i; | ||
| 665 | u32 base, limit, high; | ||
| 666 | struct resource *res, *conflict; | ||
| 667 | |||
| 668 | for (i = 0; i < 8; i++) { | ||
| 669 | pci_read_config_dword(dev, AMD_141b_MMIO_BASE(i), &base); | ||
| 670 | pci_read_config_dword(dev, AMD_141b_MMIO_HIGH(i), &high); | ||
| 671 | |||
| 672 | /* Is this slot free? */ | ||
| 673 | if (!(base & (AMD_141b_MMIO_BASE_RE_MASK | | ||
| 674 | AMD_141b_MMIO_BASE_WE_MASK))) | ||
| 675 | break; | ||
| 676 | |||
| 677 | base >>= 8; | ||
| 678 | base |= high << 24; | ||
| 679 | |||
| 680 | /* Abort if a slot already configures a 64bit BAR. */ | ||
| 681 | if (base > 0x10000) | ||
| 682 | return; | ||
| 683 | } | ||
| 684 | if (i == 8) | ||
| 685 | return; | ||
| 686 | |||
| 687 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
| 688 | if (!res) | ||
| 689 | return; | ||
| 690 | |||
| 691 | res->name = "PCI Bus 0000:00"; | ||
| 692 | res->flags = IORESOURCE_PREFETCH | IORESOURCE_MEM | | ||
| 693 | IORESOURCE_MEM_64 | IORESOURCE_WINDOW; | ||
| 694 | res->start = 0x100000000ull; | ||
| 695 | res->end = 0xfd00000000ull - 1; | ||
| 696 | |||
| 697 | /* Just grab the free area behind system memory for this */ | ||
| 698 | while ((conflict = request_resource_conflict(&iomem_resource, res))) | ||
| 699 | res->start = conflict->end + 1; | ||
| 700 | |||
| 701 | dev_info(&dev->dev, "adding root bus resource %pR\n", res); | ||
| 702 | |||
| 703 | base = ((res->start >> 8) & AMD_141b_MMIO_BASE_MMIOBASE_MASK) | | ||
| 704 | AMD_141b_MMIO_BASE_RE_MASK | AMD_141b_MMIO_BASE_WE_MASK; | ||
| 705 | limit = ((res->end + 1) >> 8) & AMD_141b_MMIO_LIMIT_MMIOLIMIT_MASK; | ||
| 706 | high = ((res->start >> 40) & AMD_141b_MMIO_HIGH_MMIOBASE_MASK) | | ||
| 707 | ((((res->end + 1) >> 40) << AMD_141b_MMIO_HIGH_MMIOLIMIT_SHIFT) | ||
| 708 | & AMD_141b_MMIO_HIGH_MMIOLIMIT_MASK); | ||
| 709 | |||
| 710 | pci_write_config_dword(dev, AMD_141b_MMIO_HIGH(i), high); | ||
| 711 | pci_write_config_dword(dev, AMD_141b_MMIO_LIMIT(i), limit); | ||
| 712 | pci_write_config_dword(dev, AMD_141b_MMIO_BASE(i), base); | ||
| 713 | |||
| 714 | pci_bus_add_resource(dev->bus, res, 0); | ||
| 715 | } | ||
| 716 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1401, pci_amd_enable_64bit_bar); | ||
| 717 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x141b, pci_amd_enable_64bit_bar); | ||
| 718 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar); | ||
| 719 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar); | ||
| 720 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar); | ||
| 721 | |||
| 722 | #endif | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d50c58d6acd3..c5172b01164d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -2966,6 +2966,107 @@ bool pci_acs_path_enabled(struct pci_dev *start, | |||
| 2966 | } | 2966 | } |
| 2967 | 2967 | ||
| 2968 | /** | 2968 | /** |
| 2969 | * pci_rebar_find_pos - find position of resize ctrl reg for BAR | ||
| 2970 | * @pdev: PCI device | ||
| 2971 | * @bar: BAR to find | ||
| 2972 | * | ||
| 2973 | * Helper to find the position of the ctrl register for a BAR. | ||
| 2974 | * Returns -ENOTSUPP if resizable BARs are not supported at all. | ||
| 2975 | * Returns -ENOENT if no ctrl register for the BAR could be found. | ||
| 2976 | */ | ||
| 2977 | static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) | ||
| 2978 | { | ||
| 2979 | unsigned int pos, nbars, i; | ||
| 2980 | u32 ctrl; | ||
| 2981 | |||
| 2982 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); | ||
| 2983 | if (!pos) | ||
| 2984 | return -ENOTSUPP; | ||
| 2985 | |||
| 2986 | pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); | ||
| 2987 | nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >> | ||
| 2988 | PCI_REBAR_CTRL_NBAR_SHIFT; | ||
| 2989 | |||
| 2990 | for (i = 0; i < nbars; i++, pos += 8) { | ||
| 2991 | int bar_idx; | ||
| 2992 | |||
| 2993 | pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); | ||
| 2994 | bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX; | ||
| 2995 | if (bar_idx == bar) | ||
| 2996 | return pos; | ||
| 2997 | } | ||
| 2998 | |||
| 2999 | return -ENOENT; | ||
| 3000 | } | ||
| 3001 | |||
| 3002 | /** | ||
| 3003 | * pci_rebar_get_possible_sizes - get possible sizes for BAR | ||
| 3004 | * @pdev: PCI device | ||
| 3005 | * @bar: BAR to query | ||
| 3006 | * | ||
| 3007 | * Get the possible sizes of a resizable BAR as bitmask defined in the spec | ||
| 3008 | * (bit 0=1MB, bit 19=512GB). Returns 0 if BAR isn't resizable. | ||
| 3009 | */ | ||
| 3010 | u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar) | ||
| 3011 | { | ||
| 3012 | int pos; | ||
| 3013 | u32 cap; | ||
| 3014 | |||
| 3015 | pos = pci_rebar_find_pos(pdev, bar); | ||
| 3016 | if (pos < 0) | ||
| 3017 | return 0; | ||
| 3018 | |||
| 3019 | pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap); | ||
| 3020 | return (cap & PCI_REBAR_CAP_SIZES) >> 4; | ||
| 3021 | } | ||
| 3022 | |||
| 3023 | /** | ||
| 3024 | * pci_rebar_get_current_size - get the current size of a BAR | ||
| 3025 | * @pdev: PCI device | ||
| 3026 | * @bar: BAR to set size to | ||
| 3027 | * | ||
| 3028 | * Read the size of a BAR from the resizable BAR config. | ||
| 3029 | * Returns size if found or negative error code. | ||
| 3030 | */ | ||
| 3031 | int pci_rebar_get_current_size(struct pci_dev *pdev, int bar) | ||
| 3032 | { | ||
| 3033 | int pos; | ||
| 3034 | u32 ctrl; | ||
| 3035 | |||
| 3036 | pos = pci_rebar_find_pos(pdev, bar); | ||
| 3037 | if (pos < 0) | ||
| 3038 | return pos; | ||
| 3039 | |||
| 3040 | pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); | ||
| 3041 | return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8; | ||
| 3042 | } | ||
| 3043 | |||
| 3044 | /** | ||
| 3045 | * pci_rebar_set_size - set a new size for a BAR | ||
| 3046 | * @pdev: PCI device | ||
| 3047 | * @bar: BAR to set size to | ||
| 3048 | * @size: new size as defined in the spec (0=1MB, 19=512GB) | ||
| 3049 | * | ||
| 3050 | * Set the new size of a BAR as defined in the spec. | ||
| 3051 | * Returns zero if resizing was successful, error code otherwise. | ||
| 3052 | */ | ||
| 3053 | int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size) | ||
| 3054 | { | ||
| 3055 | int pos; | ||
| 3056 | u32 ctrl; | ||
| 3057 | |||
| 3058 | pos = pci_rebar_find_pos(pdev, bar); | ||
| 3059 | if (pos < 0) | ||
| 3060 | return pos; | ||
| 3061 | |||
| 3062 | pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl); | ||
| 3063 | ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE; | ||
| 3064 | ctrl |= size << 8; | ||
| 3065 | pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl); | ||
| 3066 | return 0; | ||
| 3067 | } | ||
| 3068 | |||
| 3069 | /** | ||
| 2969 | * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge | 3070 | * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge |
| 2970 | * @dev: the PCI device | 3071 | * @dev: the PCI device |
| 2971 | * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) | 3072 | * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) |
