diff options
Diffstat (limited to 'drivers/infiniband/hw/ehca/ipz_pt_fn.h')
-rw-r--r-- | drivers/infiniband/hw/ehca/ipz_pt_fn.h | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h new file mode 100644 index 000000000000..2f13509d5257 --- /dev/null +++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * IBM eServer eHCA Infiniband device driver for Linux on POWER | ||
3 | * | ||
4 | * internal queue handling | ||
5 | * | ||
6 | * Authors: Waleri Fomin <fomin@de.ibm.com> | ||
7 | * Reinhard Ernst <rernst@de.ibm.com> | ||
8 | * Christoph Raisch <raisch@de.ibm.com> | ||
9 | * | ||
10 | * Copyright (c) 2005 IBM Corporation | ||
11 | * | ||
12 | * All rights reserved. | ||
13 | * | ||
14 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
15 | * BSD. | ||
16 | * | ||
17 | * OpenIB BSD License | ||
18 | * | ||
19 | * Redistribution and use in source and binary forms, with or without | ||
20 | * modification, are permitted provided that the following conditions are met: | ||
21 | * | ||
22 | * Redistributions of source code must retain the above copyright notice, this | ||
23 | * list of conditions and the following disclaimer. | ||
24 | * | ||
25 | * Redistributions in binary form must reproduce the above copyright notice, | ||
26 | * this list of conditions and the following disclaimer in the documentation | ||
27 | * and/or other materials | ||
28 | * provided with the distribution. | ||
29 | * | ||
30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
31 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
34 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
35 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
36 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
37 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
38 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
39 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
40 | * POSSIBILITY OF SUCH DAMAGE. | ||
41 | */ | ||
42 | |||
43 | #ifndef __IPZ_PT_FN_H__ | ||
44 | #define __IPZ_PT_FN_H__ | ||
45 | |||
46 | #define EHCA_PAGESHIFT 12 | ||
47 | #define EHCA_PAGESIZE 4096UL | ||
48 | #define EHCA_PAGEMASK (~(EHCA_PAGESIZE-1)) | ||
49 | #define EHCA_PT_ENTRIES 512UL | ||
50 | |||
51 | #include "ehca_tools.h" | ||
52 | #include "ehca_qes.h" | ||
53 | |||
54 | /* struct generic ehca page */ | ||
55 | struct ipz_page { | ||
56 | u8 entries[EHCA_PAGESIZE]; | ||
57 | }; | ||
58 | |||
59 | /* struct generic queue in linux kernel virtual memory (kv) */ | ||
60 | struct ipz_queue { | ||
61 | u64 current_q_offset; /* current queue entry */ | ||
62 | |||
63 | struct ipz_page **queue_pages; /* array of pages belonging to queue */ | ||
64 | u32 qe_size; /* queue entry size */ | ||
65 | u32 act_nr_of_sg; | ||
66 | u32 queue_length; /* queue length allocated in bytes */ | ||
67 | u32 pagesize; | ||
68 | u32 toggle_state; /* toggle flag - per page */ | ||
69 | u32 dummy3; /* 64 bit alignment */ | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * return current Queue Entry for a certain q_offset | ||
74 | * returns address (kv) of Queue Entry | ||
75 | */ | ||
76 | static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset) | ||
77 | { | ||
78 | struct ipz_page *current_page; | ||
79 | if (q_offset >= queue->queue_length) | ||
80 | return NULL; | ||
81 | current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT]; | ||
82 | return ¤t_page->entries[q_offset & (EHCA_PAGESIZE - 1)]; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * return current Queue Entry | ||
87 | * returns address (kv) of Queue Entry | ||
88 | */ | ||
89 | static inline void *ipz_qeit_get(struct ipz_queue *queue) | ||
90 | { | ||
91 | return ipz_qeit_calc(queue, queue->current_q_offset); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * return current Queue Page , increment Queue Page iterator from | ||
96 | * page to page in struct ipz_queue, last increment will return 0! and | ||
97 | * NOT wrap | ||
98 | * returns address (kv) of Queue Page | ||
99 | * warning don't use in parallel with ipz_QE_get_inc() | ||
100 | */ | ||
101 | void *ipz_qpageit_get_inc(struct ipz_queue *queue); | ||
102 | |||
103 | /* | ||
104 | * return current Queue Entry, increment Queue Entry iterator by one | ||
105 | * step in struct ipz_queue, will wrap in ringbuffer | ||
106 | * returns address (kv) of Queue Entry BEFORE increment | ||
107 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
108 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
109 | */ | ||
110 | static inline void *ipz_qeit_get_inc(struct ipz_queue *queue) | ||
111 | { | ||
112 | void *ret = ipz_qeit_get(queue); | ||
113 | queue->current_q_offset += queue->qe_size; | ||
114 | if (queue->current_q_offset >= queue->queue_length) { | ||
115 | queue->current_q_offset = 0; | ||
116 | /* toggle the valid flag */ | ||
117 | queue->toggle_state = (~queue->toggle_state) & 1; | ||
118 | } | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * return current Queue Entry, increment Queue Entry iterator by one | ||
125 | * step in struct ipz_queue, will wrap in ringbuffer | ||
126 | * returns address (kv) of Queue Entry BEFORE increment | ||
127 | * returns 0 and does not increment, if wrong valid state | ||
128 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
129 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
130 | */ | ||
131 | static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue) | ||
132 | { | ||
133 | struct ehca_cqe *cqe = ipz_qeit_get(queue); | ||
134 | u32 cqe_flags = cqe->cqe_flags; | ||
135 | |||
136 | if ((cqe_flags >> 7) != (queue->toggle_state & 1)) | ||
137 | return NULL; | ||
138 | |||
139 | ipz_qeit_get_inc(queue); | ||
140 | return cqe; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * returns and resets Queue Entry iterator | ||
145 | * returns address (kv) of first Queue Entry | ||
146 | */ | ||
147 | static inline void *ipz_qeit_reset(struct ipz_queue *queue) | ||
148 | { | ||
149 | queue->current_q_offset = 0; | ||
150 | return ipz_qeit_get(queue); | ||
151 | } | ||
152 | |||
153 | /* struct generic page table */ | ||
154 | struct ipz_pt { | ||
155 | u64 entries[EHCA_PT_ENTRIES]; | ||
156 | }; | ||
157 | |||
158 | /* struct page table for a queue, only to be used in pf */ | ||
159 | struct ipz_qpt { | ||
160 | /* queue page tables (kv), use u64 because we know the element length */ | ||
161 | u64 *qpts; | ||
162 | u32 n_qpts; | ||
163 | u32 n_ptes; /* number of page table entries */ | ||
164 | u64 *current_pte_addr; | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * constructor for a ipz_queue_t, placement new for ipz_queue_t, | ||
169 | * new for all dependent datastructors | ||
170 | * all QP Tables are the same | ||
171 | * flow: | ||
172 | * allocate+pin queue | ||
173 | * see ipz_qpt_ctor() | ||
174 | * returns true if ok, false if out of memory | ||
175 | */ | ||
176 | int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages, | ||
177 | const u32 pagesize, const u32 qe_size, | ||
178 | const u32 nr_of_sg); | ||
179 | |||
180 | /* | ||
181 | * destructor for a ipz_queue_t | ||
182 | * -# free queue | ||
183 | * see ipz_queue_ctor() | ||
184 | * returns true if ok, false if queue was NULL-ptr of free failed | ||
185 | */ | ||
186 | int ipz_queue_dtor(struct ipz_queue *queue); | ||
187 | |||
188 | /* | ||
189 | * constructor for a ipz_qpt_t, | ||
190 | * placement new for struct ipz_queue, new for all dependent datastructors | ||
191 | * all QP Tables are the same, | ||
192 | * flow: | ||
193 | * -# allocate+pin queue | ||
194 | * -# initialise ptcb | ||
195 | * -# allocate+pin PTs | ||
196 | * -# link PTs to a ring, according to HCA Arch, set bit62 id needed | ||
197 | * -# the ring must have room for exactly nr_of_PTEs | ||
198 | * see ipz_qpt_ctor() | ||
199 | */ | ||
200 | void ipz_qpt_ctor(struct ipz_qpt *qpt, | ||
201 | const u32 nr_of_qes, | ||
202 | const u32 pagesize, | ||
203 | const u32 qe_size, | ||
204 | const u8 lowbyte, const u8 toggle, | ||
205 | u32 * act_nr_of_QEs, u32 * act_nr_of_pages); | ||
206 | |||
207 | /* | ||
208 | * return current Queue Entry, increment Queue Entry iterator by one | ||
209 | * step in struct ipz_queue, will wrap in ringbuffer | ||
210 | * returns address (kv) of Queue Entry BEFORE increment | ||
211 | * warning don't use in parallel with ipz_qpageit_get_inc() | ||
212 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
213 | * fix EQ page problems | ||
214 | */ | ||
215 | void *ipz_qeit_eq_get_inc(struct ipz_queue *queue); | ||
216 | |||
217 | /* | ||
218 | * return current Event Queue Entry, increment Queue Entry iterator | ||
219 | * by one step in struct ipz_queue if valid, will wrap in ringbuffer | ||
220 | * returns address (kv) of Queue Entry BEFORE increment | ||
221 | * returns 0 and does not increment, if wrong valid state | ||
222 | * warning don't use in parallel with ipz_queue_QPageit_get_inc() | ||
223 | * warning unpredictable results may occur if steps>act_nr_of_queue_entries | ||
224 | */ | ||
225 | static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue) | ||
226 | { | ||
227 | void *ret = ipz_qeit_get(queue); | ||
228 | u32 qe = *(u8 *) ret; | ||
229 | if ((qe >> 7) != (queue->toggle_state & 1)) | ||
230 | return NULL; | ||
231 | ipz_qeit_eq_get_inc(queue); /* this is a good one */ | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | /* returns address (GX) of first queue entry */ | ||
236 | static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt) | ||
237 | { | ||
238 | return be64_to_cpu(qpt->qpts[0]); | ||
239 | } | ||
240 | |||
241 | /* returns address (kv) of first page of queue page table */ | ||
242 | static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt) | ||
243 | { | ||
244 | return qpt->qpts; | ||
245 | } | ||
246 | |||
247 | #endif /* __IPZ_PT_FN_H__ */ | ||