]>
Commit | Line | Data |
---|---|---|
adbb3901 | 1 | // SPDX-License-Identifier: GPL-2.0 |
cd248341 JG |
2 | /* |
3 | * Copyright IBM Corp. 2012 | |
4 | * | |
5 | * Author(s): | |
6 | * Jan Glauber <jang@linux.vnet.ibm.com> | |
7 | * | |
8 | * The System z PCI code is a rewrite from a prototype by | |
9 | * the following people (Kudoz!): | |
bedef755 JG |
10 | * Alexander Schmidt |
11 | * Christoph Raisch | |
12 | * Hannes Hering | |
13 | * Hoang-Nam Nguyen | |
14 | * Jan-Bernd Themann | |
15 | * Stefan Roscher | |
16 | * Thomas Klein | |
cd248341 JG |
17 | */ |
18 | ||
896cb7e6 GS |
19 | #define KMSG_COMPONENT "zpci" |
20 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
cd248341 JG |
21 | |
22 | #include <linux/kernel.h> | |
23 | #include <linux/slab.h> | |
24 | #include <linux/err.h> | |
25 | #include <linux/export.h> | |
26 | #include <linux/delay.h> | |
9a4da8a5 JG |
27 | #include <linux/irq.h> |
28 | #include <linux/kernel_stat.h> | |
cd248341 JG |
29 | #include <linux/seq_file.h> |
30 | #include <linux/pci.h> | |
31 | #include <linux/msi.h> | |
32 | ||
9a4da8a5 JG |
33 | #include <asm/isc.h> |
34 | #include <asm/airq.h> | |
cd248341 JG |
35 | #include <asm/facility.h> |
36 | #include <asm/pci_insn.h> | |
a755a45d | 37 | #include <asm/pci_clp.h> |
828b35f6 | 38 | #include <asm/pci_dma.h> |
cd248341 JG |
39 | |
40 | #define DEBUG /* enable pr_debug */ | |
41 | ||
9a4da8a5 JG |
42 | #define SIC_IRQ_MODE_ALL 0 |
43 | #define SIC_IRQ_MODE_SINGLE 1 | |
44 | ||
cd248341 JG |
45 | #define ZPCI_NR_DMA_SPACES 1 |
46 | #define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS | |
47 | ||
48 | /* list of all detected zpci devices */ | |
67f43f38 | 49 | static LIST_HEAD(zpci_list); |
57b5918c | 50 | static DEFINE_SPINLOCK(zpci_list_lock); |
cd248341 | 51 | |
1f44a225 MS |
52 | static struct irq_chip zpci_irq_chip = { |
53 | .name = "zPCI", | |
280510f1 TG |
54 | .irq_unmask = pci_msi_unmask_irq, |
55 | .irq_mask = pci_msi_mask_irq, | |
9a4da8a5 JG |
56 | }; |
57 | ||
1f44a225 MS |
58 | static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); |
59 | static DEFINE_SPINLOCK(zpci_domain_lock); | |
9a4da8a5 | 60 | |
5d0d8f43 | 61 | static struct airq_iv *zpci_aisb_iv; |
1f44a225 | 62 | static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES]; |
9a4da8a5 | 63 | |
c506fff3 | 64 | #define ZPCI_IOMAP_ENTRIES \ |
b0c8ce89 | 65 | min(((unsigned long) ZPCI_NR_DEVICES * PCI_BAR_COUNT / 2), \ |
c506fff3 SO |
66 | ZPCI_IOMAP_MAX_ENTRIES) |
67 | ||
cd248341 | 68 | static DEFINE_SPINLOCK(zpci_iomap_lock); |
c506fff3 | 69 | static unsigned long *zpci_iomap_bitmap; |
cd248341 JG |
70 | struct zpci_iomap_entry *zpci_iomap_start; |
71 | EXPORT_SYMBOL_GPL(zpci_iomap_start); | |
72 | ||
d0b08853 JG |
73 | static struct kmem_cache *zdev_fmb_cache; |
74 | ||
cd248341 JG |
75 | struct zpci_dev *get_zdev_by_fid(u32 fid) |
76 | { | |
77 | struct zpci_dev *tmp, *zdev = NULL; | |
78 | ||
57b5918c | 79 | spin_lock(&zpci_list_lock); |
cd248341 JG |
80 | list_for_each_entry(tmp, &zpci_list, entry) { |
81 | if (tmp->fid == fid) { | |
82 | zdev = tmp; | |
83 | break; | |
84 | } | |
85 | } | |
57b5918c | 86 | spin_unlock(&zpci_list_lock); |
cd248341 JG |
87 | return zdev; |
88 | } | |
89 | ||
01553d9a SO |
90 | void zpci_remove_reserved_devices(void) |
91 | { | |
92 | struct zpci_dev *tmp, *zdev; | |
93 | enum zpci_state state; | |
94 | LIST_HEAD(remove); | |
95 | ||
96 | spin_lock(&zpci_list_lock); | |
97 | list_for_each_entry_safe(zdev, tmp, &zpci_list, entry) { | |
98 | if (zdev->state == ZPCI_FN_STATE_STANDBY && | |
99 | !clp_get_state(zdev->fid, &state) && | |
100 | state == ZPCI_FN_STATE_RESERVED) | |
101 | list_move_tail(&zdev->entry, &remove); | |
102 | } | |
103 | spin_unlock(&zpci_list_lock); | |
104 | ||
105 | list_for_each_entry_safe(zdev, tmp, &remove, entry) | |
106 | zpci_remove_device(zdev); | |
107 | } | |
108 | ||
cd248341 JG |
109 | static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus) |
110 | { | |
111 | return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL; | |
112 | } | |
113 | ||
114 | int pci_domain_nr(struct pci_bus *bus) | |
115 | { | |
116 | return ((struct zpci_dev *) bus->sysdata)->domain; | |
117 | } | |
118 | EXPORT_SYMBOL_GPL(pci_domain_nr); | |
119 | ||
120 | int pci_proc_domain(struct pci_bus *bus) | |
121 | { | |
122 | return pci_domain_nr(bus); | |
123 | } | |
124 | EXPORT_SYMBOL_GPL(pci_proc_domain); | |
125 | ||
9a4da8a5 | 126 | /* Modify PCI: Register adapter interruptions */ |
5d0d8f43 | 127 | static int zpci_set_airq(struct zpci_dev *zdev) |
9a4da8a5 JG |
128 | { |
129 | u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT); | |
cb4deb69 | 130 | struct zpci_fib fib = {0}; |
4dfbd3ef | 131 | u8 status; |
9a4da8a5 | 132 | |
cb4deb69 SO |
133 | fib.isc = PCI_ISC; |
134 | fib.sum = 1; /* enable summary notifications */ | |
135 | fib.noi = airq_iv_end(zdev->aibv); | |
136 | fib.aibv = (unsigned long) zdev->aibv->vector; | |
137 | fib.aibvo = 0; /* each zdev has its own interrupt vector */ | |
138 | fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8; | |
139 | fib.aisbo = zdev->aisb & 63; | |
9a4da8a5 | 140 | |
4dfbd3ef SO |
141 | return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; |
142 | } | |
143 | ||
144 | /* Modify PCI: Unregister adapter interruptions */ | |
145 | static int zpci_clear_airq(struct zpci_dev *zdev) | |
146 | { | |
147 | u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT); | |
148 | struct zpci_fib fib = {0}; | |
149 | u8 cc, status; | |
150 | ||
151 | cc = zpci_mod_fc(req, &fib, &status); | |
152 | if (cc == 3 || (cc == 1 && status == 24)) | |
153 | /* Function already gone or IRQs already deregistered. */ | |
154 | cc = 0; | |
155 | ||
156 | return cc ? -EIO : 0; | |
9a4da8a5 JG |
157 | } |
158 | ||
828b35f6 JG |
159 | /* Modify PCI: Register I/O address translation parameters */ |
160 | int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, | |
161 | u64 base, u64 limit, u64 iota) | |
162 | { | |
72570834 SO |
163 | u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_REG_IOAT); |
164 | struct zpci_fib fib = {0}; | |
165 | u8 status; | |
828b35f6 JG |
166 | |
167 | WARN_ON_ONCE(iota & 0x3fff); | |
72570834 SO |
168 | fib.pba = base; |
169 | fib.pal = limit; | |
170 | fib.iota = iota | ZPCI_IOTA_RTTO_FLAG; | |
171 | return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; | |
828b35f6 JG |
172 | } |
173 | ||
174 | /* Modify PCI: Unregister I/O address translation parameters */ | |
175 | int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) | |
176 | { | |
72570834 SO |
177 | u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_DEREG_IOAT); |
178 | struct zpci_fib fib = {0}; | |
179 | u8 cc, status; | |
828b35f6 | 180 | |
72570834 SO |
181 | cc = zpci_mod_fc(req, &fib, &status); |
182 | if (cc == 3) /* Function already gone. */ | |
183 | cc = 0; | |
184 | return cc ? -EIO : 0; | |
828b35f6 JG |
185 | } |
186 | ||
d0b08853 JG |
187 | /* Modify PCI: Set PCI function measurement parameters */ |
188 | int zpci_fmb_enable_device(struct zpci_dev *zdev) | |
189 | { | |
4e5bd780 SO |
190 | u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE); |
191 | struct zpci_fib fib = {0}; | |
192 | u8 cc, status; | |
d0b08853 | 193 | |
0b7589ec | 194 | if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length) |
d0b08853 JG |
195 | return -EINVAL; |
196 | ||
08b42124 | 197 | zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL); |
d0b08853 JG |
198 | if (!zdev->fmb) |
199 | return -ENOMEM; | |
d0b08853 JG |
200 | WARN_ON((u64) zdev->fmb & 0xf); |
201 | ||
6001018a SO |
202 | /* reset software counters */ |
203 | atomic64_set(&zdev->allocated_pages, 0); | |
204 | atomic64_set(&zdev->mapped_pages, 0); | |
205 | atomic64_set(&zdev->unmapped_pages, 0); | |
206 | ||
4e5bd780 SO |
207 | fib.fmb_addr = virt_to_phys(zdev->fmb); |
208 | cc = zpci_mod_fc(req, &fib, &status); | |
209 | if (cc) { | |
210 | kmem_cache_free(zdev_fmb_cache, zdev->fmb); | |
211 | zdev->fmb = NULL; | |
212 | } | |
213 | return cc ? -EIO : 0; | |
d0b08853 JG |
214 | } |
215 | ||
216 | /* Modify PCI: Disable PCI function measurement */ | |
217 | int zpci_fmb_disable_device(struct zpci_dev *zdev) | |
218 | { | |
4e5bd780 SO |
219 | u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE); |
220 | struct zpci_fib fib = {0}; | |
221 | u8 cc, status; | |
d0b08853 JG |
222 | |
223 | if (!zdev->fmb) | |
224 | return -EINVAL; | |
225 | ||
226 | /* Function measurement is disabled if fmb address is zero */ | |
4e5bd780 SO |
227 | cc = zpci_mod_fc(req, &fib, &status); |
228 | if (cc == 3) /* Function already gone. */ | |
229 | cc = 0; | |
d0b08853 | 230 | |
4e5bd780 SO |
231 | if (!cc) { |
232 | kmem_cache_free(zdev_fmb_cache, zdev->fmb); | |
233 | zdev->fmb = NULL; | |
234 | } | |
235 | return cc ? -EIO : 0; | |
d0b08853 JG |
236 | } |
237 | ||
cd248341 JG |
238 | static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) |
239 | { | |
240 | u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len); | |
241 | u64 data; | |
242 | int rc; | |
243 | ||
9389339f | 244 | rc = zpci_load(&data, req, offset); |
b170bad4 | 245 | if (!rc) { |
5064cd35 SO |
246 | data = le64_to_cpu((__force __le64) data); |
247 | data >>= (8 - len) * 8; | |
cd248341 | 248 | *val = (u32) data; |
b170bad4 | 249 | } else |
cd248341 JG |
250 | *val = 0xffffffff; |
251 | return rc; | |
252 | } | |
253 | ||
254 | static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len) | |
255 | { | |
256 | u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len); | |
257 | u64 data = val; | |
258 | int rc; | |
259 | ||
5064cd35 SO |
260 | data <<= (8 - len) * 8; |
261 | data = (__force u64) cpu_to_le64(data); | |
9389339f | 262 | rc = zpci_store(data, req, offset); |
cd248341 JG |
263 | return rc; |
264 | } | |
265 | ||
cd248341 JG |
266 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, |
267 | resource_size_t size, | |
268 | resource_size_t align) | |
269 | { | |
270 | return 0; | |
271 | } | |
272 | ||
87bc359b JG |
273 | /* combine single writes by using store-block insn */ |
274 | void __iowrite64_copy(void __iomem *to, const void *from, size_t count) | |
275 | { | |
276 | zpci_memcpy_toio(to, from, count); | |
277 | } | |
278 | ||
cd248341 | 279 | /* Create a virtual mapping cookie for a PCI BAR */ |
8cfc99b5 MT |
280 | void __iomem *pci_iomap_range(struct pci_dev *pdev, |
281 | int bar, | |
282 | unsigned long offset, | |
283 | unsigned long max) | |
cd248341 | 284 | { |
198a5278 | 285 | struct zpci_dev *zdev = to_zpci(pdev); |
cd248341 JG |
286 | int idx; |
287 | ||
c0cabadd | 288 | if (!pci_resource_len(pdev, bar)) |
cd248341 JG |
289 | return NULL; |
290 | ||
291 | idx = zdev->bars[bar].map_idx; | |
292 | spin_lock(&zpci_iomap_lock); | |
8cfc99b5 | 293 | /* Detect overrun */ |
f5e44f82 SO |
294 | WARN_ON(!++zpci_iomap_start[idx].count); |
295 | zpci_iomap_start[idx].fh = zdev->fh; | |
296 | zpci_iomap_start[idx].bar = bar; | |
cd248341 JG |
297 | spin_unlock(&zpci_iomap_lock); |
298 | ||
9e00caae | 299 | return (void __iomem *) ZPCI_ADDR(idx) + offset; |
cd248341 | 300 | } |
d9426083 | 301 | EXPORT_SYMBOL(pci_iomap_range); |
8cfc99b5 MT |
302 | |
303 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) | |
304 | { | |
305 | return pci_iomap_range(dev, bar, 0, maxlen); | |
306 | } | |
307 | EXPORT_SYMBOL(pci_iomap); | |
cd248341 JG |
308 | |
309 | void pci_iounmap(struct pci_dev *pdev, void __iomem *addr) | |
310 | { | |
9e00caae | 311 | unsigned int idx = ZPCI_IDX(addr); |
cd248341 | 312 | |
cd248341 | 313 | spin_lock(&zpci_iomap_lock); |
8cfc99b5 | 314 | /* Detect underrun */ |
f5e44f82 | 315 | WARN_ON(!zpci_iomap_start[idx].count); |
8cfc99b5 MT |
316 | if (!--zpci_iomap_start[idx].count) { |
317 | zpci_iomap_start[idx].fh = 0; | |
318 | zpci_iomap_start[idx].bar = 0; | |
319 | } | |
cd248341 JG |
320 | spin_unlock(&zpci_iomap_lock); |
321 | } | |
d9426083 | 322 | EXPORT_SYMBOL(pci_iounmap); |
cd248341 JG |
323 | |
324 | static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |
325 | int size, u32 *val) | |
326 | { | |
327 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | |
2c3700bb | 328 | int ret; |
cd248341 JG |
329 | |
330 | if (!zdev || devfn != ZPCI_DEVFN) | |
2c3700bb SO |
331 | ret = -ENODEV; |
332 | else | |
333 | ret = zpci_cfg_load(zdev, where, val, size); | |
334 | ||
335 | return ret; | |
cd248341 JG |
336 | } |
337 | ||
338 | static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |
339 | int size, u32 val) | |
340 | { | |
341 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | |
2c3700bb | 342 | int ret; |
cd248341 JG |
343 | |
344 | if (!zdev || devfn != ZPCI_DEVFN) | |
2c3700bb SO |
345 | ret = -ENODEV; |
346 | else | |
347 | ret = zpci_cfg_store(zdev, where, val, size); | |
348 | ||
349 | return ret; | |
cd248341 JG |
350 | } |
351 | ||
352 | static struct pci_ops pci_root_ops = { | |
353 | .read = pci_read, | |
354 | .write = pci_write, | |
355 | }; | |
356 | ||
f4eae94f | 357 | static void zpci_irq_handler(struct airq_struct *airq) |
9a4da8a5 | 358 | { |
5d0d8f43 | 359 | unsigned long si, ai; |
1f44a225 | 360 | struct airq_iv *aibv; |
5d0d8f43 | 361 | int irqs_on = 0; |
9a4da8a5 | 362 | |
420f42ec | 363 | inc_irq_stat(IRQIO_PCI); |
5d0d8f43 MS |
364 | for (si = 0;;) { |
365 | /* Scan adapter summary indicator bit vector */ | |
366 | si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv)); | |
367 | if (si == -1UL) { | |
368 | if (irqs_on++) | |
369 | /* End of second scan with interrupts on. */ | |
370 | break; | |
371 | /* First scan complete, reenable interrupts. */ | |
48070c73 CB |
372 | if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC)) |
373 | break; | |
5d0d8f43 MS |
374 | si = 0; |
375 | continue; | |
376 | } | |
9a4da8a5 | 377 | |
5d0d8f43 | 378 | /* Scan the adapter interrupt vector for this device. */ |
1f44a225 | 379 | aibv = zpci_aibv[si]; |
5d0d8f43 | 380 | for (ai = 0;;) { |
1f44a225 | 381 | ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv)); |
5d0d8f43 MS |
382 | if (ai == -1UL) |
383 | break; | |
420f42ec | 384 | inc_irq_stat(IRQIO_MSI); |
1f44a225 | 385 | generic_handle_irq(airq_iv_get_data(aibv, ai)); |
9a4da8a5 JG |
386 | } |
387 | } | |
5d0d8f43 | 388 | } |
9a4da8a5 | 389 | |
5d0d8f43 | 390 | int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
9a4da8a5 | 391 | { |
198a5278 | 392 | struct zpci_dev *zdev = to_zpci(pdev); |
0a0a9421 | 393 | unsigned int hwirq, msi_vecs; |
5d0d8f43 | 394 | unsigned long aisb; |
9a4da8a5 | 395 | struct msi_desc *msi; |
1f44a225 | 396 | struct msi_msg msg; |
0a0a9421 | 397 | int rc, irq; |
9a4da8a5 | 398 | |
795818e8 | 399 | zdev->aisb = -1UL; |
a384c892 AG |
400 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
401 | return 1; | |
b19148f6 | 402 | msi_vecs = min_t(unsigned int, nvec, zdev->max_msi); |
9a4da8a5 | 403 | |
5d0d8f43 | 404 | /* Allocate adapter summary indicator bit */ |
5d0d8f43 MS |
405 | aisb = airq_iv_alloc_bit(zpci_aisb_iv); |
406 | if (aisb == -1UL) | |
795818e8 | 407 | return -EIO; |
9a4da8a5 | 408 | zdev->aisb = aisb; |
9a4da8a5 | 409 | |
5d0d8f43 | 410 | /* Create adapter interrupt vector */ |
9594ca6b | 411 | zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA); |
5d0d8f43 | 412 | if (!zdev->aibv) |
795818e8 | 413 | return -ENOMEM; |
9a4da8a5 | 414 | |
5d0d8f43 | 415 | /* Wire up shortcut pointer */ |
1f44a225 | 416 | zpci_aibv[aisb] = zdev->aibv; |
5d0d8f43 | 417 | |
1f44a225 MS |
418 | /* Request MSI interrupts */ |
419 | hwirq = 0; | |
df516f42 | 420 | for_each_pci_msi_entry(msi, pdev) { |
866f3576 SO |
421 | if (hwirq >= msi_vecs) |
422 | break; | |
1f44a225 | 423 | irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ |
0a0a9421 | 424 | if (irq < 0) |
795818e8 | 425 | return -ENOMEM; |
1f44a225 | 426 | rc = irq_set_msi_desc(irq, msi); |
9a4da8a5 | 427 | if (rc) |
795818e8 | 428 | return rc; |
1f44a225 MS |
429 | irq_set_chip_and_handler(irq, &zpci_irq_chip, |
430 | handle_simple_irq); | |
431 | msg.data = hwirq; | |
432 | msg.address_lo = zdev->msi_addr & 0xffffffff; | |
433 | msg.address_hi = zdev->msi_addr >> 32; | |
83a18912 | 434 | pci_write_msi_msg(irq, &msg); |
1f44a225 MS |
435 | airq_iv_set_data(zdev->aibv, hwirq, irq); |
436 | hwirq++; | |
9a4da8a5 JG |
437 | } |
438 | ||
5d0d8f43 MS |
439 | /* Enable adapter interrupts */ |
440 | rc = zpci_set_airq(zdev); | |
441 | if (rc) | |
795818e8 | 442 | return rc; |
5d0d8f43 MS |
443 | |
444 | return (msi_vecs == nvec) ? 0 : msi_vecs; | |
9a4da8a5 JG |
445 | } |
446 | ||
5d0d8f43 | 447 | void arch_teardown_msi_irqs(struct pci_dev *pdev) |
9a4da8a5 | 448 | { |
198a5278 | 449 | struct zpci_dev *zdev = to_zpci(pdev); |
9a4da8a5 | 450 | struct msi_desc *msi; |
5d0d8f43 MS |
451 | int rc; |
452 | ||
5d0d8f43 MS |
453 | /* Disable adapter interrupts */ |
454 | rc = zpci_clear_airq(zdev); | |
1f1dcbd4 | 455 | if (rc) |
9a4da8a5 | 456 | return; |
9a4da8a5 | 457 | |
1f44a225 | 458 | /* Release MSI interrupts */ |
df516f42 | 459 | for_each_pci_msi_entry(msi, pdev) { |
795818e8 SO |
460 | if (!msi->irq) |
461 | continue; | |
8fb878c5 | 462 | if (msi->msi_attrib.is_msix) |
23ed8d57 | 463 | __pci_msix_desc_mask_irq(msi, 1); |
8fb878c5 | 464 | else |
23ed8d57 | 465 | __pci_msi_desc_mask_irq(msi, 1, 1); |
1f44a225 MS |
466 | irq_set_msi_desc(msi->irq, NULL); |
467 | irq_free_desc(msi->irq); | |
468 | msi->msg.address_lo = 0; | |
469 | msi->msg.address_hi = 0; | |
470 | msi->msg.data = 0; | |
471 | msi->irq = 0; | |
472 | } | |
9a4da8a5 | 473 | |
795818e8 SO |
474 | if (zdev->aisb != -1UL) { |
475 | zpci_aibv[zdev->aisb] = NULL; | |
476 | airq_iv_free_bit(zpci_aisb_iv, zdev->aisb); | |
477 | zdev->aisb = -1UL; | |
478 | } | |
479 | if (zdev->aibv) { | |
480 | airq_iv_release(zdev->aibv); | |
481 | zdev->aibv = NULL; | |
482 | } | |
9a4da8a5 JG |
483 | } |
484 | ||
1803ba2d | 485 | static void zpci_map_resources(struct pci_dev *pdev) |
cd248341 | 486 | { |
cd248341 JG |
487 | resource_size_t len; |
488 | int i; | |
489 | ||
490 | for (i = 0; i < PCI_BAR_COUNT; i++) { | |
491 | len = pci_resource_len(pdev, i); | |
492 | if (!len) | |
493 | continue; | |
5b9f2081 MS |
494 | pdev->resource[i].start = |
495 | (resource_size_t __force) pci_iomap(pdev, i, 0); | |
cd248341 | 496 | pdev->resource[i].end = pdev->resource[i].start + len - 1; |
cd248341 | 497 | } |
944239c5 SO |
498 | } |
499 | ||
1803ba2d | 500 | static void zpci_unmap_resources(struct pci_dev *pdev) |
944239c5 | 501 | { |
944239c5 SO |
502 | resource_size_t len; |
503 | int i; | |
504 | ||
505 | for (i = 0; i < PCI_BAR_COUNT; i++) { | |
506 | len = pci_resource_len(pdev, i); | |
507 | if (!len) | |
508 | continue; | |
5b9f2081 MS |
509 | pci_iounmap(pdev, (void __iomem __force *) |
510 | pdev->resource[i].start); | |
944239c5 SO |
511 | } |
512 | } | |
cd248341 | 513 | |
561ecb0c SO |
514 | static struct airq_struct zpci_airq = { |
515 | .handler = zpci_irq_handler, | |
516 | .isc = PCI_ISC, | |
517 | }; | |
518 | ||
9a4da8a5 JG |
519 | static int __init zpci_irq_init(void) |
520 | { | |
5d0d8f43 | 521 | int rc; |
9a4da8a5 | 522 | |
f4eae94f MS |
523 | rc = register_adapter_interrupt(&zpci_airq); |
524 | if (rc) | |
5d0d8f43 | 525 | goto out; |
f4eae94f MS |
526 | /* Set summary to 1 to be called every time for the ISC. */ |
527 | *zpci_airq.lsi_ptr = 1; | |
9a4da8a5 | 528 | |
5d0d8f43 MS |
529 | rc = -ENOMEM; |
530 | zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC); | |
531 | if (!zpci_aisb_iv) | |
532 | goto out_airq; | |
9a4da8a5 | 533 | |
9389339f | 534 | zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); |
9a4da8a5 JG |
535 | return 0; |
536 | ||
5d0d8f43 MS |
537 | out_airq: |
538 | unregister_adapter_interrupt(&zpci_airq); | |
539 | out: | |
9a4da8a5 JG |
540 | return rc; |
541 | } | |
542 | ||
543 | static void zpci_irq_exit(void) | |
544 | { | |
5d0d8f43 | 545 | airq_iv_release(zpci_aisb_iv); |
f4eae94f | 546 | unregister_adapter_interrupt(&zpci_airq); |
9a4da8a5 JG |
547 | } |
548 | ||
cd248341 JG |
549 | static int zpci_alloc_iomap(struct zpci_dev *zdev) |
550 | { | |
bf19c94d | 551 | unsigned long entry; |
cd248341 JG |
552 | |
553 | spin_lock(&zpci_iomap_lock); | |
c506fff3 SO |
554 | entry = find_first_zero_bit(zpci_iomap_bitmap, ZPCI_IOMAP_ENTRIES); |
555 | if (entry == ZPCI_IOMAP_ENTRIES) { | |
cd248341 JG |
556 | spin_unlock(&zpci_iomap_lock); |
557 | return -ENOSPC; | |
558 | } | |
c506fff3 | 559 | set_bit(entry, zpci_iomap_bitmap); |
cd248341 JG |
560 | spin_unlock(&zpci_iomap_lock); |
561 | return entry; | |
562 | } | |
563 | ||
564 | static void zpci_free_iomap(struct zpci_dev *zdev, int entry) | |
565 | { | |
566 | spin_lock(&zpci_iomap_lock); | |
567 | memset(&zpci_iomap_start[entry], 0, sizeof(struct zpci_iomap_entry)); | |
c506fff3 | 568 | clear_bit(entry, zpci_iomap_bitmap); |
cd248341 JG |
569 | spin_unlock(&zpci_iomap_lock); |
570 | } | |
571 | ||
7a572a3a SO |
572 | static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start, |
573 | unsigned long size, unsigned long flags) | |
574 | { | |
575 | struct resource *r; | |
576 | ||
577 | r = kzalloc(sizeof(*r), GFP_KERNEL); | |
578 | if (!r) | |
579 | return NULL; | |
580 | ||
581 | r->start = start; | |
582 | r->end = r->start + size - 1; | |
583 | r->flags = flags; | |
584 | r->name = zdev->res_name; | |
585 | ||
586 | if (request_resource(&iomem_resource, r)) { | |
587 | kfree(r); | |
588 | return NULL; | |
589 | } | |
590 | return r; | |
591 | } | |
592 | ||
593 | static int zpci_setup_bus_resources(struct zpci_dev *zdev, | |
594 | struct list_head *resources) | |
595 | { | |
596 | unsigned long addr, size, flags; | |
597 | struct resource *res; | |
598 | int i, entry; | |
599 | ||
600 | snprintf(zdev->res_name, sizeof(zdev->res_name), | |
601 | "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR); | |
602 | ||
603 | for (i = 0; i < PCI_BAR_COUNT; i++) { | |
604 | if (!zdev->bars[i].size) | |
605 | continue; | |
606 | entry = zpci_alloc_iomap(zdev); | |
607 | if (entry < 0) | |
608 | return entry; | |
609 | zdev->bars[i].map_idx = entry; | |
610 | ||
611 | /* only MMIO is supported */ | |
612 | flags = IORESOURCE_MEM; | |
613 | if (zdev->bars[i].val & 8) | |
614 | flags |= IORESOURCE_PREFETCH; | |
615 | if (zdev->bars[i].val & 4) | |
616 | flags |= IORESOURCE_MEM_64; | |
617 | ||
9e00caae | 618 | addr = ZPCI_ADDR(entry); |
7a572a3a SO |
619 | size = 1UL << zdev->bars[i].size; |
620 | ||
621 | res = __alloc_res(zdev, addr, size, flags); | |
622 | if (!res) { | |
623 | zpci_free_iomap(zdev, entry); | |
624 | return -ENOMEM; | |
625 | } | |
626 | zdev->bars[i].res = res; | |
627 | pci_add_resource(resources, res); | |
628 | } | |
629 | ||
630 | return 0; | |
631 | } | |
632 | ||
633 | static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) | |
634 | { | |
635 | int i; | |
636 | ||
637 | for (i = 0; i < PCI_BAR_COUNT; i++) { | |
2b1df724 | 638 | if (!zdev->bars[i].size || !zdev->bars[i].res) |
7a572a3a SO |
639 | continue; |
640 | ||
641 | zpci_free_iomap(zdev, zdev->bars[i].map_idx); | |
642 | release_resource(zdev->bars[i].res); | |
643 | kfree(zdev->bars[i].res); | |
644 | } | |
645 | } | |
646 | ||
af0a8a84 SO |
647 | int pcibios_add_device(struct pci_dev *pdev) |
648 | { | |
cb809182 SO |
649 | struct resource *res; |
650 | int i; | |
651 | ||
7dc20ab1 SO |
652 | if (pdev->is_physfn) |
653 | pdev->no_vf_scan = 1; | |
654 | ||
ef4858c6 | 655 | pdev->dev.groups = zpci_attr_groups; |
5657933d | 656 | pdev->dev.dma_ops = &s390_pci_dma_ops; |
1803ba2d | 657 | zpci_map_resources(pdev); |
cb809182 SO |
658 | |
659 | for (i = 0; i < PCI_BAR_COUNT; i++) { | |
660 | res = &pdev->resource[i]; | |
661 | if (res->parent || !res->flags) | |
662 | continue; | |
663 | pci_claim_resource(pdev, i); | |
664 | } | |
665 | ||
666 | return 0; | |
667 | } | |
668 | ||
1803ba2d SO |
669 | void pcibios_release_device(struct pci_dev *pdev) |
670 | { | |
671 | zpci_unmap_resources(pdev); | |
672 | } | |
673 | ||
cb809182 SO |
674 | int pcibios_enable_device(struct pci_dev *pdev, int mask) |
675 | { | |
198a5278 | 676 | struct zpci_dev *zdev = to_zpci(pdev); |
af0a8a84 | 677 | |
9a99649f | 678 | zpci_debug_init_device(zdev, dev_name(&pdev->dev)); |
af0a8a84 | 679 | zpci_fmb_enable_device(zdev); |
af0a8a84 | 680 | |
d7533232 | 681 | return pci_enable_resources(pdev, mask); |
af0a8a84 SO |
682 | } |
683 | ||
cb809182 | 684 | void pcibios_disable_device(struct pci_dev *pdev) |
944239c5 | 685 | { |
198a5278 | 686 | struct zpci_dev *zdev = to_zpci(pdev); |
944239c5 | 687 | |
944239c5 SO |
688 | zpci_fmb_disable_device(zdev); |
689 | zpci_debug_exit_device(zdev); | |
944239c5 SO |
690 | } |
691 | ||
69db3b5e SO |
692 | #ifdef CONFIG_HIBERNATE_CALLBACKS |
693 | static int zpci_restore(struct device *dev) | |
694 | { | |
1803ba2d | 695 | struct pci_dev *pdev = to_pci_dev(dev); |
198a5278 | 696 | struct zpci_dev *zdev = to_zpci(pdev); |
69db3b5e SO |
697 | int ret = 0; |
698 | ||
699 | if (zdev->state != ZPCI_FN_STATE_ONLINE) | |
700 | goto out; | |
701 | ||
702 | ret = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES); | |
703 | if (ret) | |
704 | goto out; | |
705 | ||
1803ba2d | 706 | zpci_map_resources(pdev); |
69eea95c | 707 | zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, |
69db3b5e SO |
708 | (u64) zdev->dma_table); |
709 | ||
710 | out: | |
711 | return ret; | |
712 | } | |
713 | ||
714 | static int zpci_freeze(struct device *dev) | |
715 | { | |
1803ba2d | 716 | struct pci_dev *pdev = to_pci_dev(dev); |
198a5278 | 717 | struct zpci_dev *zdev = to_zpci(pdev); |
69db3b5e SO |
718 | |
719 | if (zdev->state != ZPCI_FN_STATE_ONLINE) | |
720 | return 0; | |
721 | ||
722 | zpci_unregister_ioat(zdev, 0); | |
1803ba2d | 723 | zpci_unmap_resources(pdev); |
69db3b5e SO |
724 | return clp_disable_fh(zdev); |
725 | } | |
726 | ||
727 | struct dev_pm_ops pcibios_pm_ops = { | |
728 | .thaw_noirq = zpci_restore, | |
729 | .freeze_noirq = zpci_freeze, | |
730 | .restore_noirq = zpci_restore, | |
731 | .poweroff_noirq = zpci_freeze, | |
732 | }; | |
733 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | |
734 | ||
cd248341 JG |
735 | static int zpci_alloc_domain(struct zpci_dev *zdev) |
736 | { | |
5c5afd02 SO |
737 | if (zpci_unique_uid) { |
738 | zdev->domain = (u16) zdev->uid; | |
312e8462 SO |
739 | if (zdev->domain >= ZPCI_NR_DEVICES) |
740 | return 0; | |
741 | ||
742 | spin_lock(&zpci_domain_lock); | |
743 | if (test_bit(zdev->domain, zpci_domain)) { | |
744 | spin_unlock(&zpci_domain_lock); | |
745 | return -EEXIST; | |
746 | } | |
747 | set_bit(zdev->domain, zpci_domain); | |
748 | spin_unlock(&zpci_domain_lock); | |
5c5afd02 SO |
749 | return 0; |
750 | } | |
751 | ||
cd248341 JG |
752 | spin_lock(&zpci_domain_lock); |
753 | zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES); | |
754 | if (zdev->domain == ZPCI_NR_DEVICES) { | |
755 | spin_unlock(&zpci_domain_lock); | |
756 | return -ENOSPC; | |
757 | } | |
758 | set_bit(zdev->domain, zpci_domain); | |
759 | spin_unlock(&zpci_domain_lock); | |
760 | return 0; | |
761 | } | |
762 | ||
763 | static void zpci_free_domain(struct zpci_dev *zdev) | |
764 | { | |
312e8462 | 765 | if (zdev->domain >= ZPCI_NR_DEVICES) |
5c5afd02 SO |
766 | return; |
767 | ||
cd248341 JG |
768 | spin_lock(&zpci_domain_lock); |
769 | clear_bit(zdev->domain, zpci_domain); | |
770 | spin_unlock(&zpci_domain_lock); | |
771 | } | |
772 | ||
7d594322 SO |
773 | void pcibios_remove_bus(struct pci_bus *bus) |
774 | { | |
775 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | |
776 | ||
777 | zpci_exit_slot(zdev); | |
778 | zpci_cleanup_bus_resources(zdev); | |
f42c2235 | 779 | zpci_destroy_iommu(zdev); |
7d594322 SO |
780 | zpci_free_domain(zdev); |
781 | ||
782 | spin_lock(&zpci_list_lock); | |
783 | list_del(&zdev->entry); | |
784 | spin_unlock(&zpci_list_lock); | |
785 | ||
be2c3676 | 786 | zpci_dbg(3, "rem fid:%x\n", zdev->fid); |
7d594322 SO |
787 | kfree(zdev); |
788 | } | |
789 | ||
790 | static int zpci_scan_bus(struct zpci_dev *zdev) | |
791 | { | |
792 | LIST_HEAD(resources); | |
793 | int ret; | |
794 | ||
795 | ret = zpci_setup_bus_resources(zdev, &resources); | |
796 | if (ret) | |
2b1df724 | 797 | goto error; |
7d594322 SO |
798 | |
799 | zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, | |
800 | zdev, &resources); | |
801 | if (!zdev->bus) { | |
2b1df724 SO |
802 | ret = -EIO; |
803 | goto error; | |
7d594322 | 804 | } |
7d594322 | 805 | zdev->bus->max_bus_speed = zdev->max_bus_speed; |
b97ea289 | 806 | pci_bus_add_devices(zdev->bus); |
7d594322 | 807 | return 0; |
2b1df724 SO |
808 | |
809 | error: | |
810 | zpci_cleanup_bus_resources(zdev); | |
811 | pci_free_resource_list(&resources); | |
812 | return ret; | |
7d594322 SO |
813 | } |
814 | ||
a755a45d JG |
815 | int zpci_enable_device(struct zpci_dev *zdev) |
816 | { | |
817 | int rc; | |
818 | ||
819 | rc = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES); | |
820 | if (rc) | |
821 | goto out; | |
828b35f6 JG |
822 | |
823 | rc = zpci_dma_init_device(zdev); | |
824 | if (rc) | |
825 | goto out_dma; | |
0ff70ec8 SO |
826 | |
827 | zdev->state = ZPCI_FN_STATE_ONLINE; | |
a755a45d | 828 | return 0; |
828b35f6 JG |
829 | |
830 | out_dma: | |
831 | clp_disable_fh(zdev); | |
a755a45d JG |
832 | out: |
833 | return rc; | |
834 | } | |
835 | EXPORT_SYMBOL_GPL(zpci_enable_device); | |
836 | ||
cb65a669 SO |
837 | int zpci_disable_device(struct zpci_dev *zdev) |
838 | { | |
839 | zpci_dma_exit_device(zdev); | |
840 | return clp_disable_fh(zdev); | |
841 | } | |
842 | EXPORT_SYMBOL_GPL(zpci_disable_device); | |
843 | ||
cd248341 JG |
844 | int zpci_create_device(struct zpci_dev *zdev) |
845 | { | |
846 | int rc; | |
847 | ||
848 | rc = zpci_alloc_domain(zdev); | |
849 | if (rc) | |
850 | goto out; | |
851 | ||
f42c2235 JR |
852 | rc = zpci_init_iommu(zdev); |
853 | if (rc) | |
854 | goto out_free; | |
855 | ||
80ed156a | 856 | mutex_init(&zdev->lock); |
1c21351b SO |
857 | if (zdev->state == ZPCI_FN_STATE_CONFIGURED) { |
858 | rc = zpci_enable_device(zdev); | |
859 | if (rc) | |
f42c2235 | 860 | goto out_destroy_iommu; |
1c21351b SO |
861 | } |
862 | rc = zpci_scan_bus(zdev); | |
cd248341 | 863 | if (rc) |
1c21351b | 864 | goto out_disable; |
cd248341 | 865 | |
57b5918c | 866 | spin_lock(&zpci_list_lock); |
cd248341 | 867 | list_add_tail(&zdev->entry, &zpci_list); |
57b5918c | 868 | spin_unlock(&zpci_list_lock); |
cd248341 | 869 | |
67f43f38 SO |
870 | zpci_init_slot(zdev); |
871 | ||
cd248341 JG |
872 | return 0; |
873 | ||
1c21351b SO |
874 | out_disable: |
875 | if (zdev->state == ZPCI_FN_STATE_ONLINE) | |
876 | zpci_disable_device(zdev); | |
f42c2235 JR |
877 | out_destroy_iommu: |
878 | zpci_destroy_iommu(zdev); | |
1c21351b | 879 | out_free: |
cd248341 JG |
880 | zpci_free_domain(zdev); |
881 | out: | |
882 | return rc; | |
883 | } | |
884 | ||
623bd44d SO |
885 | void zpci_remove_device(struct zpci_dev *zdev) |
886 | { | |
887 | if (!zdev->bus) | |
888 | return; | |
889 | ||
890 | pci_stop_root_bus(zdev->bus); | |
891 | pci_remove_root_bus(zdev->bus); | |
892 | } | |
893 | ||
bd3a1725 MS |
894 | int zpci_report_error(struct pci_dev *pdev, |
895 | struct zpci_report_error_header *report) | |
896 | { | |
897 | struct zpci_dev *zdev = to_zpci(pdev); | |
898 | ||
899 | return sclp_pci_report(report, zdev->fh, zdev->fid); | |
900 | } | |
901 | EXPORT_SYMBOL(zpci_report_error); | |
902 | ||
cd248341 JG |
903 | static int zpci_mem_init(void) |
904 | { | |
80c544de SO |
905 | BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) || |
906 | __alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb)); | |
907 | ||
d0b08853 | 908 | zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb), |
80c544de | 909 | __alignof__(struct zpci_fmb), 0, NULL); |
d0b08853 | 910 | if (!zdev_fmb_cache) |
c506fff3 | 911 | goto error_fmb; |
d0b08853 | 912 | |
c506fff3 SO |
913 | zpci_iomap_start = kcalloc(ZPCI_IOMAP_ENTRIES, |
914 | sizeof(*zpci_iomap_start), GFP_KERNEL); | |
cd248341 | 915 | if (!zpci_iomap_start) |
9a4da8a5 | 916 | goto error_iomap; |
cd248341 | 917 | |
c506fff3 SO |
918 | zpci_iomap_bitmap = kcalloc(BITS_TO_LONGS(ZPCI_IOMAP_ENTRIES), |
919 | sizeof(*zpci_iomap_bitmap), GFP_KERNEL); | |
920 | if (!zpci_iomap_bitmap) | |
921 | goto error_iomap_bitmap; | |
922 | ||
923 | return 0; | |
924 | error_iomap_bitmap: | |
925 | kfree(zpci_iomap_start); | |
9a4da8a5 | 926 | error_iomap: |
d0b08853 | 927 | kmem_cache_destroy(zdev_fmb_cache); |
c506fff3 | 928 | error_fmb: |
cd248341 JG |
929 | return -ENOMEM; |
930 | } | |
931 | ||
932 | static void zpci_mem_exit(void) | |
933 | { | |
c506fff3 | 934 | kfree(zpci_iomap_bitmap); |
cd248341 | 935 | kfree(zpci_iomap_start); |
d0b08853 | 936 | kmem_cache_destroy(zdev_fmb_cache); |
cd248341 JG |
937 | } |
938 | ||
257608fb | 939 | static unsigned int s390_pci_probe = 1; |
aa3b7c29 | 940 | static unsigned int s390_pci_initialized; |
cd248341 JG |
941 | |
942 | char * __init pcibios_setup(char *str) | |
943 | { | |
257608fb SO |
944 | if (!strcmp(str, "off")) { |
945 | s390_pci_probe = 0; | |
cd248341 JG |
946 | return NULL; |
947 | } | |
948 | return str; | |
949 | } | |
950 | ||
aa3b7c29 SO |
951 | bool zpci_is_enabled(void) |
952 | { | |
953 | return s390_pci_initialized; | |
954 | } | |
955 | ||
cd248341 JG |
956 | static int __init pci_base_init(void) |
957 | { | |
958 | int rc; | |
959 | ||
1e5635d1 | 960 | if (!s390_pci_probe) |
cd248341 JG |
961 | return 0; |
962 | ||
48070c73 | 963 | if (!test_facility(69) || !test_facility(71)) |
cd248341 JG |
964 | return 0; |
965 | ||
d0b08853 JG |
966 | rc = zpci_debug_init(); |
967 | if (rc) | |
1f44a225 | 968 | goto out; |
d0b08853 | 969 | |
cd248341 JG |
970 | rc = zpci_mem_init(); |
971 | if (rc) | |
972 | goto out_mem; | |
973 | ||
9a4da8a5 JG |
974 | rc = zpci_irq_init(); |
975 | if (rc) | |
976 | goto out_irq; | |
977 | ||
828b35f6 JG |
978 | rc = zpci_dma_init(); |
979 | if (rc) | |
980 | goto out_dma; | |
981 | ||
1d578966 | 982 | rc = clp_scan_pci_devices(); |
a755a45d JG |
983 | if (rc) |
984 | goto out_find; | |
985 | ||
aa3b7c29 | 986 | s390_pci_initialized = 1; |
cd248341 JG |
987 | return 0; |
988 | ||
a755a45d | 989 | out_find: |
828b35f6 JG |
990 | zpci_dma_exit(); |
991 | out_dma: | |
9a4da8a5 JG |
992 | zpci_irq_exit(); |
993 | out_irq: | |
cd248341 JG |
994 | zpci_mem_exit(); |
995 | out_mem: | |
d0b08853 | 996 | zpci_debug_exit(); |
1f44a225 | 997 | out: |
cd248341 JG |
998 | return rc; |
999 | } | |
67f43f38 | 1000 | subsys_initcall_sync(pci_base_init); |
57b5918c SO |
1001 | |
1002 | void zpci_rescan(void) | |
1003 | { | |
aa3b7c29 SO |
1004 | if (zpci_is_enabled()) |
1005 | clp_rescan_pci_devices_simple(); | |
57b5918c | 1006 | } |