diff options
Diffstat (limited to 'arch/s390/include/asm')
-rw-r--r-- | arch/s390/include/asm/io.h | 55 | ||||
-rw-r--r-- | arch/s390/include/asm/pci.h | 82 | ||||
-rw-r--r-- | arch/s390/include/asm/pci_insn.h | 280 | ||||
-rw-r--r-- | arch/s390/include/asm/pci_io.h | 194 |
4 files changed, 603 insertions, 8 deletions
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h index 559e921a6bba..16c3eb164f4f 100644 --- a/arch/s390/include/asm/io.h +++ b/arch/s390/include/asm/io.h | |||
@@ -9,9 +9,9 @@ | |||
9 | #ifndef _S390_IO_H | 9 | #ifndef _S390_IO_H |
10 | #define _S390_IO_H | 10 | #define _S390_IO_H |
11 | 11 | ||
12 | #include <linux/kernel.h> | ||
12 | #include <asm/page.h> | 13 | #include <asm/page.h> |
13 | 14 | #include <asm/pci_io.h> | |
14 | #define IO_SPACE_LIMIT 0xffffffff | ||
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Change virtual addresses to physical addresses and vv. | 17 | * Change virtual addresses to physical addresses and vv. |
@@ -24,10 +24,11 @@ static inline unsigned long virt_to_phys(volatile void * address) | |||
24 | " lra %0,0(%1)\n" | 24 | " lra %0,0(%1)\n" |
25 | " jz 0f\n" | 25 | " jz 0f\n" |
26 | " la %0,0\n" | 26 | " la %0,0\n" |
27 | "0:" | 27 | "0:" |
28 | : "=a" (real_address) : "a" (address) : "cc"); | 28 | : "=a" (real_address) : "a" (address) : "cc"); |
29 | return real_address; | 29 | return real_address; |
30 | } | 30 | } |
31 | #define virt_to_phys virt_to_phys | ||
31 | 32 | ||
32 | static inline void * phys_to_virt(unsigned long address) | 33 | static inline void * phys_to_virt(unsigned long address) |
33 | { | 34 | { |
@@ -42,4 +43,50 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr); | |||
42 | */ | 43 | */ |
43 | #define xlate_dev_kmem_ptr(p) p | 44 | #define xlate_dev_kmem_ptr(p) p |
44 | 45 | ||
46 | #define IO_SPACE_LIMIT 0 | ||
47 | |||
48 | #ifdef CONFIG_PCI | ||
49 | |||
50 | #define ioremap_nocache(addr, size) ioremap(addr, size) | ||
51 | #define ioremap_wc ioremap_nocache | ||
52 | |||
53 | /* TODO: s390 cannot support io_remap_pfn_range... */ | ||
54 | #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ | ||
55 | remap_pfn_range(vma, vaddr, pfn, size, prot) | ||
56 | |||
57 | static inline void __iomem *ioremap(unsigned long offset, unsigned long size) | ||
58 | { | ||
59 | return (void __iomem *) offset; | ||
60 | } | ||
61 | |||
62 | static inline void iounmap(volatile void __iomem *addr) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * s390 needs a private implementation of pci_iomap since ioremap with its | ||
68 | * offset parameter isn't sufficient. That's because BAR spaces are not | ||
69 | * disjunctive on s390 so we need the bar parameter of pci_iomap to find | ||
70 | * the corresponding device and create the mapping cookie. | ||
71 | */ | ||
72 | #define pci_iomap pci_iomap | ||
73 | #define pci_iounmap pci_iounmap | ||
74 | |||
75 | #define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count) | ||
76 | #define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count) | ||
77 | #define memset_io(dst, val, count) zpci_memset_io(dst, val, count) | ||
78 | |||
79 | #define __raw_readb zpci_read_u8 | ||
80 | #define __raw_readw zpci_read_u16 | ||
81 | #define __raw_readl zpci_read_u32 | ||
82 | #define __raw_readq zpci_read_u64 | ||
83 | #define __raw_writeb zpci_write_u8 | ||
84 | #define __raw_writew zpci_write_u16 | ||
85 | #define __raw_writel zpci_write_u32 | ||
86 | #define __raw_writeq zpci_write_u64 | ||
87 | |||
88 | #endif /* CONFIG_PCI */ | ||
89 | |||
90 | #include <asm-generic/io.h> | ||
91 | |||
45 | #endif | 92 | #endif |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 42a145c9ddd6..ff7b3596f47c 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
@@ -1,10 +1,84 @@ | |||
1 | #ifndef __ASM_S390_PCI_H | 1 | #ifndef __ASM_S390_PCI_H |
2 | #define __ASM_S390_PCI_H | 2 | #define __ASM_S390_PCI_H |
3 | 3 | ||
4 | /* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code | 4 | /* must be set before including asm-generic/pci.h */ |
5 | * includes it even if CONFIG_PCI is not set. | ||
6 | */ | ||
7 | #define PCI_DMA_BUS_IS_PHYS (0) | 5 | #define PCI_DMA_BUS_IS_PHYS (0) |
6 | /* must be set before including pci_clp.h */ | ||
7 | #define PCI_BAR_COUNT 6 | ||
8 | 8 | ||
9 | #endif /* __ASM_S390_PCI_H */ | 9 | #include <asm-generic/pci.h> |
10 | #include <asm-generic/pci-dma-compat.h> | ||
10 | 11 | ||
12 | #define PCIBIOS_MIN_IO 0x1000 | ||
13 | #define PCIBIOS_MIN_MEM 0x10000000 | ||
14 | |||
15 | #define pcibios_assign_all_busses() (0) | ||
16 | |||
17 | void __iomem *pci_iomap(struct pci_dev *, int, unsigned long); | ||
18 | void pci_iounmap(struct pci_dev *, void __iomem *); | ||
19 | int pci_domain_nr(struct pci_bus *); | ||
20 | int pci_proc_domain(struct pci_bus *); | ||
21 | |||
22 | #define ZPCI_BUS_NR 0 /* default bus number */ | ||
23 | #define ZPCI_DEVFN 0 /* default device number */ | ||
24 | |||
25 | /* PCI Function Controls */ | ||
26 | #define ZPCI_FC_FN_ENABLED 0x80 | ||
27 | #define ZPCI_FC_ERROR 0x40 | ||
28 | #define ZPCI_FC_BLOCKED 0x20 | ||
29 | #define ZPCI_FC_DMA_ENABLED 0x10 | ||
30 | |||
31 | enum zpci_state { | ||
32 | ZPCI_FN_STATE_RESERVED, | ||
33 | ZPCI_FN_STATE_STANDBY, | ||
34 | ZPCI_FN_STATE_CONFIGURED, | ||
35 | ZPCI_FN_STATE_ONLINE, | ||
36 | NR_ZPCI_FN_STATES, | ||
37 | }; | ||
38 | |||
39 | struct zpci_bar_struct { | ||
40 | u32 val; /* bar start & 3 flag bits */ | ||
41 | u8 size; /* order 2 exponent */ | ||
42 | u16 map_idx; /* index into bar mapping array */ | ||
43 | }; | ||
44 | |||
45 | /* Private data per function */ | ||
46 | struct zpci_dev { | ||
47 | struct pci_dev *pdev; | ||
48 | struct pci_bus *bus; | ||
49 | struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */ | ||
50 | |||
51 | enum zpci_state state; | ||
52 | u32 fid; /* function ID, used by sclp */ | ||
53 | u32 fh; /* function handle, used by insn's */ | ||
54 | u16 pchid; /* physical channel ID */ | ||
55 | u8 pfgid; /* function group ID */ | ||
56 | u16 domain; | ||
57 | |||
58 | struct zpci_bar_struct bars[PCI_BAR_COUNT]; | ||
59 | |||
60 | enum pci_bus_speed max_bus_speed; | ||
61 | }; | ||
62 | |||
63 | static inline bool zdev_enabled(struct zpci_dev *zdev) | ||
64 | { | ||
65 | return (zdev->fh & (1UL << 31)) ? true : false; | ||
66 | } | ||
67 | |||
68 | /* ----------------------------------------------------------------------------- | ||
69 | Prototypes | ||
70 | ----------------------------------------------------------------------------- */ | ||
71 | /* Base stuff */ | ||
72 | struct zpci_dev *zpci_alloc_device(void); | ||
73 | int zpci_create_device(struct zpci_dev *); | ||
74 | int zpci_enable_device(struct zpci_dev *); | ||
75 | void zpci_stop_device(struct zpci_dev *); | ||
76 | void zpci_free_device(struct zpci_dev *); | ||
77 | int zpci_scan_device(struct zpci_dev *); | ||
78 | |||
79 | /* Helpers */ | ||
80 | struct zpci_dev *get_zdev(struct pci_dev *); | ||
81 | struct zpci_dev *get_zdev_by_fid(u32); | ||
82 | bool zpci_fid_present(u32); | ||
83 | |||
84 | #endif | ||
diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h new file mode 100644 index 000000000000..15b88b908e8c --- /dev/null +++ b/arch/s390/include/asm/pci_insn.h | |||
@@ -0,0 +1,280 @@ | |||
1 | #ifndef _ASM_S390_PCI_INSN_H | ||
2 | #define _ASM_S390_PCI_INSN_H | ||
3 | |||
4 | #include <linux/delay.h> | ||
5 | |||
6 | #define ZPCI_INSN_BUSY_DELAY 1 /* 1 millisecond */ | ||
7 | |||
8 | /* Load/Store status codes */ | ||
9 | #define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4 | ||
10 | #define ZPCI_PCI_ST_FUNC_IN_ERR 8 | ||
11 | #define ZPCI_PCI_ST_BLOCKED 12 | ||
12 | #define ZPCI_PCI_ST_INSUF_RES 16 | ||
13 | #define ZPCI_PCI_ST_INVAL_AS 20 | ||
14 | #define ZPCI_PCI_ST_FUNC_ALREADY_ENABLED 24 | ||
15 | #define ZPCI_PCI_ST_DMA_AS_NOT_ENABLED 28 | ||
16 | #define ZPCI_PCI_ST_2ND_OP_IN_INV_AS 36 | ||
17 | #define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40 | ||
18 | #define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44 | ||
19 | |||
20 | /* Load/Store return codes */ | ||
21 | #define ZPCI_PCI_LS_OK 0 | ||
22 | #define ZPCI_PCI_LS_ERR 1 | ||
23 | #define ZPCI_PCI_LS_BUSY 2 | ||
24 | #define ZPCI_PCI_LS_INVAL_HANDLE 3 | ||
25 | |||
26 | /* Load/Store address space identifiers */ | ||
27 | #define ZPCI_PCIAS_MEMIO_0 0 | ||
28 | #define ZPCI_PCIAS_MEMIO_1 1 | ||
29 | #define ZPCI_PCIAS_MEMIO_2 2 | ||
30 | #define ZPCI_PCIAS_MEMIO_3 3 | ||
31 | #define ZPCI_PCIAS_MEMIO_4 4 | ||
32 | #define ZPCI_PCIAS_MEMIO_5 5 | ||
33 | #define ZPCI_PCIAS_CFGSPC 15 | ||
34 | |||
35 | /* Modify PCI Function Controls */ | ||
36 | #define ZPCI_MOD_FC_REG_INT 2 | ||
37 | #define ZPCI_MOD_FC_DEREG_INT 3 | ||
38 | #define ZPCI_MOD_FC_REG_IOAT 4 | ||
39 | #define ZPCI_MOD_FC_DEREG_IOAT 5 | ||
40 | #define ZPCI_MOD_FC_REREG_IOAT 6 | ||
41 | #define ZPCI_MOD_FC_RESET_ERROR 7 | ||
42 | #define ZPCI_MOD_FC_RESET_BLOCK 9 | ||
43 | #define ZPCI_MOD_FC_SET_MEASURE 10 | ||
44 | |||
45 | /* FIB function controls */ | ||
46 | #define ZPCI_FIB_FC_ENABLED 0x80 | ||
47 | #define ZPCI_FIB_FC_ERROR 0x40 | ||
48 | #define ZPCI_FIB_FC_LS_BLOCKED 0x20 | ||
49 | #define ZPCI_FIB_FC_DMAAS_REG 0x10 | ||
50 | |||
51 | /* FIB function controls */ | ||
52 | #define ZPCI_FIB_FC_ENABLED 0x80 | ||
53 | #define ZPCI_FIB_FC_ERROR 0x40 | ||
54 | #define ZPCI_FIB_FC_LS_BLOCKED 0x20 | ||
55 | #define ZPCI_FIB_FC_DMAAS_REG 0x10 | ||
56 | |||
57 | /* Function Information Block */ | ||
58 | struct zpci_fib { | ||
59 | u32 fmt : 8; /* format */ | ||
60 | u32 : 24; | ||
61 | u32 reserved1; | ||
62 | u8 fc; /* function controls */ | ||
63 | u8 reserved2; | ||
64 | u16 reserved3; | ||
65 | u32 reserved4; | ||
66 | u64 pba; /* PCI base address */ | ||
67 | u64 pal; /* PCI address limit */ | ||
68 | u64 iota; /* I/O Translation Anchor */ | ||
69 | u32 : 1; | ||
70 | u32 isc : 3; /* Interrupt subclass */ | ||
71 | u32 noi : 12; /* Number of interrupts */ | ||
72 | u32 : 2; | ||
73 | u32 aibvo : 6; /* Adapter interrupt bit vector offset */ | ||
74 | u32 sum : 1; /* Adapter int summary bit enabled */ | ||
75 | u32 : 1; | ||
76 | u32 aisbo : 6; /* Adapter int summary bit offset */ | ||
77 | u32 reserved5; | ||
78 | u64 aibv; /* Adapter int bit vector address */ | ||
79 | u64 aisb; /* Adapter int summary bit address */ | ||
80 | u64 fmb_addr; /* Function measurement block address and key */ | ||
81 | u64 reserved6; | ||
82 | u64 reserved7; | ||
83 | } __packed; | ||
84 | |||
85 | /* Modify PCI Function Controls */ | ||
86 | static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status) | ||
87 | { | ||
88 | u8 cc; | ||
89 | |||
90 | asm volatile ( | ||
91 | " .insn rxy,0xe300000000d0,%[req],%[fib]\n" | ||
92 | " ipm %[cc]\n" | ||
93 | " srl %[cc],28\n" | ||
94 | : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib) | ||
95 | : : "cc"); | ||
96 | *status = req >> 24 & 0xff; | ||
97 | return cc; | ||
98 | } | ||
99 | |||
100 | static inline int mpcifc_instr(u64 req, struct zpci_fib *fib) | ||
101 | { | ||
102 | u8 cc, status; | ||
103 | |||
104 | do { | ||
105 | cc = __mpcifc(req, fib, &status); | ||
106 | if (cc == 2) | ||
107 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
108 | } while (cc == 2); | ||
109 | |||
110 | if (cc) | ||
111 | printk_once(KERN_ERR "%s: error cc: %d status: %d\n", | ||
112 | __func__, cc, status); | ||
113 | return (cc) ? -EIO : 0; | ||
114 | } | ||
115 | |||
116 | /* Refresh PCI Translations */ | ||
117 | static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) | ||
118 | { | ||
119 | register u64 __addr asm("2") = addr; | ||
120 | register u64 __range asm("3") = range; | ||
121 | u8 cc; | ||
122 | |||
123 | asm volatile ( | ||
124 | " .insn rre,0xb9d30000,%[fn],%[addr]\n" | ||
125 | " ipm %[cc]\n" | ||
126 | " srl %[cc],28\n" | ||
127 | : [cc] "=d" (cc), [fn] "+d" (fn) | ||
128 | : [addr] "d" (__addr), "d" (__range) | ||
129 | : "cc"); | ||
130 | *status = fn >> 24 & 0xff; | ||
131 | return cc; | ||
132 | } | ||
133 | |||
134 | static inline int rpcit_instr(u64 fn, u64 addr, u64 range) | ||
135 | { | ||
136 | u8 cc, status; | ||
137 | |||
138 | do { | ||
139 | cc = __rpcit(fn, addr, range, &status); | ||
140 | if (cc == 2) | ||
141 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
142 | } while (cc == 2); | ||
143 | |||
144 | if (cc) | ||
145 | printk_once(KERN_ERR "%s: error cc: %d status: %d dma_addr: %Lx size: %Lx\n", | ||
146 | __func__, cc, status, addr, range); | ||
147 | return (cc) ? -EIO : 0; | ||
148 | } | ||
149 | |||
150 | /* Store PCI function controls */ | ||
151 | static inline u8 __stpcifc(u32 handle, u8 space, struct zpci_fib *fib, u8 *status) | ||
152 | { | ||
153 | u64 fn = (u64) handle << 32 | space << 16; | ||
154 | u8 cc; | ||
155 | |||
156 | asm volatile ( | ||
157 | " .insn rxy,0xe300000000d4,%[fn],%[fib]\n" | ||
158 | " ipm %[cc]\n" | ||
159 | " srl %[cc],28\n" | ||
160 | : [cc] "=d" (cc), [fn] "+d" (fn), [fib] "=m" (*fib) | ||
161 | : : "cc"); | ||
162 | *status = fn >> 24 & 0xff; | ||
163 | return cc; | ||
164 | } | ||
165 | |||
166 | /* Set Interruption Controls */ | ||
167 | static inline void sic_instr(u16 ctl, char *unused, u8 isc) | ||
168 | { | ||
169 | asm volatile ( | ||
170 | " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n" | ||
171 | : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused)); | ||
172 | } | ||
173 | |||
174 | /* PCI Load */ | ||
175 | static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status) | ||
176 | { | ||
177 | register u64 __req asm("2") = req; | ||
178 | register u64 __offset asm("3") = offset; | ||
179 | u64 __data; | ||
180 | u8 cc; | ||
181 | |||
182 | asm volatile ( | ||
183 | " .insn rre,0xb9d20000,%[data],%[req]\n" | ||
184 | " ipm %[cc]\n" | ||
185 | " srl %[cc],28\n" | ||
186 | : [cc] "=d" (cc), [data] "=d" (__data), [req] "+d" (__req) | ||
187 | : "d" (__offset) | ||
188 | : "cc"); | ||
189 | *status = __req >> 24 & 0xff; | ||
190 | *data = __data; | ||
191 | return cc; | ||
192 | } | ||
193 | |||
194 | static inline int pcilg_instr(u64 *data, u64 req, u64 offset) | ||
195 | { | ||
196 | u8 cc, status; | ||
197 | |||
198 | do { | ||
199 | cc = __pcilg(data, req, offset, &status); | ||
200 | if (cc == 2) | ||
201 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
202 | } while (cc == 2); | ||
203 | |||
204 | if (cc) { | ||
205 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | ||
206 | __func__, cc, status, req, offset); | ||
207 | /* TODO: on IO errors set data to 0xff... | ||
208 | * here or in users of pcilg (le conversion)? | ||
209 | */ | ||
210 | } | ||
211 | return (cc) ? -EIO : 0; | ||
212 | } | ||
213 | |||
214 | /* PCI Store */ | ||
215 | static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status) | ||
216 | { | ||
217 | register u64 __req asm("2") = req; | ||
218 | register u64 __offset asm("3") = offset; | ||
219 | u8 cc; | ||
220 | |||
221 | asm volatile ( | ||
222 | " .insn rre,0xb9d00000,%[data],%[req]\n" | ||
223 | " ipm %[cc]\n" | ||
224 | " srl %[cc],28\n" | ||
225 | : [cc] "=d" (cc), [req] "+d" (__req) | ||
226 | : "d" (__offset), [data] "d" (data) | ||
227 | : "cc"); | ||
228 | *status = __req >> 24 & 0xff; | ||
229 | return cc; | ||
230 | } | ||
231 | |||
232 | static inline int pcistg_instr(u64 data, u64 req, u64 offset) | ||
233 | { | ||
234 | u8 cc, status; | ||
235 | |||
236 | do { | ||
237 | cc = __pcistg(data, req, offset, &status); | ||
238 | if (cc == 2) | ||
239 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
240 | } while (cc == 2); | ||
241 | |||
242 | if (cc) | ||
243 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | ||
244 | __func__, cc, status, req, offset); | ||
245 | return (cc) ? -EIO : 0; | ||
246 | } | ||
247 | |||
248 | /* PCI Store Block */ | ||
249 | static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) | ||
250 | { | ||
251 | u8 cc; | ||
252 | |||
253 | asm volatile ( | ||
254 | " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" | ||
255 | " ipm %[cc]\n" | ||
256 | " srl %[cc],28\n" | ||
257 | : [cc] "=d" (cc), [req] "+d" (req) | ||
258 | : [offset] "d" (offset), [data] "Q" (*data) | ||
259 | : "cc"); | ||
260 | *status = req >> 24 & 0xff; | ||
261 | return cc; | ||
262 | } | ||
263 | |||
264 | static inline int pcistb_instr(const u64 *data, u64 req, u64 offset) | ||
265 | { | ||
266 | u8 cc, status; | ||
267 | |||
268 | do { | ||
269 | cc = __pcistb(data, req, offset, &status); | ||
270 | if (cc == 2) | ||
271 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
272 | } while (cc == 2); | ||
273 | |||
274 | if (cc) | ||
275 | printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n", | ||
276 | __func__, cc, status, req, offset); | ||
277 | return (cc) ? -EIO : 0; | ||
278 | } | ||
279 | |||
280 | #endif | ||
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h new file mode 100644 index 000000000000..5fd81f31d6c7 --- /dev/null +++ b/arch/s390/include/asm/pci_io.h | |||
@@ -0,0 +1,194 @@ | |||
1 | #ifndef _ASM_S390_PCI_IO_H | ||
2 | #define _ASM_S390_PCI_IO_H | ||
3 | |||
4 | #ifdef CONFIG_PCI | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <asm/pci_insn.h> | ||
9 | |||
10 | /* I/O Map */ | ||
11 | #define ZPCI_IOMAP_MAX_ENTRIES 0x7fff | ||
12 | #define ZPCI_IOMAP_ADDR_BASE 0x8000000000000000ULL | ||
13 | #define ZPCI_IOMAP_ADDR_IDX_MASK 0x7fff000000000000ULL | ||
14 | #define ZPCI_IOMAP_ADDR_OFF_MASK 0x0000ffffffffffffULL | ||
15 | |||
16 | struct zpci_iomap_entry { | ||
17 | u32 fh; | ||
18 | u8 bar; | ||
19 | }; | ||
20 | |||
21 | extern struct zpci_iomap_entry *zpci_iomap_start; | ||
22 | |||
23 | #define ZPCI_IDX(addr) \ | ||
24 | (((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> 48) | ||
25 | #define ZPCI_OFFSET(addr) \ | ||
26 | ((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK) | ||
27 | |||
28 | #define ZPCI_CREATE_REQ(handle, space, len) \ | ||
29 | ((u64) handle << 32 | space << 16 | len) | ||
30 | |||
31 | #define zpci_read(LENGTH, RETTYPE) \ | ||
32 | static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \ | ||
33 | { \ | ||
34 | struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \ | ||
35 | u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \ | ||
36 | u64 data; \ | ||
37 | int rc; \ | ||
38 | \ | ||
39 | rc = pcilg_instr(&data, req, ZPCI_OFFSET(addr)); \ | ||
40 | if (rc) \ | ||
41 | data = -1ULL; \ | ||
42 | return (RETTYPE) data; \ | ||
43 | } | ||
44 | |||
45 | #define zpci_write(LENGTH, VALTYPE) \ | ||
46 | static inline void zpci_write_##VALTYPE(VALTYPE val, \ | ||
47 | const volatile void __iomem *addr) \ | ||
48 | { \ | ||
49 | struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \ | ||
50 | u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \ | ||
51 | u64 data = (VALTYPE) val; \ | ||
52 | \ | ||
53 | pcistg_instr(data, req, ZPCI_OFFSET(addr)); \ | ||
54 | } | ||
55 | |||
56 | zpci_read(8, u64) | ||
57 | zpci_read(4, u32) | ||
58 | zpci_read(2, u16) | ||
59 | zpci_read(1, u8) | ||
60 | zpci_write(8, u64) | ||
61 | zpci_write(4, u32) | ||
62 | zpci_write(2, u16) | ||
63 | zpci_write(1, u8) | ||
64 | |||
65 | static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len) | ||
66 | { | ||
67 | u64 val; | ||
68 | |||
69 | switch (len) { | ||
70 | case 1: | ||
71 | val = (u64) *((u8 *) data); | ||
72 | break; | ||
73 | case 2: | ||
74 | val = (u64) *((u16 *) data); | ||
75 | break; | ||
76 | case 4: | ||
77 | val = (u64) *((u32 *) data); | ||
78 | break; | ||
79 | case 8: | ||
80 | val = (u64) *((u64 *) data); | ||
81 | break; | ||
82 | default: | ||
83 | val = 0; /* let FW report error */ | ||
84 | break; | ||
85 | } | ||
86 | return pcistg_instr(val, req, offset); | ||
87 | } | ||
88 | |||
89 | static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len) | ||
90 | { | ||
91 | u64 data; | ||
92 | u8 cc; | ||
93 | |||
94 | cc = pcilg_instr(&data, req, offset); | ||
95 | switch (len) { | ||
96 | case 1: | ||
97 | *((u8 *) dst) = (u8) data; | ||
98 | break; | ||
99 | case 2: | ||
100 | *((u16 *) dst) = (u16) data; | ||
101 | break; | ||
102 | case 4: | ||
103 | *((u32 *) dst) = (u32) data; | ||
104 | break; | ||
105 | case 8: | ||
106 | *((u64 *) dst) = (u64) data; | ||
107 | break; | ||
108 | } | ||
109 | return cc; | ||
110 | } | ||
111 | |||
112 | static inline int zpci_write_block(u64 req, const u64 *data, u64 offset) | ||
113 | { | ||
114 | return pcistb_instr(data, req, offset); | ||
115 | } | ||
116 | |||
117 | static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max) | ||
118 | { | ||
119 | int count = len > max ? max : len, size = 1; | ||
120 | |||
121 | while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) { | ||
122 | dst = dst >> 1; | ||
123 | src = src >> 1; | ||
124 | size = size << 1; | ||
125 | } | ||
126 | return size; | ||
127 | } | ||
128 | |||
129 | static inline int zpci_memcpy_fromio(void *dst, | ||
130 | const volatile void __iomem *src, | ||
131 | unsigned long n) | ||
132 | { | ||
133 | struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(src)]; | ||
134 | u64 req, offset = ZPCI_OFFSET(src); | ||
135 | int size, rc = 0; | ||
136 | |||
137 | while (n > 0) { | ||
138 | size = zpci_get_max_write_size((u64) src, (u64) dst, n, 8); | ||
139 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | ||
140 | rc = zpci_read_single(req, dst, offset, size); | ||
141 | if (rc) | ||
142 | break; | ||
143 | offset += size; | ||
144 | dst += size; | ||
145 | n -= size; | ||
146 | } | ||
147 | return rc; | ||
148 | } | ||
149 | |||
150 | static inline int zpci_memcpy_toio(volatile void __iomem *dst, | ||
151 | const void *src, unsigned long n) | ||
152 | { | ||
153 | struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)]; | ||
154 | u64 req, offset = ZPCI_OFFSET(dst); | ||
155 | int size, rc = 0; | ||
156 | |||
157 | if (!src) | ||
158 | return -EINVAL; | ||
159 | |||
160 | while (n > 0) { | ||
161 | size = zpci_get_max_write_size((u64) dst, (u64) src, n, 128); | ||
162 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | ||
163 | |||
164 | if (size > 8) /* main path */ | ||
165 | rc = zpci_write_block(req, src, offset); | ||
166 | else | ||
167 | rc = zpci_write_single(req, src, offset, size); | ||
168 | if (rc) | ||
169 | break; | ||
170 | offset += size; | ||
171 | src += size; | ||
172 | n -= size; | ||
173 | } | ||
174 | return rc; | ||
175 | } | ||
176 | |||
177 | static inline int zpci_memset_io(volatile void __iomem *dst, | ||
178 | unsigned char val, size_t count) | ||
179 | { | ||
180 | u8 *src = kmalloc(count, GFP_KERNEL); | ||
181 | int rc; | ||
182 | |||
183 | if (src == NULL) | ||
184 | return -ENOMEM; | ||
185 | memset(src, val, count); | ||
186 | |||
187 | rc = zpci_memcpy_toio(dst, src, count); | ||
188 | kfree(src); | ||
189 | return rc; | ||
190 | } | ||
191 | |||
192 | #endif /* CONFIG_PCI */ | ||
193 | |||
194 | #endif /* _ASM_S390_PCI_IO_H */ | ||