diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2012-11-29 06:50:30 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-11-30 09:40:45 -0500 |
commit | cd24834130ac655d15accee6757e0eaeab4ad4ef (patch) | |
tree | 33be1efb537d6a08557a488f096c22516da0b3c2 | |
parent | d07dc5d8ab6f15353c866e2768c389abdc1faba6 (diff) |
s390/pci: base support
Add PCI support for s390, (only 64 bit mode is supported by hardware):
- PCI facility tests
- PCI instructions: pcilg, pcistg, pcistb, stpcifc, mpcifc, rpcit
- map readb/w/l/q and writeb/w/l/q to pcilg and pcistg instructions
- pci_iomap implementation
- memcpy_fromio/toio
- pci_root_ops using special pcilg/pcistg
- device, bus and domain allocation
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/Kbuild | 1 | ||||
-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 | ||||
-rw-r--r-- | arch/s390/kernel/dis.c | 15 | ||||
-rw-r--r-- | arch/s390/pci/Makefile | 5 | ||||
-rw-r--r-- | arch/s390/pci/pci.c | 557 | ||||
-rw-r--r-- | include/asm-generic/io.h | 21 |
9 files changed, 1201 insertions, 9 deletions
diff --git a/arch/s390/Kbuild b/arch/s390/Kbuild index cc45d25487b0..647c3eccc3d0 100644 --- a/arch/s390/Kbuild +++ b/arch/s390/Kbuild | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += hypfs/ | |||
6 | obj-$(CONFIG_APPLDATA_BASE) += appldata/ | 6 | obj-$(CONFIG_APPLDATA_BASE) += appldata/ |
7 | obj-$(CONFIG_MATHEMU) += math-emu/ | 7 | obj-$(CONFIG_MATHEMU) += math-emu/ |
8 | obj-y += net/ | 8 | obj-y += net/ |
9 | obj-$(CONFIG_PCI) += pci/ | ||
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 */ | ||
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index afdb9729cf9b..a7f9abd98cf2 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
@@ -399,6 +399,10 @@ enum { | |||
399 | LONG_INSN_TABORT, | 399 | LONG_INSN_TABORT, |
400 | LONG_INSN_TBEGIN, | 400 | LONG_INSN_TBEGIN, |
401 | LONG_INSN_TBEGINC, | 401 | LONG_INSN_TBEGINC, |
402 | LONG_INSN_PCISTG, | ||
403 | LONG_INSN_MPCIFC, | ||
404 | LONG_INSN_STPCIFC, | ||
405 | LONG_INSN_PCISTB, | ||
402 | }; | 406 | }; |
403 | 407 | ||
404 | static char *long_insn_name[] = { | 408 | static char *long_insn_name[] = { |
@@ -469,6 +473,10 @@ static char *long_insn_name[] = { | |||
469 | [LONG_INSN_TABORT] = "tabort", | 473 | [LONG_INSN_TABORT] = "tabort", |
470 | [LONG_INSN_TBEGIN] = "tbegin", | 474 | [LONG_INSN_TBEGIN] = "tbegin", |
471 | [LONG_INSN_TBEGINC] = "tbeginc", | 475 | [LONG_INSN_TBEGINC] = "tbeginc", |
476 | [LONG_INSN_PCISTG] = "pcistg", | ||
477 | [LONG_INSN_MPCIFC] = "mpcifc", | ||
478 | [LONG_INSN_STPCIFC] = "stpcifc", | ||
479 | [LONG_INSN_PCISTB] = "pcistb", | ||
472 | }; | 480 | }; |
473 | 481 | ||
474 | static struct insn opcode[] = { | 482 | static struct insn opcode[] = { |
@@ -1115,6 +1123,9 @@ static struct insn opcode_b9[] = { | |||
1115 | { { 0, LONG_INSN_SLHHHR }, 0xcb, INSTR_RRF_R0RR2 }, | 1123 | { { 0, LONG_INSN_SLHHHR }, 0xcb, INSTR_RRF_R0RR2 }, |
1116 | { "chhr", 0xcd, INSTR_RRE_RR }, | 1124 | { "chhr", 0xcd, INSTR_RRE_RR }, |
1117 | { "clhhr", 0xcf, INSTR_RRE_RR }, | 1125 | { "clhhr", 0xcf, INSTR_RRE_RR }, |
1126 | { { 0, LONG_INSN_PCISTG }, 0xd0, INSTR_RRE_RR }, | ||
1127 | { "pcilg", 0xd2, INSTR_RRE_RR }, | ||
1128 | { "rpcit", 0xd3, INSTR_RRE_RR }, | ||
1118 | { "ahhlr", 0xd8, INSTR_RRF_R0RR2 }, | 1129 | { "ahhlr", 0xd8, INSTR_RRF_R0RR2 }, |
1119 | { "shhlr", 0xd9, INSTR_RRF_R0RR2 }, | 1130 | { "shhlr", 0xd9, INSTR_RRF_R0RR2 }, |
1120 | { { 0, LONG_INSN_ALHHLR }, 0xda, INSTR_RRF_R0RR2 }, | 1131 | { { 0, LONG_INSN_ALHHLR }, 0xda, INSTR_RRF_R0RR2 }, |
@@ -1346,6 +1357,8 @@ static struct insn opcode_e3[] = { | |||
1346 | { "stfh", 0xcb, INSTR_RXY_RRRD }, | 1357 | { "stfh", 0xcb, INSTR_RXY_RRRD }, |
1347 | { "chf", 0xcd, INSTR_RXY_RRRD }, | 1358 | { "chf", 0xcd, INSTR_RXY_RRRD }, |
1348 | { "clhf", 0xcf, INSTR_RXY_RRRD }, | 1359 | { "clhf", 0xcf, INSTR_RXY_RRRD }, |
1360 | { { 0, LONG_INSN_MPCIFC }, 0xd0, INSTR_RXY_RRRD }, | ||
1361 | { { 0, LONG_INSN_STPCIFC }, 0xd4, INSTR_RXY_RRRD }, | ||
1349 | #endif | 1362 | #endif |
1350 | { "lrv", 0x1e, INSTR_RXY_RRRD }, | 1363 | { "lrv", 0x1e, INSTR_RXY_RRRD }, |
1351 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, | 1364 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, |
@@ -1423,6 +1436,8 @@ static struct insn opcode_eb[] = { | |||
1423 | { "lmy", 0x98, INSTR_RSY_RRRD }, | 1436 | { "lmy", 0x98, INSTR_RSY_RRRD }, |
1424 | { "lamy", 0x9a, INSTR_RSY_AARD }, | 1437 | { "lamy", 0x9a, INSTR_RSY_AARD }, |
1425 | { "stamy", 0x9b, INSTR_RSY_AARD }, | 1438 | { "stamy", 0x9b, INSTR_RSY_AARD }, |
1439 | { { 0, LONG_INSN_PCISTB }, 0xd0, INSTR_RSY_RRRD }, | ||
1440 | { "sic", 0xd1, INSTR_RSY_RRRD }, | ||
1426 | { "srak", 0xdc, INSTR_RSY_RRRD }, | 1441 | { "srak", 0xdc, INSTR_RSY_RRRD }, |
1427 | { "slak", 0xdd, INSTR_RSY_RRRD }, | 1442 | { "slak", 0xdd, INSTR_RSY_RRRD }, |
1428 | { "srlk", 0xde, INSTR_RSY_RRRD }, | 1443 | { "srlk", 0xde, INSTR_RSY_RRRD }, |
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile new file mode 100644 index 000000000000..78a1344ff7b1 --- /dev/null +++ b/arch/s390/pci/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the s390 PCI subsystem. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI) += pci.o | ||
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c new file mode 100644 index 000000000000..0b80ac7e158f --- /dev/null +++ b/arch/s390/pci/pci.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * Copyright IBM Corp. 2012 | ||
3 | * | ||
4 | * Author(s): | ||
5 | * Jan Glauber <jang@linux.vnet.ibm.com> | ||
6 | * | ||
7 | * The System z PCI code is a rewrite from a prototype by | ||
8 | * the following people (Kudoz!): | ||
9 | * Alexander Schmidt <alexschm@de.ibm.com> | ||
10 | * Christoph Raisch <raisch@de.ibm.com> | ||
11 | * Hannes Hering <hering2@de.ibm.com> | ||
12 | * Hoang-Nam Nguyen <hnguyen@de.ibm.com> | ||
13 | * Jan-Bernd Themann <themann@de.ibm.com> | ||
14 | * Stefan Roscher <stefan.roscher@de.ibm.com> | ||
15 | * Thomas Klein <tklein@de.ibm.com> | ||
16 | */ | ||
17 | |||
18 | #define COMPONENT "zPCI" | ||
19 | #define pr_fmt(fmt) COMPONENT ": " fmt | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/export.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/msi.h> | ||
29 | |||
30 | #include <asm/facility.h> | ||
31 | #include <asm/pci_insn.h> | ||
32 | |||
33 | #define DEBUG /* enable pr_debug */ | ||
34 | |||
35 | #define ZPCI_NR_DMA_SPACES 1 | ||
36 | #define ZPCI_NR_DEVICES CONFIG_PCI_NR_FUNCTIONS | ||
37 | |||
38 | /* list of all detected zpci devices */ | ||
39 | LIST_HEAD(zpci_list); | ||
40 | DEFINE_MUTEX(zpci_list_lock); | ||
41 | |||
42 | static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); | ||
43 | static DEFINE_SPINLOCK(zpci_domain_lock); | ||
44 | |||
45 | /* I/O Map */ | ||
46 | static DEFINE_SPINLOCK(zpci_iomap_lock); | ||
47 | static DECLARE_BITMAP(zpci_iomap, ZPCI_IOMAP_MAX_ENTRIES); | ||
48 | struct zpci_iomap_entry *zpci_iomap_start; | ||
49 | EXPORT_SYMBOL_GPL(zpci_iomap_start); | ||
50 | |||
51 | struct zpci_dev *get_zdev(struct pci_dev *pdev) | ||
52 | { | ||
53 | return (struct zpci_dev *) pdev->sysdata; | ||
54 | } | ||
55 | |||
56 | struct zpci_dev *get_zdev_by_fid(u32 fid) | ||
57 | { | ||
58 | struct zpci_dev *tmp, *zdev = NULL; | ||
59 | |||
60 | mutex_lock(&zpci_list_lock); | ||
61 | list_for_each_entry(tmp, &zpci_list, entry) { | ||
62 | if (tmp->fid == fid) { | ||
63 | zdev = tmp; | ||
64 | break; | ||
65 | } | ||
66 | } | ||
67 | mutex_unlock(&zpci_list_lock); | ||
68 | return zdev; | ||
69 | } | ||
70 | |||
71 | bool zpci_fid_present(u32 fid) | ||
72 | { | ||
73 | return (get_zdev_by_fid(fid) != NULL) ? true : false; | ||
74 | } | ||
75 | |||
76 | static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus) | ||
77 | { | ||
78 | return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL; | ||
79 | } | ||
80 | |||
81 | int pci_domain_nr(struct pci_bus *bus) | ||
82 | { | ||
83 | return ((struct zpci_dev *) bus->sysdata)->domain; | ||
84 | } | ||
85 | EXPORT_SYMBOL_GPL(pci_domain_nr); | ||
86 | |||
87 | int pci_proc_domain(struct pci_bus *bus) | ||
88 | { | ||
89 | return pci_domain_nr(bus); | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(pci_proc_domain); | ||
92 | |||
93 | /* Store PCI function information block */ | ||
94 | static int zpci_store_fib(struct zpci_dev *zdev, u8 *fc) | ||
95 | { | ||
96 | struct zpci_fib *fib; | ||
97 | u8 status, cc; | ||
98 | |||
99 | fib = (void *) get_zeroed_page(GFP_KERNEL); | ||
100 | if (!fib) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | do { | ||
104 | cc = __stpcifc(zdev->fh, 0, fib, &status); | ||
105 | if (cc == 2) { | ||
106 | msleep(ZPCI_INSN_BUSY_DELAY); | ||
107 | memset(fib, 0, PAGE_SIZE); | ||
108 | } | ||
109 | } while (cc == 2); | ||
110 | |||
111 | if (cc) | ||
112 | pr_err_once("%s: cc: %u status: %u\n", | ||
113 | __func__, cc, status); | ||
114 | |||
115 | /* Return PCI function controls */ | ||
116 | *fc = fib->fc; | ||
117 | |||
118 | free_page((unsigned long) fib); | ||
119 | return (cc) ? -EIO : 0; | ||
120 | } | ||
121 | |||
122 | #define ZPCI_PCIAS_CFGSPC 15 | ||
123 | |||
124 | static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len) | ||
125 | { | ||
126 | u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len); | ||
127 | u64 data; | ||
128 | int rc; | ||
129 | |||
130 | rc = pcilg_instr(&data, req, offset); | ||
131 | data = data << ((8 - len) * 8); | ||
132 | data = le64_to_cpu(data); | ||
133 | if (!rc) | ||
134 | *val = (u32) data; | ||
135 | else | ||
136 | *val = 0xffffffff; | ||
137 | return rc; | ||
138 | } | ||
139 | |||
140 | static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len) | ||
141 | { | ||
142 | u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len); | ||
143 | u64 data = val; | ||
144 | int rc; | ||
145 | |||
146 | data = cpu_to_le64(data); | ||
147 | data = data >> ((8 - len) * 8); | ||
148 | rc = pcistg_instr(data, req, offset); | ||
149 | return rc; | ||
150 | } | ||
151 | |||
152 | void __devinit pcibios_fixup_bus(struct pci_bus *bus) | ||
153 | { | ||
154 | } | ||
155 | |||
156 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, | ||
157 | resource_size_t size, | ||
158 | resource_size_t align) | ||
159 | { | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* Create a virtual mapping cookie for a PCI BAR */ | ||
164 | void __iomem *pci_iomap(struct pci_dev *pdev, int bar, unsigned long max) | ||
165 | { | ||
166 | struct zpci_dev *zdev = get_zdev(pdev); | ||
167 | u64 addr; | ||
168 | int idx; | ||
169 | |||
170 | if ((bar & 7) != bar) | ||
171 | return NULL; | ||
172 | |||
173 | idx = zdev->bars[bar].map_idx; | ||
174 | spin_lock(&zpci_iomap_lock); | ||
175 | zpci_iomap_start[idx].fh = zdev->fh; | ||
176 | zpci_iomap_start[idx].bar = bar; | ||
177 | spin_unlock(&zpci_iomap_lock); | ||
178 | |||
179 | addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48); | ||
180 | return (void __iomem *) addr; | ||
181 | } | ||
182 | EXPORT_SYMBOL_GPL(pci_iomap); | ||
183 | |||
184 | void pci_iounmap(struct pci_dev *pdev, void __iomem *addr) | ||
185 | { | ||
186 | unsigned int idx; | ||
187 | |||
188 | idx = (((__force u64) addr) & ~ZPCI_IOMAP_ADDR_BASE) >> 48; | ||
189 | spin_lock(&zpci_iomap_lock); | ||
190 | zpci_iomap_start[idx].fh = 0; | ||
191 | zpci_iomap_start[idx].bar = 0; | ||
192 | spin_unlock(&zpci_iomap_lock); | ||
193 | } | ||
194 | EXPORT_SYMBOL_GPL(pci_iounmap); | ||
195 | |||
196 | static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | ||
197 | int size, u32 *val) | ||
198 | { | ||
199 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | ||
200 | |||
201 | if (!zdev || devfn != ZPCI_DEVFN) | ||
202 | return 0; | ||
203 | return zpci_cfg_load(zdev, where, val, size); | ||
204 | } | ||
205 | |||
206 | static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | ||
207 | int size, u32 val) | ||
208 | { | ||
209 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | ||
210 | |||
211 | if (!zdev || devfn != ZPCI_DEVFN) | ||
212 | return 0; | ||
213 | return zpci_cfg_store(zdev, where, val, size); | ||
214 | } | ||
215 | |||
216 | static struct pci_ops pci_root_ops = { | ||
217 | .read = pci_read, | ||
218 | .write = pci_write, | ||
219 | }; | ||
220 | |||
221 | static void zpci_map_resources(struct zpci_dev *zdev) | ||
222 | { | ||
223 | struct pci_dev *pdev = zdev->pdev; | ||
224 | resource_size_t len; | ||
225 | int i; | ||
226 | |||
227 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
228 | len = pci_resource_len(pdev, i); | ||
229 | if (!len) | ||
230 | continue; | ||
231 | pdev->resource[i].start = (resource_size_t) pci_iomap(pdev, i, 0); | ||
232 | pdev->resource[i].end = pdev->resource[i].start + len - 1; | ||
233 | pr_debug("BAR%i: -> start: %Lx end: %Lx\n", | ||
234 | i, pdev->resource[i].start, pdev->resource[i].end); | ||
235 | } | ||
236 | }; | ||
237 | |||
238 | static void zpci_unmap_resources(struct pci_dev *pdev) | ||
239 | { | ||
240 | resource_size_t len; | ||
241 | int i; | ||
242 | |||
243 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
244 | len = pci_resource_len(pdev, i); | ||
245 | if (!len) | ||
246 | continue; | ||
247 | pci_iounmap(pdev, (void *) pdev->resource[i].start); | ||
248 | } | ||
249 | }; | ||
250 | |||
251 | struct zpci_dev *zpci_alloc_device(void) | ||
252 | { | ||
253 | struct zpci_dev *zdev; | ||
254 | |||
255 | /* Alloc memory for our private pci device data */ | ||
256 | zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); | ||
257 | if (!zdev) | ||
258 | return ERR_PTR(-ENOMEM); | ||
259 | return zdev; | ||
260 | } | ||
261 | |||
262 | void zpci_free_device(struct zpci_dev *zdev) | ||
263 | { | ||
264 | kfree(zdev); | ||
265 | } | ||
266 | |||
267 | /* Called on removal of pci_dev, leaves zpci and bus device */ | ||
268 | static void zpci_remove_device(struct pci_dev *pdev) | ||
269 | { | ||
270 | struct zpci_dev *zdev = get_zdev(pdev); | ||
271 | |||
272 | dev_info(&pdev->dev, "Removing device %u\n", zdev->domain); | ||
273 | zdev->state = ZPCI_FN_STATE_CONFIGURED; | ||
274 | zpci_unmap_resources(pdev); | ||
275 | list_del(&zdev->entry); /* can be called from init */ | ||
276 | zdev->pdev = NULL; | ||
277 | } | ||
278 | |||
279 | static void zpci_scan_devices(void) | ||
280 | { | ||
281 | struct zpci_dev *zdev; | ||
282 | |||
283 | mutex_lock(&zpci_list_lock); | ||
284 | list_for_each_entry(zdev, &zpci_list, entry) | ||
285 | if (zdev->state == ZPCI_FN_STATE_CONFIGURED) | ||
286 | zpci_scan_device(zdev); | ||
287 | mutex_unlock(&zpci_list_lock); | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Too late for any s390 specific setup, since interrupts must be set up | ||
292 | * already which requires DMA setup too and the pci scan will access the | ||
293 | * config space, which only works if the function handle is enabled. | ||
294 | */ | ||
295 | int pcibios_enable_device(struct pci_dev *pdev, int mask) | ||
296 | { | ||
297 | struct resource *res; | ||
298 | u16 cmd; | ||
299 | int i; | ||
300 | |||
301 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | ||
302 | |||
303 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
304 | res = &pdev->resource[i]; | ||
305 | |||
306 | if (res->flags & IORESOURCE_IO) | ||
307 | return -EINVAL; | ||
308 | |||
309 | if (res->flags & IORESOURCE_MEM) | ||
310 | cmd |= PCI_COMMAND_MEMORY; | ||
311 | } | ||
312 | pci_write_config_word(pdev, PCI_COMMAND, cmd); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | void pcibios_disable_device(struct pci_dev *pdev) | ||
317 | { | ||
318 | zpci_remove_device(pdev); | ||
319 | pdev->sysdata = NULL; | ||
320 | } | ||
321 | |||
322 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, | ||
323 | unsigned long flags, int domain) | ||
324 | { | ||
325 | struct resource *r; | ||
326 | char *name; | ||
327 | int rc; | ||
328 | |||
329 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
330 | if (!r) | ||
331 | return ERR_PTR(-ENOMEM); | ||
332 | r->start = start; | ||
333 | r->end = r->start + size - 1; | ||
334 | r->flags = flags; | ||
335 | r->parent = &iomem_resource; | ||
336 | name = kmalloc(18, GFP_KERNEL); | ||
337 | if (!name) { | ||
338 | kfree(r); | ||
339 | return ERR_PTR(-ENOMEM); | ||
340 | } | ||
341 | sprintf(name, "PCI Bus: %04x:%02x", domain, ZPCI_BUS_NR); | ||
342 | r->name = name; | ||
343 | |||
344 | rc = request_resource(&iomem_resource, r); | ||
345 | if (rc) | ||
346 | pr_debug("request resource %pR failed\n", r); | ||
347 | return r; | ||
348 | } | ||
349 | |||
350 | static int zpci_alloc_iomap(struct zpci_dev *zdev) | ||
351 | { | ||
352 | int entry; | ||
353 | |||
354 | spin_lock(&zpci_iomap_lock); | ||
355 | entry = find_first_zero_bit(zpci_iomap, ZPCI_IOMAP_MAX_ENTRIES); | ||
356 | if (entry == ZPCI_IOMAP_MAX_ENTRIES) { | ||
357 | spin_unlock(&zpci_iomap_lock); | ||
358 | return -ENOSPC; | ||
359 | } | ||
360 | set_bit(entry, zpci_iomap); | ||
361 | spin_unlock(&zpci_iomap_lock); | ||
362 | return entry; | ||
363 | } | ||
364 | |||
365 | static void zpci_free_iomap(struct zpci_dev *zdev, int entry) | ||
366 | { | ||
367 | spin_lock(&zpci_iomap_lock); | ||
368 | memset(&zpci_iomap_start[entry], 0, sizeof(struct zpci_iomap_entry)); | ||
369 | clear_bit(entry, zpci_iomap); | ||
370 | spin_unlock(&zpci_iomap_lock); | ||
371 | } | ||
372 | |||
373 | static int zpci_create_device_bus(struct zpci_dev *zdev) | ||
374 | { | ||
375 | struct resource *res; | ||
376 | LIST_HEAD(resources); | ||
377 | int i; | ||
378 | |||
379 | /* allocate mapping entry for each used bar */ | ||
380 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
381 | unsigned long addr, size, flags; | ||
382 | int entry; | ||
383 | |||
384 | if (!zdev->bars[i].size) | ||
385 | continue; | ||
386 | entry = zpci_alloc_iomap(zdev); | ||
387 | if (entry < 0) | ||
388 | return entry; | ||
389 | zdev->bars[i].map_idx = entry; | ||
390 | |||
391 | /* only MMIO is supported */ | ||
392 | flags = IORESOURCE_MEM; | ||
393 | if (zdev->bars[i].val & 8) | ||
394 | flags |= IORESOURCE_PREFETCH; | ||
395 | if (zdev->bars[i].val & 4) | ||
396 | flags |= IORESOURCE_MEM_64; | ||
397 | |||
398 | addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); | ||
399 | |||
400 | size = 1UL << zdev->bars[i].size; | ||
401 | |||
402 | res = zpci_alloc_bus_resource(addr, size, flags, zdev->domain); | ||
403 | if (IS_ERR(res)) { | ||
404 | zpci_free_iomap(zdev, entry); | ||
405 | return PTR_ERR(res); | ||
406 | } | ||
407 | pci_add_resource(&resources, res); | ||
408 | } | ||
409 | |||
410 | zdev->bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, | ||
411 | zdev, &resources); | ||
412 | if (!zdev->bus) | ||
413 | return -EIO; | ||
414 | |||
415 | zdev->bus->max_bus_speed = zdev->max_bus_speed; | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int zpci_alloc_domain(struct zpci_dev *zdev) | ||
420 | { | ||
421 | spin_lock(&zpci_domain_lock); | ||
422 | zdev->domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES); | ||
423 | if (zdev->domain == ZPCI_NR_DEVICES) { | ||
424 | spin_unlock(&zpci_domain_lock); | ||
425 | return -ENOSPC; | ||
426 | } | ||
427 | set_bit(zdev->domain, zpci_domain); | ||
428 | spin_unlock(&zpci_domain_lock); | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static void zpci_free_domain(struct zpci_dev *zdev) | ||
433 | { | ||
434 | spin_lock(&zpci_domain_lock); | ||
435 | clear_bit(zdev->domain, zpci_domain); | ||
436 | spin_unlock(&zpci_domain_lock); | ||
437 | } | ||
438 | |||
439 | int zpci_create_device(struct zpci_dev *zdev) | ||
440 | { | ||
441 | int rc; | ||
442 | |||
443 | rc = zpci_alloc_domain(zdev); | ||
444 | if (rc) | ||
445 | goto out; | ||
446 | |||
447 | rc = zpci_create_device_bus(zdev); | ||
448 | if (rc) | ||
449 | goto out_bus; | ||
450 | |||
451 | mutex_lock(&zpci_list_lock); | ||
452 | list_add_tail(&zdev->entry, &zpci_list); | ||
453 | mutex_unlock(&zpci_list_lock); | ||
454 | |||
455 | if (zdev->state == ZPCI_FN_STATE_STANDBY) | ||
456 | return 0; | ||
457 | |||
458 | return 0; | ||
459 | |||
460 | out_bus: | ||
461 | zpci_free_domain(zdev); | ||
462 | out: | ||
463 | return rc; | ||
464 | } | ||
465 | |||
466 | void zpci_stop_device(struct zpci_dev *zdev) | ||
467 | { | ||
468 | /* | ||
469 | * Note: SCLP disables fh via set-pci-fn so don't | ||
470 | * do that here. | ||
471 | */ | ||
472 | } | ||
473 | EXPORT_SYMBOL_GPL(zpci_stop_device); | ||
474 | |||
475 | int zpci_scan_device(struct zpci_dev *zdev) | ||
476 | { | ||
477 | zdev->pdev = pci_scan_single_device(zdev->bus, ZPCI_DEVFN); | ||
478 | if (!zdev->pdev) { | ||
479 | pr_err("pci_scan_single_device failed for fid: 0x%x\n", | ||
480 | zdev->fid); | ||
481 | goto out; | ||
482 | } | ||
483 | |||
484 | zpci_map_resources(zdev); | ||
485 | pci_bus_add_devices(zdev->bus); | ||
486 | |||
487 | /* now that pdev was added to the bus mark it as used */ | ||
488 | zdev->state = ZPCI_FN_STATE_ONLINE; | ||
489 | return 0; | ||
490 | |||
491 | out: | ||
492 | return -EIO; | ||
493 | } | ||
494 | EXPORT_SYMBOL_GPL(zpci_scan_device); | ||
495 | |||
496 | static inline int barsize(u8 size) | ||
497 | { | ||
498 | return (size) ? (1 << size) >> 10 : 0; | ||
499 | } | ||
500 | |||
501 | static int zpci_mem_init(void) | ||
502 | { | ||
503 | /* TODO: use realloc */ | ||
504 | zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start), | ||
505 | GFP_KERNEL); | ||
506 | if (!zpci_iomap_start) | ||
507 | goto error_zdev; | ||
508 | return 0; | ||
509 | |||
510 | error_zdev: | ||
511 | return -ENOMEM; | ||
512 | } | ||
513 | |||
514 | static void zpci_mem_exit(void) | ||
515 | { | ||
516 | kfree(zpci_iomap_start); | ||
517 | } | ||
518 | |||
519 | unsigned int pci_probe = 1; | ||
520 | EXPORT_SYMBOL_GPL(pci_probe); | ||
521 | |||
522 | char * __init pcibios_setup(char *str) | ||
523 | { | ||
524 | if (!strcmp(str, "off")) { | ||
525 | pci_probe = 0; | ||
526 | return NULL; | ||
527 | } | ||
528 | return str; | ||
529 | } | ||
530 | |||
531 | static int __init pci_base_init(void) | ||
532 | { | ||
533 | int rc; | ||
534 | |||
535 | if (!pci_probe) | ||
536 | return 0; | ||
537 | |||
538 | if (!test_facility(2) || !test_facility(69) | ||
539 | || !test_facility(71) || !test_facility(72)) | ||
540 | return 0; | ||
541 | |||
542 | pr_info("Probing PCI hardware: PCI:%d SID:%d AEN:%d\n", | ||
543 | test_facility(69), test_facility(70), | ||
544 | test_facility(71)); | ||
545 | |||
546 | rc = zpci_mem_init(); | ||
547 | if (rc) | ||
548 | goto out_mem; | ||
549 | |||
550 | zpci_scan_devices(); | ||
551 | return 0; | ||
552 | |||
553 | zpci_mem_exit(); | ||
554 | out_mem: | ||
555 | return rc; | ||
556 | } | ||
557 | subsys_initcall(pci_base_init); | ||
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 448303bdb85f..9e0ebe051243 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h | |||
@@ -83,19 +83,25 @@ static inline void __raw_writel(u32 b, volatile void __iomem *addr) | |||
83 | #define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr) | 83 | #define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr) |
84 | 84 | ||
85 | #ifdef CONFIG_64BIT | 85 | #ifdef CONFIG_64BIT |
86 | #ifndef __raw_readq | ||
86 | static inline u64 __raw_readq(const volatile void __iomem *addr) | 87 | static inline u64 __raw_readq(const volatile void __iomem *addr) |
87 | { | 88 | { |
88 | return *(const volatile u64 __force *) addr; | 89 | return *(const volatile u64 __force *) addr; |
89 | } | 90 | } |
91 | #endif | ||
92 | |||
90 | #define readq(addr) __le64_to_cpu(__raw_readq(addr)) | 93 | #define readq(addr) __le64_to_cpu(__raw_readq(addr)) |
91 | 94 | ||
95 | #ifndef __raw_writeq | ||
92 | static inline void __raw_writeq(u64 b, volatile void __iomem *addr) | 96 | static inline void __raw_writeq(u64 b, volatile void __iomem *addr) |
93 | { | 97 | { |
94 | *(volatile u64 __force *) addr = b; | 98 | *(volatile u64 __force *) addr = b; |
95 | } | 99 | } |
96 | #define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr) | ||
97 | #endif | 100 | #endif |
98 | 101 | ||
102 | #define writeq(b, addr) __raw_writeq(__cpu_to_le64(b), addr) | ||
103 | #endif /* CONFIG_64BIT */ | ||
104 | |||
99 | #ifndef PCI_IOBASE | 105 | #ifndef PCI_IOBASE |
100 | #define PCI_IOBASE ((void __iomem *) 0) | 106 | #define PCI_IOBASE ((void __iomem *) 0) |
101 | #endif | 107 | #endif |
@@ -286,15 +292,20 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len) | |||
286 | 292 | ||
287 | #ifndef CONFIG_GENERIC_IOMAP | 293 | #ifndef CONFIG_GENERIC_IOMAP |
288 | struct pci_dev; | 294 | struct pci_dev; |
295 | extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); | ||
296 | |||
297 | #ifndef pci_iounmap | ||
289 | static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p) | 298 | static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p) |
290 | { | 299 | { |
291 | } | 300 | } |
301 | #endif | ||
292 | #endif /* CONFIG_GENERIC_IOMAP */ | 302 | #endif /* CONFIG_GENERIC_IOMAP */ |
293 | 303 | ||
294 | /* | 304 | /* |
295 | * Change virtual addresses to physical addresses and vv. | 305 | * Change virtual addresses to physical addresses and vv. |
296 | * These are pretty trivial | 306 | * These are pretty trivial |
297 | */ | 307 | */ |
308 | #ifndef virt_to_phys | ||
298 | static inline unsigned long virt_to_phys(volatile void *address) | 309 | static inline unsigned long virt_to_phys(volatile void *address) |
299 | { | 310 | { |
300 | return __pa((unsigned long)address); | 311 | return __pa((unsigned long)address); |
@@ -304,6 +315,7 @@ static inline void *phys_to_virt(unsigned long address) | |||
304 | { | 315 | { |
305 | return __va(address); | 316 | return __va(address); |
306 | } | 317 | } |
318 | #endif | ||
307 | 319 | ||
308 | /* | 320 | /* |
309 | * Change "struct page" to physical address. | 321 | * Change "struct page" to physical address. |
@@ -363,9 +375,16 @@ static inline void *bus_to_virt(unsigned long address) | |||
363 | } | 375 | } |
364 | #endif | 376 | #endif |
365 | 377 | ||
378 | #ifndef memset_io | ||
366 | #define memset_io(a, b, c) memset(__io_virt(a), (b), (c)) | 379 | #define memset_io(a, b, c) memset(__io_virt(a), (b), (c)) |
380 | #endif | ||
381 | |||
382 | #ifndef memcpy_fromio | ||
367 | #define memcpy_fromio(a, b, c) memcpy((a), __io_virt(b), (c)) | 383 | #define memcpy_fromio(a, b, c) memcpy((a), __io_virt(b), (c)) |
384 | #endif | ||
385 | #ifndef memcpy_toio | ||
368 | #define memcpy_toio(a, b, c) memcpy(__io_virt(a), (b), (c)) | 386 | #define memcpy_toio(a, b, c) memcpy(__io_virt(a), (b), (c)) |
387 | #endif | ||
369 | 388 | ||
370 | #endif /* __KERNEL__ */ | 389 | #endif /* __KERNEL__ */ |
371 | 390 | ||