0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/bits.h>
0012 #include <linux/export.h>
0013 #include <linux/pci.h>
0014 #include <linux/platform_data/x86/p2sb.h>
0015
0016 #include <asm/cpu_device_id.h>
0017 #include <asm/intel-family.h>
0018
0019 #define P2SBC 0xe0
0020 #define P2SBC_HIDE BIT(8)
0021
0022 static const struct x86_cpu_id p2sb_cpu_ids[] = {
0023 X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)),
0024 X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, PCI_DEVFN(31, 1)),
0025 X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D, PCI_DEVFN(31, 1)),
0026 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, PCI_DEVFN(31, 1)),
0027 X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, PCI_DEVFN(31, 1)),
0028 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, PCI_DEVFN(31, 1)),
0029 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, PCI_DEVFN(31, 1)),
0030 {}
0031 };
0032
0033 static int p2sb_get_devfn(unsigned int *devfn)
0034 {
0035 const struct x86_cpu_id *id;
0036
0037 id = x86_match_cpu(p2sb_cpu_ids);
0038 if (!id)
0039 return -ENODEV;
0040
0041 *devfn = (unsigned int)id->driver_data;
0042 return 0;
0043 }
0044
0045
0046 static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem)
0047 {
0048 struct resource *bar0 = &pdev->resource[0];
0049
0050
0051 memset(mem, 0, sizeof(*mem));
0052
0053
0054
0055
0056
0057
0058 mem->start = bar0->start;
0059 mem->end = bar0->end;
0060 mem->flags = bar0->flags;
0061 mem->desc = bar0->desc;
0062
0063 return 0;
0064 }
0065
0066 static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
0067 {
0068 struct pci_dev *pdev;
0069 int ret;
0070
0071 pdev = pci_scan_single_device(bus, devfn);
0072 if (!pdev)
0073 return -ENODEV;
0074
0075 ret = p2sb_read_bar0(pdev, mem);
0076
0077 pci_stop_and_remove_bus_device(pdev);
0078 return ret;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem)
0101 {
0102 struct pci_dev *pdev_p2sb;
0103 unsigned int devfn_p2sb;
0104 u32 value = P2SBC_HIDE;
0105 int ret;
0106
0107
0108 ret = p2sb_get_devfn(&devfn_p2sb);
0109 if (ret)
0110 return ret;
0111
0112
0113 bus = bus ?: pci_find_bus(0, 0);
0114
0115
0116
0117
0118
0119 pci_lock_rescan_remove();
0120
0121
0122 pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value);
0123 if (value & P2SBC_HIDE)
0124 pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0);
0125
0126 pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb);
0127 if (devfn)
0128 ret = p2sb_scan_and_read(bus, devfn, mem);
0129 else
0130 ret = p2sb_read_bar0(pdev_p2sb, mem);
0131 pci_stop_and_remove_bus_device(pdev_p2sb);
0132
0133
0134 if (value & P2SBC_HIDE)
0135 pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE);
0136
0137 pci_unlock_rescan_remove();
0138
0139 if (ret)
0140 return ret;
0141
0142 if (mem->flags == 0)
0143 return -ENODEV;
0144
0145 return 0;
0146 }
0147 EXPORT_SYMBOL_GPL(p2sb_bar);