diff options
-rw-r--r-- | drivers/pci/host/pci-host-generic.c | 120 |
1 files changed, 27 insertions, 93 deletions
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c index 1e1a80fc6faa..18959075d164 100644 --- a/drivers/pci/host/pci-host-generic.c +++ b/drivers/pci/host/pci-host-generic.c | |||
@@ -32,7 +32,7 @@ struct gen_pci_cfg_bus_ops { | |||
32 | 32 | ||
33 | struct gen_pci_cfg_windows { | 33 | struct gen_pci_cfg_windows { |
34 | struct resource res; | 34 | struct resource res; |
35 | struct resource bus_range; | 35 | struct resource *bus_range; |
36 | void __iomem **win; | 36 | void __iomem **win; |
37 | 37 | ||
38 | const struct gen_pci_cfg_bus_ops *ops; | 38 | const struct gen_pci_cfg_bus_ops *ops; |
@@ -50,7 +50,7 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus, | |||
50 | { | 50 | { |
51 | struct pci_sys_data *sys = bus->sysdata; | 51 | struct pci_sys_data *sys = bus->sysdata; |
52 | struct gen_pci *pci = sys->private_data; | 52 | struct gen_pci *pci = sys->private_data; |
53 | resource_size_t idx = bus->number - pci->cfg.bus_range.start; | 53 | resource_size_t idx = bus->number - pci->cfg.bus_range->start; |
54 | 54 | ||
55 | return pci->cfg.win[idx] + ((devfn << 8) | where); | 55 | return pci->cfg.win[idx] + ((devfn << 8) | where); |
56 | } | 56 | } |
@@ -66,7 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus, | |||
66 | { | 66 | { |
67 | struct pci_sys_data *sys = bus->sysdata; | 67 | struct pci_sys_data *sys = bus->sysdata; |
68 | struct gen_pci *pci = sys->private_data; | 68 | struct gen_pci *pci = sys->private_data; |
69 | resource_size_t idx = bus->number - pci->cfg.bus_range.start; | 69 | resource_size_t idx = bus->number - pci->cfg.bus_range->start; |
70 | 70 | ||
71 | return pci->cfg.win[idx] + ((devfn << 12) | where); | 71 | return pci->cfg.win[idx] + ((devfn << 12) | where); |
72 | } | 72 | } |
@@ -138,106 +138,50 @@ static const struct of_device_id gen_pci_of_match[] = { | |||
138 | }; | 138 | }; |
139 | MODULE_DEVICE_TABLE(of, gen_pci_of_match); | 139 | MODULE_DEVICE_TABLE(of, gen_pci_of_match); |
140 | 140 | ||
141 | static int gen_pci_calc_io_offset(struct device *dev, | ||
142 | struct of_pci_range *range, | ||
143 | struct resource *res, | ||
144 | resource_size_t *offset) | ||
145 | { | ||
146 | static atomic_t wins = ATOMIC_INIT(0); | ||
147 | int err, idx, max_win; | ||
148 | unsigned int window; | ||
149 | |||
150 | if (!PAGE_ALIGNED(range->cpu_addr)) | ||
151 | return -EINVAL; | ||
152 | |||
153 | max_win = (IO_SPACE_LIMIT + 1) / SZ_64K; | ||
154 | idx = atomic_inc_return(&wins); | ||
155 | if (idx > max_win) | ||
156 | return -ENOSPC; | ||
157 | |||
158 | window = (idx - 1) * SZ_64K; | ||
159 | err = pci_ioremap_io(window, range->cpu_addr); | ||
160 | if (err) | ||
161 | return err; | ||
162 | |||
163 | of_pci_range_to_resource(range, dev->of_node, res); | ||
164 | res->start = window; | ||
165 | res->end = res->start + range->size - 1; | ||
166 | *offset = window - range->pci_addr; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int gen_pci_calc_mem_offset(struct device *dev, | ||
171 | struct of_pci_range *range, | ||
172 | struct resource *res, | ||
173 | resource_size_t *offset) | ||
174 | { | ||
175 | of_pci_range_to_resource(range, dev->of_node, res); | ||
176 | *offset = range->cpu_addr - range->pci_addr; | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) | 141 | static void gen_pci_release_of_pci_ranges(struct gen_pci *pci) |
181 | { | 142 | { |
182 | struct pci_host_bridge_window *win; | ||
183 | |||
184 | list_for_each_entry(win, &pci->resources, list) | ||
185 | release_resource(win->res); | ||
186 | |||
187 | pci_free_resource_list(&pci->resources); | 143 | pci_free_resource_list(&pci->resources); |
188 | } | 144 | } |
189 | 145 | ||
190 | static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) | 146 | static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci) |
191 | { | 147 | { |
192 | struct of_pci_range range; | ||
193 | struct of_pci_range_parser parser; | ||
194 | int err, res_valid = 0; | 148 | int err, res_valid = 0; |
195 | struct device *dev = pci->host.dev.parent; | 149 | struct device *dev = pci->host.dev.parent; |
196 | struct device_node *np = dev->of_node; | 150 | struct device_node *np = dev->of_node; |
151 | resource_size_t iobase; | ||
152 | struct pci_host_bridge_window *win; | ||
197 | 153 | ||
198 | if (of_pci_range_parser_init(&parser, np)) { | 154 | err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources, |
199 | dev_err(dev, "missing \"ranges\" property\n"); | 155 | &iobase); |
200 | return -EINVAL; | 156 | if (err) |
201 | } | 157 | return err; |
202 | 158 | ||
203 | for_each_of_pci_range(&parser, &range) { | 159 | list_for_each_entry(win, &pci->resources, list) { |
204 | struct resource *parent, *res; | 160 | struct resource *parent, *res = win->res; |
205 | resource_size_t offset; | ||
206 | u32 restype = range.flags & IORESOURCE_TYPE_BITS; | ||
207 | 161 | ||
208 | res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL); | 162 | switch (resource_type(res)) { |
209 | if (!res) { | ||
210 | err = -ENOMEM; | ||
211 | goto out_release_res; | ||
212 | } | ||
213 | |||
214 | switch (restype) { | ||
215 | case IORESOURCE_IO: | 163 | case IORESOURCE_IO: |
216 | parent = &ioport_resource; | 164 | parent = &ioport_resource; |
217 | err = gen_pci_calc_io_offset(dev, &range, res, &offset); | 165 | err = pci_remap_iospace(res, iobase); |
166 | if (err) { | ||
167 | dev_warn(dev, "error %d: failed to map resource %pR\n", | ||
168 | err, res); | ||
169 | continue; | ||
170 | } | ||
218 | break; | 171 | break; |
219 | case IORESOURCE_MEM: | 172 | case IORESOURCE_MEM: |
220 | parent = &iomem_resource; | 173 | parent = &iomem_resource; |
221 | err = gen_pci_calc_mem_offset(dev, &range, res, &offset); | 174 | res_valid |= !(res->flags & IORESOURCE_PREFETCH); |
222 | res_valid |= !(res->flags & IORESOURCE_PREFETCH || err); | ||
223 | break; | 175 | break; |
176 | case IORESOURCE_BUS: | ||
177 | pci->cfg.bus_range = res; | ||
224 | default: | 178 | default: |
225 | err = -EINVAL; | ||
226 | continue; | 179 | continue; |
227 | } | 180 | } |
228 | 181 | ||
229 | if (err) { | 182 | err = devm_request_resource(dev, parent, res); |
230 | dev_warn(dev, | ||
231 | "error %d: failed to add resource [type 0x%x, %lld bytes]\n", | ||
232 | err, restype, range.size); | ||
233 | continue; | ||
234 | } | ||
235 | |||
236 | err = request_resource(parent, res); | ||
237 | if (err) | 183 | if (err) |
238 | goto out_release_res; | 184 | goto out_release_res; |
239 | |||
240 | pci_add_resource_offset(&pci->resources, res, offset); | ||
241 | } | 185 | } |
242 | 186 | ||
243 | if (!res_valid) { | 187 | if (!res_valid) { |
@@ -262,14 +206,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) | |||
262 | struct device *dev = pci->host.dev.parent; | 206 | struct device *dev = pci->host.dev.parent; |
263 | struct device_node *np = dev->of_node; | 207 | struct device_node *np = dev->of_node; |
264 | 208 | ||
265 | if (of_pci_parse_bus_range(np, &pci->cfg.bus_range)) | ||
266 | pci->cfg.bus_range = (struct resource) { | ||
267 | .name = np->name, | ||
268 | .start = 0, | ||
269 | .end = 0xff, | ||
270 | .flags = IORESOURCE_BUS, | ||
271 | }; | ||
272 | |||
273 | err = of_address_to_resource(np, 0, &pci->cfg.res); | 209 | err = of_address_to_resource(np, 0, &pci->cfg.res); |
274 | if (err) { | 210 | if (err) { |
275 | dev_err(dev, "missing \"reg\" property\n"); | 211 | dev_err(dev, "missing \"reg\" property\n"); |
@@ -277,12 +213,12 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) | |||
277 | } | 213 | } |
278 | 214 | ||
279 | /* Limit the bus-range to fit within reg */ | 215 | /* Limit the bus-range to fit within reg */ |
280 | bus_max = pci->cfg.bus_range.start + | 216 | bus_max = pci->cfg.bus_range->start + |
281 | (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; | 217 | (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1; |
282 | pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end, | 218 | pci->cfg.bus_range->end = min_t(resource_size_t, |
283 | bus_max); | 219 | pci->cfg.bus_range->end, bus_max); |
284 | 220 | ||
285 | pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range), | 221 | pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range), |
286 | sizeof(*pci->cfg.win), GFP_KERNEL); | 222 | sizeof(*pci->cfg.win), GFP_KERNEL); |
287 | if (!pci->cfg.win) | 223 | if (!pci->cfg.win) |
288 | return -ENOMEM; | 224 | return -ENOMEM; |
@@ -293,7 +229,7 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) | |||
293 | "Configuration Space")) | 229 | "Configuration Space")) |
294 | return -ENOMEM; | 230 | return -ENOMEM; |
295 | 231 | ||
296 | bus_range = &pci->cfg.bus_range; | 232 | bus_range = pci->cfg.bus_range; |
297 | for (busn = bus_range->start; busn <= bus_range->end; ++busn) { | 233 | for (busn = bus_range->start; busn <= bus_range->end; ++busn) { |
298 | u32 idx = busn - bus_range->start; | 234 | u32 idx = busn - bus_range->start; |
299 | u32 sz = 1 << pci->cfg.ops->bus_shift; | 235 | u32 sz = 1 << pci->cfg.ops->bus_shift; |
@@ -305,8 +241,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) | |||
305 | return -ENOMEM; | 241 | return -ENOMEM; |
306 | } | 242 | } |
307 | 243 | ||
308 | /* Register bus resource */ | ||
309 | pci_add_resource(&pci->resources, bus_range); | ||
310 | return 0; | 244 | return 0; |
311 | } | 245 | } |
312 | 246 | ||