diff options
author | Adrian Calianu <adrian.calianu@enea.com> | 2017-09-27 10:37:36 +0200 |
---|---|---|
committer | Adrian Calianu <adrian.calianu@enea.com> | 2017-09-27 10:37:36 +0200 |
commit | ad4d4e5cbad3ad875eaa59e0a919c014dfb6a39e (patch) | |
tree | 9f4ec55e714e2be67dab4b775775b704af454f74 /patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch | |
parent | 7579efbdb49529f36652b69d4630c6c43907f77b (diff) | |
download | enea-kernel-cache-ad4d4e5cbad3ad875eaa59e0a919c014dfb6a39e.tar.gz |
add guest features from yocto branch
Signed-off-by: Adrian Calianu <adrian.calianu@enea.com>
Diffstat (limited to 'patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch')
-rw-r--r-- | patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch b/patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch new file mode 100644 index 0000000..742a045 --- /dev/null +++ b/patches/boot_time_opt_guest/0110-pci-probe-identify-known-devices.patch | |||
@@ -0,0 +1,190 @@ | |||
1 | From c662d99134b67c58e63ecc17c2531588a3a51596 Mon Sep 17 00:00:00 2001 | ||
2 | From: Arjan van de Ven <arjan@linux.intel.com> | ||
3 | Date: Sat, 14 Feb 2015 09:49:41 -0600 | ||
4 | Subject: [PATCH 110/114] pci: probe: identify known devices | ||
5 | |||
6 | Author: Arjan van de Ven <arjan@linux.intel.com> | ||
7 | Modify-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com> | ||
8 | |||
9 | Signed-off-by: Miguel Bernal Marin <miguel.bernal.marin@linux.intel.com> | ||
10 | --- | ||
11 | drivers/pci/probe.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
12 | 1 file changed, 156 insertions(+) | ||
13 | |||
14 | diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c | ||
15 | index 7399a06698da..4fb2d7fed4c5 100644 | ||
16 | --- a/drivers/pci/probe.c | ||
17 | +++ b/drivers/pci/probe.c | ||
18 | @@ -163,6 +163,159 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar) | ||
19 | |||
20 | #define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO) | ||
21 | |||
22 | +/* shortcut version of __pci_read_base where we know the sizes already */ | ||
23 | +int __pci_read_base_shortcut(struct pci_dev *dev, enum pci_bar_type type, | ||
24 | + struct resource *res, unsigned int pos, u32 sz_in, u32 sz2_in) | ||
25 | +{ | ||
26 | + u32 l, sz; | ||
27 | + u64 l64, sz64, mask64; | ||
28 | + struct pci_bus_region region, inverted_region; | ||
29 | + | ||
30 | + res->name = pci_name(dev); | ||
31 | + | ||
32 | + pci_read_config_dword(dev, pos, &l); | ||
33 | + | ||
34 | + sz = sz_in; | ||
35 | + | ||
36 | + /* | ||
37 | + * All bits set in sz means the device isn't working properly. | ||
38 | + * If the BAR isn't implemented, all bits must be 0. If it's a | ||
39 | + * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit | ||
40 | + * 1 must be clear. | ||
41 | + * Here we set the size and is not 0xffffffff | ||
42 | + */ | ||
43 | + | ||
44 | + /* | ||
45 | + * I don't know how l can have all bits set. Copied from old code. | ||
46 | + * Maybe it fixes a bug on some ancient platform. | ||
47 | + */ | ||
48 | + if (l == 0xffffffff) | ||
49 | + l = 0; | ||
50 | + | ||
51 | + if (type == pci_bar_unknown) { | ||
52 | + res->flags = decode_bar(dev, l); | ||
53 | + res->flags |= IORESOURCE_SIZEALIGN; | ||
54 | + if (res->flags & IORESOURCE_IO) { | ||
55 | + l64 = l & PCI_BASE_ADDRESS_IO_MASK; | ||
56 | + sz64 = sz & PCI_BASE_ADDRESS_IO_MASK; | ||
57 | + mask64 = PCI_BASE_ADDRESS_IO_MASK & (u32)IO_SPACE_LIMIT; | ||
58 | + } else { | ||
59 | + l64 = l & PCI_BASE_ADDRESS_MEM_MASK; | ||
60 | + sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; | ||
61 | + mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; | ||
62 | + } | ||
63 | + } else { | ||
64 | + res->flags |= (l & IORESOURCE_ROM_ENABLE); | ||
65 | + l64 = l & PCI_ROM_ADDRESS_MASK; | ||
66 | + sz64 = sz & PCI_ROM_ADDRESS_MASK; | ||
67 | + mask64 = (u32)PCI_ROM_ADDRESS_MASK; | ||
68 | + } | ||
69 | + | ||
70 | + if (res->flags & IORESOURCE_MEM_64) { | ||
71 | + pci_read_config_dword(dev, pos + 4, &l); | ||
72 | + sz = sz2_in; | ||
73 | + | ||
74 | + l64 |= ((u64)l << 32); | ||
75 | + sz64 |= ((u64)sz << 32); | ||
76 | + mask64 |= ((u64)~0 << 32); | ||
77 | + } | ||
78 | + | ||
79 | + if (!sz64) | ||
80 | + goto fail; | ||
81 | + | ||
82 | + sz64 = pci_size(l64, sz64, mask64); | ||
83 | + if (!sz64) { | ||
84 | + dev_info(&dev->dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n", | ||
85 | + pos); | ||
86 | + goto fail; | ||
87 | + } | ||
88 | + | ||
89 | + if (res->flags & IORESOURCE_MEM_64) { | ||
90 | + if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && | ||
91 | + sz64 > 0x100000000ULL) { | ||
92 | + res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; | ||
93 | + res->start = 0; | ||
94 | + res->end = 0; | ||
95 | + dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", | ||
96 | + pos, (unsigned long long)sz64); | ||
97 | + goto out; | ||
98 | + } | ||
99 | + | ||
100 | + if ((sizeof(dma_addr_t) < 8) && l) { | ||
101 | + /* Above 32-bit boundary; try to reallocate */ | ||
102 | + res->flags |= IORESOURCE_UNSET; | ||
103 | + res->start = 0; | ||
104 | + res->end = sz64; | ||
105 | + dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n", | ||
106 | + pos, (unsigned long long)l64); | ||
107 | + goto out; | ||
108 | + } | ||
109 | + } | ||
110 | + | ||
111 | + region.start = l64; | ||
112 | + region.end = l64 + sz64; | ||
113 | + | ||
114 | + pcibios_bus_to_resource(dev->bus, res, ®ion); | ||
115 | + pcibios_resource_to_bus(dev->bus, &inverted_region, res); | ||
116 | + | ||
117 | + /* | ||
118 | + * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is | ||
119 | + * the corresponding resource address (the physical address used by | ||
120 | + * the CPU. Converting that resource address back to a bus address | ||
121 | + * should yield the original BAR value: | ||
122 | + * | ||
123 | + * resource_to_bus(bus_to_resource(A)) == A | ||
124 | + * | ||
125 | + * If it doesn't, CPU accesses to "bus_to_resource(A)" will not | ||
126 | + * be claimed by the device. | ||
127 | + */ | ||
128 | + if (inverted_region.start != region.start) { | ||
129 | + res->flags |= IORESOURCE_UNSET; | ||
130 | + res->start = 0; | ||
131 | + res->end = region.end - region.start; | ||
132 | + dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", | ||
133 | + pos, (unsigned long long)region.start); | ||
134 | + } | ||
135 | + | ||
136 | + goto out; | ||
137 | + | ||
138 | + | ||
139 | +fail: | ||
140 | + res->flags = 0; | ||
141 | +out: | ||
142 | + if (res->flags) | ||
143 | + dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); | ||
144 | + | ||
145 | + return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; | ||
146 | +} | ||
147 | + | ||
148 | +static int is_known_device(struct pci_dev *dev, int pos, int *sz) | ||
149 | +{ | ||
150 | + /* Red Hat, Inc : Virtio network device */ | ||
151 | + if (dev->vendor == 0x1af4 && dev->device == 0x1000) { | ||
152 | + if (pos == 0x10) { | ||
153 | + *sz = 0xffffffe1; | ||
154 | + return 1; | ||
155 | + } | ||
156 | + if (pos == 0x14) { | ||
157 | + *sz = 0xfffff000; | ||
158 | + return 1; | ||
159 | + } | ||
160 | + } | ||
161 | + /* Red Hat, Inc : Virtio block device */ | ||
162 | + if (dev->vendor == 0x1af4 && dev->device == 0x1001) { | ||
163 | + if (pos == 0x10) { | ||
164 | + *sz = 0xffffffc1; | ||
165 | + return 1; | ||
166 | + } | ||
167 | + if (pos == 0x14) { | ||
168 | + *sz = 0xfffff000; | ||
169 | + return 1; | ||
170 | + } | ||
171 | + } | ||
172 | + return 0; | ||
173 | +} | ||
174 | + | ||
175 | /** | ||
176 | * pci_read_base - read a PCI BAR | ||
177 | * @dev: the PCI device | ||
178 | @@ -182,6 +335,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | ||
179 | |||
180 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; | ||
181 | |||
182 | + if (is_known_device(dev, pos, &sz)) | ||
183 | + return __pci_read_base_shortcut(dev, type, res, pos, sz, 0); | ||
184 | + | ||
185 | res->name = pci_name(dev); | ||
186 | |||
187 | printk("clr: Starting probe for %s\n", res->name); | ||
188 | -- | ||
189 | 2.11.1 | ||
190 | |||