1 // SPDX-License-Identifier: GPL-2.0
3 * s390 specific pci instructions
5 * Copyright IBM Corp. 2013
8 #include <linux/export.h>
9 #include <linux/errno.h>
10 #include <linux/delay.h>
11 #include <linux/jump_label.h>
12 #include <asm/facility.h>
13 #include <asm/pci_insn.h>
14 #include <asm/pci_debug.h>
15 #include <asm/pci_io.h>
16 #include <asm/processor.h>
18 #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
20 static inline void zpci_err_insn(u8 cc
, u8 status
, u64 req
, u64 offset
)
27 } __packed data
= {req
, offset
, cc
, status
};
29 zpci_err_hex(&data
, sizeof(data
));
32 /* Modify PCI Function Controls */
33 static inline u8
__mpcifc(u64 req
, struct zpci_fib
*fib
, u8
*status
)
38 " .insn rxy,0xe300000000d0,%[req],%[fib]\n"
41 : [cc
] "=d" (cc
), [req
] "+d" (req
), [fib
] "+Q" (*fib
)
43 *status
= req
>> 24 & 0xff;
47 u8
zpci_mod_fc(u64 req
, struct zpci_fib
*fib
, u8
*status
)
52 cc
= __mpcifc(req
, fib
, status
);
54 msleep(ZPCI_INSN_BUSY_DELAY
);
58 zpci_err_insn(cc
, *status
, req
, 0);
63 /* Refresh PCI Translations */
64 static inline u8
__rpcit(u64 fn
, u64 addr
, u64 range
, u8
*status
)
66 register u64 __addr
asm("2") = addr
;
67 register u64 __range
asm("3") = range
;
71 " .insn rre,0xb9d30000,%[fn],%[addr]\n"
74 : [cc
] "=d" (cc
), [fn
] "+d" (fn
)
75 : [addr
] "d" (__addr
), "d" (__range
)
77 *status
= fn
>> 24 & 0xff;
81 int zpci_refresh_trans(u64 fn
, u64 addr
, u64 range
)
86 cc
= __rpcit(fn
, addr
, range
, &status
);
88 udelay(ZPCI_INSN_BUSY_DELAY
);
92 zpci_err_insn(cc
, status
, addr
, range
);
94 if (cc
== 1 && (status
== 4 || status
== 16))
97 return (cc
) ? -EIO
: 0;
100 /* Set Interruption Controls */
101 int __zpci_set_irq_ctrl(u16 ctl
, u8 isc
, union zpci_sic_iib
*iib
)
103 if (!test_facility(72))
107 ".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
108 : : [ctl
] "d" (ctl
), [isc
] "d" (isc
<< 27), [iib
] "Q" (*iib
));
114 static inline int ____pcilg(u64
*data
, u64 req
, u64 offset
, u8
*status
)
116 register u64 __req
asm("2") = req
;
117 register u64 __offset
asm("3") = offset
;
122 " .insn rre,0xb9d20000,%[data],%[req]\n"
127 : [cc
] "+d" (cc
), [data
] "=d" (__data
), [req
] "+d" (__req
)
130 *status
= __req
>> 24 & 0xff;
135 static inline int __pcilg(u64
*data
, u64 req
, u64 offset
, u8
*status
)
140 cc
= ____pcilg(&__data
, req
, offset
, status
);
147 int __zpci_load(u64
*data
, u64 req
, u64 offset
)
153 cc
= __pcilg(data
, req
, offset
, &status
);
155 udelay(ZPCI_INSN_BUSY_DELAY
);
159 zpci_err_insn(cc
, status
, req
, offset
);
161 return (cc
> 0) ? -EIO
: cc
;
163 EXPORT_SYMBOL_GPL(__zpci_load
);
165 static inline int zpci_load_fh(u64
*data
, const volatile void __iomem
*addr
,
168 struct zpci_iomap_entry
*entry
= &zpci_iomap_start
[ZPCI_IDX(addr
)];
169 u64 req
= ZPCI_CREATE_REQ(entry
->fh
, entry
->bar
, len
);
171 return __zpci_load(data
, req
, ZPCI_OFFSET(addr
));
174 static inline int __pcilg_mio(u64
*data
, u64 ioaddr
, u64 len
, u8
*status
)
176 register u64 addr
asm("2") = ioaddr
;
177 register u64 r3
asm("3") = len
;
182 " .insn rre,0xb9d60000,%[data],%[ioaddr]\n"
187 : [cc
] "+d" (cc
), [data
] "=d" (__data
), "+d" (r3
)
188 : [ioaddr
] "d" (addr
)
190 *status
= r3
>> 24 & 0xff;
195 int zpci_load(u64
*data
, const volatile void __iomem
*addr
, unsigned long len
)
200 if (!static_branch_unlikely(&have_mio
))
201 return zpci_load_fh(data
, addr
, len
);
203 cc
= __pcilg_mio(data
, (__force u64
) addr
, len
, &status
);
205 zpci_err_insn(cc
, status
, 0, (__force u64
) addr
);
207 return (cc
> 0) ? -EIO
: cc
;
209 EXPORT_SYMBOL_GPL(zpci_load
);
212 static inline int __pcistg(u64 data
, u64 req
, u64 offset
, u8
*status
)
214 register u64 __req
asm("2") = req
;
215 register u64 __offset
asm("3") = offset
;
219 " .insn rre,0xb9d00000,%[data],%[req]\n"
224 : [cc
] "+d" (cc
), [req
] "+d" (__req
)
225 : "d" (__offset
), [data
] "d" (data
)
227 *status
= __req
>> 24 & 0xff;
231 int __zpci_store(u64 data
, u64 req
, u64 offset
)
237 cc
= __pcistg(data
, req
, offset
, &status
);
239 udelay(ZPCI_INSN_BUSY_DELAY
);
243 zpci_err_insn(cc
, status
, req
, offset
);
245 return (cc
> 0) ? -EIO
: cc
;
247 EXPORT_SYMBOL_GPL(__zpci_store
);
249 static inline int zpci_store_fh(const volatile void __iomem
*addr
, u64 data
,
252 struct zpci_iomap_entry
*entry
= &zpci_iomap_start
[ZPCI_IDX(addr
)];
253 u64 req
= ZPCI_CREATE_REQ(entry
->fh
, entry
->bar
, len
);
255 return __zpci_store(data
, req
, ZPCI_OFFSET(addr
));
258 static inline int __pcistg_mio(u64 data
, u64 ioaddr
, u64 len
, u8
*status
)
260 register u64 addr
asm("2") = ioaddr
;
261 register u64 r3
asm("3") = len
;
265 " .insn rre,0xb9d40000,%[data],%[ioaddr]\n"
270 : [cc
] "+d" (cc
), "+d" (r3
)
271 : [data
] "d" (data
), [ioaddr
] "d" (addr
)
273 *status
= r3
>> 24 & 0xff;
277 int zpci_store(const volatile void __iomem
*addr
, u64 data
, unsigned long len
)
282 if (!static_branch_unlikely(&have_mio
))
283 return zpci_store_fh(addr
, data
, len
);
285 cc
= __pcistg_mio(data
, (__force u64
) addr
, len
, &status
);
287 zpci_err_insn(cc
, status
, 0, (__force u64
) addr
);
289 return (cc
> 0) ? -EIO
: cc
;
291 EXPORT_SYMBOL_GPL(zpci_store
);
293 /* PCI Store Block */
294 static inline int __pcistb(const u64
*data
, u64 req
, u64 offset
, u8
*status
)
299 " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
304 : [cc
] "+d" (cc
), [req
] "+d" (req
)
305 : [offset
] "d" (offset
), [data
] "Q" (*data
)
307 *status
= req
>> 24 & 0xff;
311 int __zpci_store_block(const u64
*data
, u64 req
, u64 offset
)
317 cc
= __pcistb(data
, req
, offset
, &status
);
319 udelay(ZPCI_INSN_BUSY_DELAY
);
323 zpci_err_insn(cc
, status
, req
, offset
);
325 return (cc
> 0) ? -EIO
: cc
;
327 EXPORT_SYMBOL_GPL(__zpci_store_block
);
329 static inline int zpci_write_block_fh(volatile void __iomem
*dst
,
330 const void *src
, unsigned long len
)
332 struct zpci_iomap_entry
*entry
= &zpci_iomap_start
[ZPCI_IDX(dst
)];
333 u64 req
= ZPCI_CREATE_REQ(entry
->fh
, entry
->bar
, len
);
334 u64 offset
= ZPCI_OFFSET(dst
);
336 return __zpci_store_block(src
, req
, offset
);
339 static inline int __pcistb_mio(const u64
*data
, u64 ioaddr
, u64 len
, u8
*status
)
344 " .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n"
349 : [cc
] "+d" (cc
), [len
] "+d" (len
)
350 : [ioaddr
] "d" (ioaddr
), [data
] "Q" (*data
)
352 *status
= len
>> 24 & 0xff;
356 int zpci_write_block(volatile void __iomem
*dst
,
357 const void *src
, unsigned long len
)
362 if (!static_branch_unlikely(&have_mio
))
363 return zpci_write_block_fh(dst
, src
, len
);
365 cc
= __pcistb_mio(src
, (__force u64
) dst
, len
, &status
);
367 zpci_err_insn(cc
, status
, 0, (__force u64
) dst
);
369 return (cc
> 0) ? -EIO
: cc
;
371 EXPORT_SYMBOL_GPL(zpci_write_block
);
373 static inline void __pciwb_mio(void)
375 unsigned long unused
= 0;
377 asm volatile (".insn rre,0xb9d50000,%[op],%[op]\n"
378 : [op
] "+d" (unused
));
381 void zpci_barrier(void)
383 if (static_branch_likely(&have_mio
))
386 EXPORT_SYMBOL_GPL(zpci_barrier
);