[MLTHCA] added polling mode support.
[mirror/winof/.git] / hw / mthca / kernel / mthca_eq.c
1 /*\r
2  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.\r
3  * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
4  *\r
5  * This software is available to you under a choice of one of two\r
6  * licenses.  You may choose to be licensed under the terms of the GNU\r
7  * General Public License (GPL) Version 2, available from the file\r
8  * COPYING in the main directory of this source tree, or the\r
9  * OpenIB.org BSD license below:\r
10  *\r
11  *     Redistribution and use in source and binary forms, with or\r
12  *     without modification, are permitted provided that the following\r
13  *     conditions are met:\r
14  *\r
15  *      - Redistributions of source code must retain the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer.\r
18  *\r
19  *      - Redistributions in binary form must reproduce the above\r
20  *        copyright notice, this list of conditions and the following\r
21  *        disclaimer in the documentation and/or other materials\r
22  *        provided with the distribution.\r
23  *\r
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
31  * SOFTWARE.\r
32  *\r
33  * $Id$\r
34  */\r
35 \r
36 #include "mthca_dev.h"\r
37 #if defined(EVENT_TRACING)\r
38 #ifdef offsetof\r
39 #undef offsetof\r
40 #endif\r
41 #include "mthca_eq.tmh"\r
42 #endif\r
43 #include "mthca_cmd.h"\r
44 #include "mthca_config_reg.h"\r
45 #include "mthca_wqe.h"\r
46 \r
47 static int mthca_map_reg(struct mthca_dev *dev,\r
48                                    u64 offset, unsigned long size,\r
49                                    void __iomem **map, SIZE_T *map_size);\r
50 static int mthca_map_eq_regs(struct mthca_dev *dev);\r
51 static void mthca_unmap_eq_regs(struct mthca_dev *dev);\r
52 static int mthca_create_eq(struct mthca_dev *dev,\r
53                                      int nent,\r
54                                      u8 intr,\r
55                                      struct mthca_eq *eq);\r
56 \r
57 \r
58 \r
59 #ifdef ALLOC_PRAGMA\r
60 #pragma alloc_text (PAGE, mthca_map_reg)\r
61 #pragma alloc_text (PAGE, mthca_map_eq_regs)\r
62 #pragma alloc_text (PAGE, mthca_init_eq_table)\r
63 #pragma alloc_text (PAGE, mthca_unmap_eq_regs)\r
64 #pragma alloc_text (PAGE, mthca_map_eq_icm)\r
65 #pragma alloc_text (PAGE, mthca_unmap_eq_icm)\r
66 #pragma alloc_text (PAGE, mthca_create_eq)\r
67 #pragma alloc_text (PAGE, mthca_cleanup_eq_table)\r
68 #endif\r
69 \r
70 enum {\r
71         MTHCA_NUM_ASYNC_EQE = 0x80,\r
72         MTHCA_NUM_CMD_EQE   = 0x80,\r
73         MTHCA_NUM_SPARE_EQE = 0x80,\r
74         MTHCA_EQ_ENTRY_SIZE = 0x20\r
75 };\r
76 \r
77 /*\r
78  * Must be packed because start is 64 bits but only aligned to 32 bits.\r
79  */\r
80 #pragma pack(push,1)\r
81 struct mthca_eq_context {\r
82         __be32 flags;\r
83         __be64 start;\r
84         __be32 logsize_usrpage;\r
85         __be32 tavor_pd;        /* reserved for Arbel */\r
86         u8     reserved1[3];\r
87         u8     intr;\r
88         __be32 arbel_pd;        /* lost_count for Tavor */\r
89         __be32 lkey;\r
90         u32    reserved2[2];\r
91         __be32 consumer_index;\r
92         __be32 producer_index;\r
93         u32    reserved3[4];\r
94 };\r
95 #pragma pack(pop)\r
96 \r
97 #define MTHCA_EQ_STATUS_OK          ( 0 << 28)\r
98 #define MTHCA_EQ_STATUS_OVERFLOW    ( 9 << 28)\r
99 #define MTHCA_EQ_STATUS_WRITE_FAIL  (10 << 28)\r
100 #define MTHCA_EQ_OWNER_SW           ( 0 << 24)\r
101 #define MTHCA_EQ_OWNER_HW           ( 1 << 24)\r
102 #define MTHCA_EQ_FLAG_TR            ( 1 << 18)\r
103 #define MTHCA_EQ_FLAG_OI            ( 1 << 17)\r
104 #define MTHCA_EQ_STATE_ARMED        ( 1 <<  8)\r
105 #define MTHCA_EQ_STATE_FIRED        ( 2 <<  8)\r
106 #define MTHCA_EQ_STATE_ALWAYS_ARMED ( 3 <<  8)\r
107 #define MTHCA_EQ_STATE_ARBEL        ( 8 <<  8)\r
108 \r
109 enum {\r
110         MTHCA_EVENT_TYPE_COMP                                                   = 0x00,\r
111         MTHCA_EVENT_TYPE_PATH_MIG                                       = 0x01,\r
112         MTHCA_EVENT_TYPE_COMM_EST                                       = 0x02,\r
113         MTHCA_EVENT_TYPE_SQ_DRAINED                             = 0x03,\r
114         MTHCA_EVENT_TYPE_CQ_ERROR                                               = 0x04,\r
115         MTHCA_EVENT_TYPE_WQ_CATAS_ERROR                         = 0x05,\r
116         MTHCA_EVENT_TYPE_EEC_CATAS_ERROR                        = 0x06,\r
117         MTHCA_EVENT_TYPE_PATH_MIG_FAILED                        = 0x07,\r
118         MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR      = 0x08,\r
119         MTHCA_EVENT_TYPE_PORT_CHANGE                                    = 0x09,\r
120         MTHCA_EVENT_TYPE_CMD                                                                    = 0x0a,\r
121         MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,\r
122         MTHCA_EVENT_TYPE_ECC_DETECT                                     = 0x0e,\r
123         MTHCA_EVENT_TYPE_EQ_OVERFLOW                                    = 0x0f,\r
124         MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR                = 0x11,\r
125         MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR                        = 0x12,\r
126         MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE        = 0x13, \r
127         MTHCA_EVENT_TYPE_SRQ_LIMIT                                      = 0x14  \r
128 };\r
129 \r
130 #define MTHCA_ASYNC_EVENT_MASK ((1Ui64 << MTHCA_EVENT_TYPE_PATH_MIG)           | \\r
131                                 (1Ui64 << MTHCA_EVENT_TYPE_COMM_EST)           | \\r
132                                 (1Ui64 << MTHCA_EVENT_TYPE_SQ_DRAINED)         | \\r
133                                 (1Ui64 << MTHCA_EVENT_TYPE_CQ_ERROR)           | \\r
134                                 (1Ui64 << MTHCA_EVENT_TYPE_WQ_CATAS_ERROR)     | \\r
135                                 (1Ui64 << MTHCA_EVENT_TYPE_EEC_CATAS_ERROR)    | \\r
136                                 (1Ui64 << MTHCA_EVENT_TYPE_PATH_MIG_FAILED)    | \\r
137                                 (1Ui64 << MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \\r
138                                 (1Ui64 << MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR)    | \\r
139                                 (1Ui64 << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \\r
140                                 (1Ui64 << MTHCA_EVENT_TYPE_PORT_CHANGE)        | \\r
141                                 (1Ui64 << MTHCA_EVENT_TYPE_ECC_DETECT))\r
142 #define MTHCA_SRQ_EVENT_MASK   ((1Ui64 << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR)    | \\r
143                                         (1Ui64 << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE)             | \\r
144                                         (1Ui64 << MTHCA_EVENT_TYPE_SRQ_LIMIT))\r
145 \r
146 #define MTHCA_CMD_EVENT_MASK    (1Ui64 << MTHCA_EVENT_TYPE_CMD)\r
147 \r
148 #define MTHCA_EQ_DB_INC_CI     (1 << 24)\r
149 #define MTHCA_EQ_DB_REQ_NOT    (2 << 24)\r
150 #define MTHCA_EQ_DB_DISARM_CQ  (3 << 24)\r
151 #define MTHCA_EQ_DB_SET_CI     (4 << 24)\r
152 #define MTHCA_EQ_DB_ALWAYS_ARM (5 << 24)\r
153 \r
154 #pragma pack(push,1)\r
155 struct mthca_eqe {\r
156         u8 reserved1;\r
157         u8 type;\r
158         u8 reserved2;\r
159         u8 subtype;\r
160         union {\r
161                 u32 raw[6];\r
162                 struct {\r
163                         __be32 cqn;\r
164                 } comp;\r
165                 struct {\r
166                         u16    reserved1;\r
167                         __be16 token;\r
168                         u32    reserved2;\r
169                         u8     reserved3[3];\r
170                         u8     status;\r
171                         __be64 out_param;\r
172                 } cmd;\r
173                 struct {\r
174                         __be32 qpn;\r
175                         u32    reserved1;\r
176                         u32    reserved2;\r
177                         u8     reserved3[1];\r
178                         u8     vendor_code;\r
179                         u8     reserved4[2];\r
180                 } qp;\r
181                 struct {                        \r
182                         __be32 srqn;            \r
183                         u32    reserved1;\r
184                         u32    reserved2;\r
185                         u8     reserved3[1];\r
186                         u8     vendor_code;\r
187                         u8     reserved4[2];\r
188                 }       srq;\r
189                 struct {\r
190                         __be32 cqn;\r
191                         u32    reserved1;\r
192                         u8     reserved2[3];\r
193                         u8     syndrome;\r
194                 } cq_err;\r
195                 struct {\r
196                         u32    reserved1[2];\r
197                         __be32 port;\r
198                 } port_change;\r
199         } event;\r
200         u8 reserved3[3];\r
201         u8 owner;\r
202 } ;\r
203 #pragma pack(pop)\r
204 \r
205 #define  MTHCA_EQ_ENTRY_OWNER_SW      (0 << 7)\r
206 #define  MTHCA_EQ_ENTRY_OWNER_HW      (1 << 7)\r
207 \r
208 static inline u64 async_mask(struct mthca_dev *dev)\r
209 {\r
210         return dev->mthca_flags & MTHCA_FLAG_SRQ ?\r
211                 MTHCA_ASYNC_EVENT_MASK | MTHCA_SRQ_EVENT_MASK :\r
212                 MTHCA_ASYNC_EVENT_MASK;\r
213 }\r
214 \r
215 static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)\r
216 {\r
217         __be32 doorbell[2];\r
218 \r
219         doorbell[0] = cl_hton32(MTHCA_EQ_DB_SET_CI | eq->eqn);\r
220         doorbell[1] = cl_hton32(ci & (eq->nent - 1));\r
221 \r
222         /*\r
223          * This barrier makes sure that all updates to ownership bits\r
224          * done by set_eqe_hw() hit memory before the consumer index\r
225          * is updated.  set_eq_ci() allows the HCA to possibly write\r
226          * more EQ entries, and we want to avoid the exceedingly\r
227          * unlikely possibility of the HCA writing an entry and then\r
228          * having set_eqe_hw() overwrite the owner field.\r
229          */\r
230         wmb();\r
231         mthca_write64(doorbell,\r
232                       dev->kar + MTHCA_EQ_DOORBELL,\r
233                       MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));\r
234 }\r
235 \r
236 static inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)\r
237 {\r
238         /* See comment in tavor_set_eq_ci() above. */\r
239         wmb();\r
240         __raw_writel((u32) cl_hton32(ci),\r
241                 (u8*)dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8);\r
242         /* We still want ordering, just not swabbing, so add a barrier */\r
243         mb();\r
244 }\r
245 \r
246 static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)\r
247 {\r
248         if (mthca_is_memfree(dev))\r
249                 arbel_set_eq_ci(dev, eq, ci);\r
250         else\r
251                 tavor_set_eq_ci(dev, eq, ci);\r
252 }\r
253 \r
254 static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)\r
255 {\r
256         __be32 doorbell[2];\r
257 \r
258         doorbell[0] = cl_hton32(MTHCA_EQ_DB_REQ_NOT | eqn);\r
259         doorbell[1] = 0;\r
260 \r
261         mthca_write64(doorbell,\r
262                       dev->kar + MTHCA_EQ_DOORBELL,\r
263                       MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));\r
264 }\r
265 \r
266 static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)\r
267 {\r
268         writel(eqn_mask, dev->eq_regs.arbel.eq_arm);\r
269 }\r
270 \r
271 static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)\r
272 {\r
273         if (!mthca_is_memfree(dev)) {\r
274                 __be32 doorbell[2];\r
275 \r
276                 doorbell[0] = cl_hton32(MTHCA_EQ_DB_DISARM_CQ | eqn);\r
277                 doorbell[1] = cl_hton32(cqn);\r
278 \r
279                 mthca_write64(doorbell,\r
280                               dev->kar + MTHCA_EQ_DOORBELL,\r
281                               MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));\r
282         }\r
283 }\r
284 \r
285 static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry)\r
286 {\r
287         unsigned long off = (entry & (eq->nent - 1)) * MTHCA_EQ_ENTRY_SIZE;\r
288         return (struct mthca_eqe *)((u8*)eq->page_list[off / PAGE_SIZE].page + off % PAGE_SIZE);\r
289 }\r
290 \r
291 static inline struct mthca_eqe* next_eqe_sw(struct mthca_eq *eq)\r
292 {\r
293         struct mthca_eqe* eqe;\r
294         eqe = get_eqe(eq, eq->cons_index);\r
295         return (MTHCA_EQ_ENTRY_OWNER_HW & eqe->owner) ? NULL : eqe;\r
296 }\r
297 \r
298 static inline void set_eqe_hw(struct mthca_eqe *eqe)\r
299 {\r
300         eqe->owner =  MTHCA_EQ_ENTRY_OWNER_HW;\r
301 }\r
302 \r
303 static void port_change(struct mthca_dev *dev, int port, int active)\r
304 {\r
305         struct ib_event record;\r
306 \r
307         HCA_PRINT(TRACE_LEVEL_VERBOSE,HCA_DBG_LOW,("Port change to %s for port %d\n",\r
308                   active ? "active" : "down", port));\r
309 \r
310         record.device = &dev->ib_dev;\r
311         record.event  = active ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;\r
312         record.element.port_num = (u8)port;\r
313         // Gen2 ib_core mechanism\r
314         ib_dispatch_event(&record);\r
315         // our callback\r
316         ca_event_handler( &record, &dev->ext->hca.hob );\r
317 }\r
318 \r
319 static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)\r
320 {\r
321         int disarm_cqn;\r
322         int  eqes_found = 0;\r
323         int set_ci = 0;\r
324         struct mthca_eqe *eqe = next_eqe_sw(eq);\r
325     uint64_t start = cl_get_time_stamp();\r
326     int loops = 0;\r
327 \r
328         while (eqe) {\r
329 \r
330                 /*\r
331                  * Make sure we read EQ entry contents after we've\r
332                  * checked the ownership bit.\r
333                  */\r
334                 rmb();\r
335 \r
336                 switch (eqe->type) {\r
337                 case MTHCA_EVENT_TYPE_COMP:\r
338                         disarm_cqn = cl_ntoh32(eqe->event.comp.cqn) & 0xffffff;\r
339                         disarm_cq(dev, eq->eqn, disarm_cqn);\r
340                         mthca_cq_completion(dev, disarm_cqn);\r
341                         break;\r
342 \r
343                 case MTHCA_EVENT_TYPE_PATH_MIG:\r
344                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
345                                        IB_EVENT_PATH_MIG, eqe->event.qp.vendor_code);\r
346                         break;\r
347 \r
348                 case MTHCA_EVENT_TYPE_COMM_EST:\r
349                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
350                                        IB_EVENT_COMM_EST, eqe->event.qp.vendor_code);\r
351                         break;\r
352 \r
353                 case MTHCA_EVENT_TYPE_SQ_DRAINED:\r
354                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
355                                        IB_EVENT_SQ_DRAINED, eqe->event.qp.vendor_code);\r
356                         break;\r
357 \r
358                 case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE:\r
359                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
360                                        IB_EVENT_SRQ_QP_LAST_WQE_REACHED, eqe->event.qp.vendor_code);\r
361                         break;\r
362 \r
363                 case MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR:\r
364                         mthca_srq_event(dev, cl_ntoh32(eqe->event.srq.srqn) & 0xffffff,\r
365                                 IB_EVENT_SRQ_LIMIT_REACHED, eqe->event.qp.vendor_code);\r
366                         break;\r
367 \r
368                 case MTHCA_EVENT_TYPE_SRQ_LIMIT:\r
369                         mthca_srq_event(dev, cl_ntoh32(eqe->event.srq.srqn) & 0xffffff,\r
370                                 IB_EVENT_SRQ_LIMIT_REACHED, eqe->event.qp.vendor_code);\r
371                         break;\r
372 \r
373                 case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR:\r
374                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
375                                        IB_EVENT_QP_FATAL, eqe->event.qp.vendor_code);\r
376                         break;\r
377 \r
378                 case MTHCA_EVENT_TYPE_PATH_MIG_FAILED:\r
379                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
380                                        IB_EVENT_PATH_MIG_ERR, eqe->event.qp.vendor_code);\r
381                         break;\r
382 \r
383                 case MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR:\r
384                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
385                                        IB_EVENT_QP_REQ_ERR, eqe->event.qp.vendor_code);\r
386                         break;\r
387 \r
388                 case MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR:\r
389                         mthca_qp_event(dev, cl_ntoh32(eqe->event.qp.qpn) & 0xffffff,\r
390                                        IB_EVENT_QP_ACCESS_ERR, eqe->event.qp.vendor_code);\r
391                         break;\r
392 \r
393                 case MTHCA_EVENT_TYPE_CMD:\r
394                         mthca_cmd_event(dev,\r
395                                         cl_ntoh16(eqe->event.cmd.token),\r
396                                         eqe->event.cmd.status,\r
397                                         cl_ntoh64(eqe->event.cmd.out_param));\r
398                         break;\r
399 \r
400                 case MTHCA_EVENT_TYPE_PORT_CHANGE:\r
401                         port_change(dev,\r
402                                     (cl_ntoh32(eqe->event.port_change.port) >> 28) & 3,\r
403                                     eqe->subtype == 0x4);\r
404                         break;\r
405 \r
406                 case MTHCA_EVENT_TYPE_CQ_ERROR:\r
407                         HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW, ("CQ %s on CQN %06x (syndrome %d)\n",\r
408                                    eqe->event.cq_err.syndrome == 1 ?\r
409                                    "overrun" : "access violation",\r
410                                    cl_ntoh32(eqe->event.cq_err.cqn) & 0xffffff, eqe->event.cq_err.syndrome));\r
411                         mthca_cq_event(dev, cl_ntoh32(eqe->event.cq_err.cqn),\r
412                                 IB_EVENT_CQ_ERR);\r
413                         break;\r
414 \r
415                 case MTHCA_EVENT_TYPE_EQ_OVERFLOW:\r
416                         HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_LOW  ,("EQ overrun on EQN %d\n", eq->eqn));\r
417                         break;\r
418 \r
419                 case MTHCA_EVENT_TYPE_EEC_CATAS_ERROR:\r
420                 case MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR:\r
421                 case MTHCA_EVENT_TYPE_ECC_DETECT:\r
422                 default:\r
423                         HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW, ("Unhandled event %02x(%02x) on EQ %d\n",\r
424                                    eqe->type, eqe->subtype, eq->eqn));\r
425                         break;\r
426                 };\r
427 \r
428                 set_eqe_hw(eqe);\r
429                 ++eq->cons_index;\r
430                 eqes_found += 1;\r
431                 ++set_ci;\r
432 \r
433                 /*\r
434                  * The HCA will think the queue has overflowed if we\r
435                  * don't tell it we've been processing events.  We\r
436                  * create our EQs with MTHCA_NUM_SPARE_EQE extra\r
437                  * entries, so we must update our consumer index at\r
438                  * least that often.\r
439                  */\r
440                 if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) {\r
441                         /*\r
442                          * Conditional on hca_type is OK here because\r
443                          * this is a rare case, not the fast path.\r
444                          */\r
445                         set_eq_ci(dev, eq, eq->cons_index);\r
446                         set_ci = 0;\r
447                 }\r
448         loops++;\r
449         if (cl_get_time_stamp() - start > g_max_DPC_time_us ) {\r
450             HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("Handling of EQ stopped, and a new DPC is entered after %d loops\n", loops));\r
451             KeInsertQueueDpc(&dev->eq_table.eq[eq->eq_num].dpc, NULL, NULL);\r
452             break;\r
453         }       \r
454                 eqe = next_eqe_sw(eq);\r
455         }\r
456 \r
457         /*\r
458          * Rely on caller to set consumer index so that we don't have\r
459          * to test hca_type in our interrupt handling fast path.\r
460          */\r
461         return eqes_found;\r
462 }\r
463 \r
464 static void mthca_tavor_dpc( PRKDPC dpc, \r
465         PVOID ctx, PVOID arg1, PVOID arg2 )\r
466 {\r
467         struct mthca_eq  *eq  = ctx;\r
468         struct mthca_dev *dev = eq->dev;\r
469         SPIN_LOCK_PREP(lh);\r
470 \r
471         UNREFERENCED_PARAMETER(dpc);\r
472         UNREFERENCED_PARAMETER(arg1);\r
473         UNREFERENCED_PARAMETER(arg2);\r
474 \r
475         spin_lock_dpc(&eq->lock, &lh);\r
476 \r
477         /* we need 'if' in case, when there were scheduled 2 DPC for one EQ */\r
478         if (mthca_eq_int(dev, eq)) {\r
479                 tavor_set_eq_ci(dev, eq, eq->cons_index);\r
480                 tavor_eq_req_not(dev, eq->eqn);\r
481         }\r
482 \r
483         spin_unlock_dpc(&lh);\r
484 }\r
485 \r
486 static BOOLEAN mthca_tavor_interrupt(\r
487         PKINTERRUPT     int_obj, \r
488         PVOID                           ctx\r
489         )\r
490 {\r
491         struct mthca_dev *dev = ctx;\r
492         u32 ecr;\r
493         int i;\r
494 \r
495         UNREFERENCED_PARAMETER(int_obj);\r
496 \r
497         if (dev->eq_table.clr_mask)\r
498                 writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);\r
499 \r
500         ecr = readl((u8*)dev->eq_regs.tavor.ecr_base + 4);\r
501         if (!ecr)\r
502                 return FALSE;\r
503 \r
504         writel(ecr, (u8*)dev->eq_regs.tavor.ecr_base +\r
505                MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4);\r
506 \r
507         for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
508                 if (ecr & dev->eq_table.eq[i].eqn_mask &&\r
509                     next_eqe_sw(&dev->eq_table.eq[i])) {\r
510                         KeInsertQueueDpc(&dev->eq_table.eq[i].dpc, NULL, NULL);\r
511                 }\r
512         }\r
513 \r
514         return TRUE;\r
515 }\r
516 \r
517 #ifdef MSI_SUPPORT\r
518 static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr,\r
519                                          struct pt_regs *regs)\r
520 {\r
521         struct mthca_eq  *eq  = eq_ptr;\r
522         struct mthca_dev *dev = eq->dev;\r
523 \r
524         mthca_eq_int(dev, eq);\r
525         tavor_set_eq_ci(dev, eq, eq->cons_index);\r
526         tavor_eq_req_not(dev, eq->eqn);\r
527 \r
528         /* MSI-X vectors always belong to us */\r
529         return IRQ_HANDLED;\r
530 }\r
531 #endif\r
532 \r
533 static void mthca_arbel_dpc( PRKDPC dpc, \r
534         PVOID ctx, PVOID arg1, PVOID arg2 )\r
535 {\r
536         struct mthca_eq  *eq  = ctx;\r
537         struct mthca_dev *dev = eq->dev;\r
538         SPIN_LOCK_PREP(lh);\r
539 \r
540         UNREFERENCED_PARAMETER(dpc);\r
541         UNREFERENCED_PARAMETER(arg1);\r
542         UNREFERENCED_PARAMETER(arg2);\r
543 \r
544         spin_lock_dpc(&eq->lock, &lh);\r
545 \r
546         /* we need 'if' in case, when there were scheduled 2 DPC for one EQ */\r
547         if (mthca_eq_int(dev, eq))\r
548                 arbel_set_eq_ci(dev, eq, eq->cons_index);\r
549         arbel_eq_req_not(dev, eq->eqn_mask);\r
550 \r
551         spin_unlock_dpc(&lh);\r
552 }\r
553 \r
554 static BOOLEAN mthca_arbel_interrupt(\r
555         PKINTERRUPT     int_obj, \r
556         PVOID                           ctx\r
557         )\r
558 {\r
559         struct mthca_dev *dev = ctx;\r
560         int work = 0;\r
561         int i;\r
562 \r
563         UNREFERENCED_PARAMETER(int_obj);\r
564 \r
565         if (dev->eq_table.clr_mask)\r
566                 writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);\r
567 \r
568         for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
569                 if (next_eqe_sw( &dev->eq_table.eq[i]) ) {\r
570                         work = 1;\r
571                         while(InterlockedCompareExchange(&dev->dpc_lock, 1, 0));\r
572                         \r
573                         KeInsertQueueDpc(&dev->eq_table.eq[i].dpc, NULL, NULL);\r
574                         InterlockedCompareExchange(&dev->dpc_lock, 0, 1);\r
575                 } else {\r
576                         arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);\r
577                 }\r
578         }\r
579 \r
580         return (BOOLEAN)work;\r
581 }\r
582 \r
583 #ifdef MSI_SUPPORT\r
584 static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr,\r
585                                                struct pt_regs *regs)\r
586 {\r
587         struct mthca_eq  *eq  = eq_ptr;\r
588         struct mthca_dev *dev = eq->dev;\r
589 \r
590         mthca_eq_int(dev, eq);\r
591         arbel_set_eq_ci(dev, eq, eq->cons_index);\r
592         arbel_eq_req_not(dev, eq->eqn_mask);\r
593 \r
594         /* MSI-X vectors always belong to us */\r
595         return IRQ_HANDLED;\r
596 }\r
597 #endif\r
598 \r
599 #if 1//WORKAROUND_POLL_EQ\r
600 \r
601 BOOLEAN\r
602 IsrSynchronizeRoutine(\r
603         IN PVOID  SynchronizeContext\r
604         )\r
605 {\r
606         struct mthca_dev *dev = (struct mthca_dev *)SynchronizeContext;\r
607 \r
608         //Is this always correct?\r
609         mthca_arbel_interrupt(dev->ext->int_obj,dev);\r
610     \r
611         return TRUE;\r
612 }\r
613 \r
614 \r
615 VOID eq_polling_thread(void *ctx) \r
616 {\r
617 #define POLLING_INTERVAL_MS     50\r
618         NTSTATUS status;\r
619         struct mthca_dev *dev = (struct mthca_dev *)ctx;\r
620         PVOID wait_objects[2];\r
621         LARGE_INTEGER  wait_time;\r
622 \r
623         wait_objects[0] = &dev->eq_table.thread_stop_event;\r
624         wait_objects[1] = &dev->eq_table.thread_start_event;\r
625 \r
626         for(;;){\r
627 \r
628                 /* before start polling */\r
629                 DbgPrint("Before polling.\n");\r
630                 for (;;) {\r
631                         status = KeWaitForMultipleObjects( 2, wait_objects, \r
632                                                                                            WaitAny, Executive, KernelMode, FALSE, NULL, NULL );\r
633 \r
634                         if ( status == STATUS_WAIT_0 ){/* thread stopped */\r
635                                 DbgPrint("Signaled to stop polling.\n");\r
636                                 break;          \r
637                         }\r
638 \r
639                         /* start polling */\r
640                         if ( status == STATUS_WAIT_1 ){\r
641                                 DbgPrint("Signaled to start polling.\n");\r
642                                 break;          \r
643                         }\r
644 \r
645                 }\r
646 \r
647                 if(dev->eq_table.bTerminated) break;\r
648                 if ( status == STATUS_WAIT_0 ) continue;/* thread stopped, wait for start again */\r
649 \r
650                 /* polling */\r
651                 DbgPrint("Start polling.\n");\r
652                 wait_time.QuadPart = -(int64_t)(((uint64_t)POLLING_INTERVAL_MS) * 10000);\r
653                 for (;;) {\r
654                         //mlx4_interrupt( NULL, &priv->dev );\r
655                         KeSynchronizeExecution(dev->ext->int_obj, IsrSynchronizeRoutine, dev);\r
656 \r
657                         status = KeWaitForSingleObject( &dev->eq_table.thread_stop_event, \r
658                                                                                         Executive, KernelMode, FALSE, &wait_time );\r
659                         if ( status == STATUS_SUCCESS ) {\r
660                                 //KeClearEvent(&priv->eq_table.thread_stop_event);\r
661                                 DbgPrint("Signaled to stop polling while in polling mode.\n");\r
662                                 break;          /* thread stopped */\r
663                         }\r
664                 }\r
665 \r
666                 if(dev->eq_table.bTerminated) break;\r
667         }\r
668 \r
669         DbgPrint("Polling thread terminated.\n");\r
670         PsTerminateSystemThread(STATUS_SUCCESS);\r
671 \r
672 }\r
673 \r
674 \r
675 void mlnx_poll_eq(struct ib_device *device, BOOLEAN bStart)\r
676 {\r
677         LONG signalled=0;\r
678         struct mthca_dev *dev = (struct mthca_dev *)(device);\r
679 \r
680         if(bStart){\r
681                 /* signal start of polling */\r
682                 signalled = KeSetEvent(         \r
683                         &dev->eq_table.thread_start_event, IO_NO_INCREMENT, FALSE );\r
684         }else{\r
685                 /* signal end of polling */\r
686                 signalled = KeSetEvent(         \r
687                         &dev->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE );\r
688         }\r
689 \r
690 }\r
691 \r
692 #endif\r
693 \r
694 static int mthca_create_eq(struct mthca_dev *dev,\r
695                                      int nent,\r
696                                      u8 intr,\r
697                                      struct mthca_eq *eq)\r
698 {\r
699         int npages;\r
700         u64 *dma_list = NULL;\r
701         struct mthca_mailbox *mailbox;\r
702         struct mthca_eq_context *eq_context;\r
703         int err = -ENOMEM;\r
704         int i;\r
705         u8 status;\r
706         \r
707         HCA_ENTER(HCA_DBG_INIT);\r
708         eq->dev  = dev; \r
709         eq->nent = roundup_pow_of_two(max(nent, 2));\r
710         npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;\r
711 \r
712         eq->page_list = kmalloc(npages * sizeof *eq->page_list,\r
713                                 GFP_KERNEL);\r
714         if (!eq->page_list)\r
715                 goto err_out;\r
716 \r
717         for (i = 0; i < npages; ++i)\r
718                 eq->page_list[i].page = NULL;\r
719 \r
720         dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);\r
721         if (!dma_list)\r
722                 goto err_out_free;\r
723 \r
724         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);\r
725         if (IS_ERR(mailbox))\r
726                 goto err_out_free;\r
727         eq_context = mailbox->buf;\r
728 \r
729         for (i = 0; i < npages; ++i) {\r
730                 alloc_dma_zmem_map(dev, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &eq->page_list[i]);\r
731                 if (!eq->page_list[i].page)\r
732                         goto err_out_free_pages;\r
733                 dma_list[i] = eq->page_list[i].dma_address;\r
734         }\r
735 \r
736         for (i = 0; i < eq->nent; ++i)\r
737                 set_eqe_hw(get_eqe(eq, i));\r
738 \r
739         eq->eqn = mthca_alloc(&dev->eq_table.alloc);\r
740         if (eq->eqn == -1)\r
741                 goto err_out_free_pages;\r
742 \r
743         err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,\r
744                                   dma_list, PAGE_SHIFT, npages,\r
745                                   0, npages * PAGE_SIZE,\r
746                                   MTHCA_MPT_FLAG_LOCAL_WRITE |\r
747                                   MTHCA_MPT_FLAG_LOCAL_READ,\r
748                                   &eq->mr);\r
749         if (err)\r
750                 goto err_out_free_eq;\r
751 \r
752         RtlZeroMemory(eq_context, sizeof *eq_context);\r
753         eq_context->flags           = cl_hton32(MTHCA_EQ_STATUS_OK   |\r
754                                                   MTHCA_EQ_OWNER_HW    |\r
755                                                   MTHCA_EQ_STATE_ARMED |\r
756                                                   MTHCA_EQ_FLAG_TR);\r
757         if (mthca_is_memfree(dev))\r
758                 eq_context->flags  |= cl_hton32(MTHCA_EQ_STATE_ARBEL);\r
759 \r
760         eq_context->logsize_usrpage = cl_hton32((ffs(eq->nent) - 1) << 24);\r
761         if (mthca_is_memfree(dev)) {\r
762                 eq_context->arbel_pd = cl_hton32(dev->driver_pd.pd_num);\r
763         } else {\r
764                 eq_context->logsize_usrpage |= cl_hton32(dev->driver_uar.index);\r
765                 eq_context->tavor_pd         = cl_hton32(dev->driver_pd.pd_num);\r
766         }\r
767         eq_context->intr            = intr;\r
768         eq_context->lkey            = cl_hton32(eq->mr.ibmr.lkey);\r
769 \r
770         err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);\r
771         if (err) {\r
772                 HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("SW2HW_EQ failed (%d)\n", err));\r
773                 goto err_out_free_mr;\r
774         }\r
775         if (status) {\r
776                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("SW2HW_EQ returned status 0x%02x\n",\r
777                            status));\r
778                 err = -EINVAL;\r
779                 goto err_out_free_mr;\r
780         }\r
781 \r
782         kfree(dma_list);\r
783         mthca_free_mailbox(dev, mailbox);\r
784 \r
785         eq->eqn_mask   = _byteswap_ulong(1 << eq->eqn);\r
786         eq->cons_index = 0;\r
787 \r
788         dev->eq_table.arm_mask |= eq->eqn_mask;\r
789 \r
790         HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_INIT ,("Allocated EQ %d with %d entries\n",\r
791                   eq->eqn, eq->nent));\r
792 \r
793         HCA_EXIT(HCA_DBG_INIT);\r
794         return err;\r
795 \r
796  err_out_free_mr:\r
797         mthca_free_mr(dev, &eq->mr);\r
798 \r
799  err_out_free_eq:\r
800         mthca_free(&dev->eq_table.alloc, eq->eqn);\r
801 \r
802  err_out_free_pages:\r
803         for (i = 0; i < npages; ++i) {\r
804                 if (eq->page_list[i].page) {\r
805                         free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL);\r
806                 }\r
807         }\r
808         mthca_free_mailbox(dev, mailbox);\r
809 \r
810  err_out_free:\r
811         kfree(eq->page_list);\r
812         kfree(dma_list);\r
813 \r
814  err_out:\r
815         HCA_EXIT(HCA_DBG_INIT);\r
816         return err;\r
817 }\r
818 \r
819 static void mthca_free_eq(struct mthca_dev *dev,\r
820                           struct mthca_eq *eq)\r
821 {\r
822         struct mthca_mailbox *mailbox;\r
823         int err;\r
824         u8 status;\r
825         int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /\r
826                 PAGE_SIZE;\r
827         int i;\r
828 \r
829         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);\r
830         if (IS_ERR(mailbox))\r
831                 return;\r
832 \r
833         err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);\r
834         if (err)\r
835                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_LOW  ,("HW2SW_EQ failed (%d)\n", err));\r
836         if (status)\r
837                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_LOW  ,("HW2SW_EQ returned status 0x%02x\n", status));\r
838 \r
839         dev->eq_table.arm_mask &= ~eq->eqn_mask;\r
840 \r
841         { // debug print\r
842                 HCA_PRINT(TRACE_LEVEL_VERBOSE  ,HCA_DBG_LOW  ,("Dumping EQ context %02x:\n", eq->eqn));\r
843                 for (i = 0; i < sizeof (struct mthca_eq_context) / 4; i=i+4) {\r
844                         HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("[%02x] %08x %08x %08x %08x\n", i,\r
845                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + i * 4)),\r
846                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4)),\r
847                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+2)*4)),\r
848                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4))));\r
849                                         \r
850                 }\r
851         }\r
852 \r
853         mthca_free_mr(dev, &eq->mr);\r
854         for (i = 0; i < npages; ++i) {\r
855                 free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL);\r
856         }\r
857 \r
858         kfree(eq->page_list);\r
859         mthca_free_mailbox(dev, mailbox);\r
860 }\r
861 \r
862 static void mthca_free_irqs(struct mthca_dev *dev)\r
863 {\r
864         if (dev->eq_table.have_irq)\r
865                 free_irq(dev->ext->int_obj);\r
866 #ifdef MSI_SUPPORT      \r
867         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
868                 if (dev->eq_table.eq[i].have_irq)\r
869                         free_irq(dev->eq_table.eq[i].msi_x_vector,\r
870                                  dev->eq_table.eq + i);\r
871 #endif          \r
872 }\r
873 \r
874 static int mthca_map_reg(struct mthca_dev *dev,\r
875                                    u64 offset, unsigned long size,\r
876                                    void __iomem **map, SIZE_T *map_size)\r
877 {\r
878         u64 base = pci_resource_start(dev, HCA_BAR_TYPE_HCR);\r
879         *map = ioremap(base + offset, size, map_size);\r
880         if (!*map) \r
881                 return -ENOMEM;\r
882         return 0;\r
883 }\r
884 \r
885 static void mthca_unmap_reg(struct mthca_dev *dev, u64 offset,\r
886                             unsigned long size, void __iomem *map, SIZE_T map_size)\r
887 {\r
888         UNREFERENCED_PARAMETER(dev);\r
889         UNREFERENCED_PARAMETER(size);\r
890         UNREFERENCED_PARAMETER(offset);\r
891         iounmap(map, map_size);\r
892 }\r
893 \r
894 static int mthca_map_eq_regs(struct mthca_dev *dev)\r
895 {\r
896         u64 mthca_base;\r
897 \r
898         mthca_base = pci_resource_start(dev, HCA_BAR_TYPE_HCR);\r
899 \r
900         if (mthca_is_memfree(dev)) {\r
901                 /*\r
902                  * We assume that the EQ arm and EQ set CI registers\r
903                  * fall within the first BAR.  We can't trust the\r
904                  * values firmware gives us, since those addresses are\r
905                  * valid on the HCA's side of the PCI bus but not\r
906                  * necessarily the host side.\r
907                  */\r
908                 if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
909                                   dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
910                                   &dev->clr_base, &dev->clr_base_size)) {\r
911                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, "\r
912                                   "aborting.\n"));\r
913                         return -ENOMEM;\r
914                 }\r
915 \r
916                 /*\r
917                  * Add 4 because we limit ourselves to EQs 0 ... 31,\r
918                  * so we only need the low word of the register.\r
919                  */\r
920                 if (mthca_map_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
921                                         dev->fw.arbel.eq_arm_base) + 4, 4,\r
922                                   &dev->eq_regs.arbel.eq_arm, &dev->eq_regs.arbel.eq_arm_size)) {\r
923                         HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Couldn't map EQ arm register, aborting.\n"));\r
924                         mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
925                                         dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
926                                         dev->clr_base, dev->clr_base_size);\r
927                         return -ENOMEM;\r
928                 }\r
929 \r
930                 if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
931                                   dev->fw.arbel.eq_set_ci_base,\r
932                                   MTHCA_EQ_SET_CI_SIZE,\r
933                                   &dev->eq_regs.arbel.eq_set_ci_base,\r
934                                   &dev->eq_regs.arbel.eq_set_ci_base_size\r
935                                   )) {\r
936                         HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Couldn't map EQ CI register, aborting.\n"));\r
937                         mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
938                                               dev->fw.arbel.eq_arm_base) + 4, 4,\r
939                                         dev->eq_regs.arbel.eq_arm, dev->eq_regs.arbel.eq_arm_size);\r
940                         mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
941                                         dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
942                                         dev->clr_base, dev->clr_base_size);\r
943                         return -ENOMEM;\r
944                 }\r
945         } else {\r
946                 if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
947                                   &dev->clr_base, &dev->clr_base_size)) {\r
948                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, "\r
949                                   "aborting.\n"));\r
950                         return -ENOMEM;\r
951                 }\r
952 \r
953                 if (mthca_map_reg(dev, MTHCA_ECR_BASE,\r
954                                   MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,\r
955                                   &dev->eq_regs.tavor.ecr_base,  &dev->eq_regs.tavor.ecr_base_size)) {\r
956                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map ecr register, "\r
957                                   "aborting.\n"));\r
958                         mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
959                                         dev->clr_base, dev->clr_base_size);\r
960                         return -ENOMEM;\r
961                 }\r
962         }\r
963 \r
964         return 0;\r
965 \r
966 }\r
967 \r
968 static void mthca_unmap_eq_regs(struct mthca_dev *dev)\r
969 {\r
970         if (mthca_is_memfree(dev)) {\r
971                 mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
972                                 dev->fw.arbel.eq_set_ci_base,\r
973                                 MTHCA_EQ_SET_CI_SIZE,\r
974                                 dev->eq_regs.arbel.eq_set_ci_base, \r
975                                 dev->eq_regs.arbel.eq_set_ci_base_size);\r
976                 mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
977                                 dev->fw.arbel.eq_arm_base) + 4, 4,\r
978                         dev->eq_regs.arbel.eq_arm,\r
979                         dev->eq_regs.arbel.eq_arm_size);\r
980                 mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
981                                 dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
982                                 dev->clr_base, dev->clr_base_size);\r
983         } else {\r
984                 mthca_unmap_reg(dev, MTHCA_ECR_BASE,\r
985                                 MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,\r
986                                 dev->eq_regs.tavor.ecr_base, \r
987                                 dev->eq_regs.tavor.ecr_base_size);\r
988                 mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
989                                 dev->clr_base, dev->clr_base_size);\r
990         }\r
991 }\r
992 \r
993 int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)\r
994 {\r
995         int ret;\r
996         u8 status;\r
997 \r
998         /*\r
999          * We assume that mapping one page is enough for the whole EQ\r
1000          * context table.  This is fine with all current HCAs, because\r
1001          * we only use 32 EQs and each EQ uses 32 bytes of context\r
1002          * memory, or 1 KB total.\r
1003          */\r
1004         dev->eq_table.icm_virt = icm_virt;\r
1005         alloc_dma_zmem_map(dev,PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &dev->eq_table.sg);\r
1006         if (!dev->eq_table.sg.page)\r
1007                 return -ENOMEM;\r
1008 \r
1009         ret = mthca_MAP_ICM_page(dev, dev->eq_table.sg.dma_address, icm_virt, &status);\r
1010         if (!ret && status)\r
1011                 ret = -EINVAL;\r
1012         if (ret) \r
1013                 free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL );\r
1014 \r
1015         return ret;\r
1016 }\r
1017 \r
1018 void mthca_unmap_eq_icm(struct mthca_dev *dev)\r
1019 {\r
1020         u8 status;\r
1021 \r
1022         mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status);\r
1023         free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL );\r
1024 }\r
1025 \r
1026 int mthca_init_eq_table(struct mthca_dev *dev)\r
1027 {\r
1028         int err;\r
1029         u8 status;\r
1030         u8 intr;\r
1031         int i;\r
1032         \r
1033         HCA_ENTER(HCA_DBG_INIT);\r
1034         err = mthca_alloc_init(&dev->eq_table.alloc,\r
1035                                dev->limits.num_eqs,\r
1036                                dev->limits.num_eqs - 1,\r
1037                                dev->limits.reserved_eqs);\r
1038         if (err)\r
1039                 return err;\r
1040 \r
1041         err = mthca_map_eq_regs(dev);\r
1042         if (err)\r
1043                 goto err_out_free;\r
1044 \r
1045 #ifdef MSI_SUPPORT\r
1046         if (dev->mthca_flags & MTHCA_FLAG_MSI ||\r
1047             dev->mthca_flags & MTHCA_FLAG_MSI_X) {\r
1048                 dev->eq_table.clr_mask = 0;\r
1049         } else\r
1050 #endif  \r
1051         {\r
1052                 dev->eq_table.clr_mask =\r
1053                         _byteswap_ulong(1 << (dev->eq_table.inta_pin & 31));\r
1054                 dev->eq_table.clr_int  = dev->clr_base +\r
1055                         (dev->eq_table.inta_pin < 32 ? 4 : 0);\r
1056         }\r
1057 \r
1058         dev->eq_table.arm_mask = 0;\r
1059 \r
1060         intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?\r
1061                 128 : dev->eq_table.inta_pin;\r
1062 \r
1063         err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,\r
1064                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,\r
1065                               &dev->eq_table.eq[MTHCA_EQ_COMP]);\r
1066         if (err)\r
1067                 goto err_out_unmap;\r
1068 \r
1069         err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,\r
1070                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,\r
1071                               &dev->eq_table.eq[MTHCA_EQ_ASYNC]);\r
1072         if (err)\r
1073                 goto err_out_comp;\r
1074 \r
1075         err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,\r
1076                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,\r
1077                               &dev->eq_table.eq[MTHCA_EQ_CMD]);\r
1078         if (err)\r
1079                 goto err_out_async;\r
1080 \r
1081 #ifdef MSI_SUPPORT\r
1082         if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {\r
1083                 static const char *eq_name[] = {\r
1084                         [MTHCA_EQ_COMP]  = DRV_NAME " (comp)",\r
1085                         [MTHCA_EQ_ASYNC] = DRV_NAME " (async)",\r
1086                         [MTHCA_EQ_CMD]   = DRV_NAME " (cmd)"\r
1087                 };\r
1088 \r
1089                 for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
1090                         err = request_irq(dev->eq_table.eq[i].msi_x_vector,\r
1091                                           mthca_is_memfree(dev) ?\r
1092                                           mthca_arbel_msi_x_interrupt :\r
1093                                           mthca_tavor_msi_x_interrupt,\r
1094                                           0, eq_name[i], dev->eq_table.eq + i);\r
1095                         if (err)\r
1096                                 goto err_out_cmd;\r
1097                         dev->eq_table.eq[i].have_irq = 1;\r
1098                         /* init DPC stuff something like that */\r
1099                         spin_lock_init( &dev->eq_table.eq[i].lock );    \r
1100                         dev->dpc_lock = 0;\r
1101                         KeInitializeDpc(\r
1102                                 &dev->eq_table.eq[i].dpc,\r
1103                                 mthca_is_memfree(dev) ?\r
1104                                         mthca_arbel_msi_x_dpc :\r
1105                                         mthca_tavor_msi_x_dpc,\r
1106                                 dev->eq_table.eq + i);\r
1107                 }\r
1108         } else \r
1109 #endif  \r
1110         {\r
1111                 spin_lock_init( &dev->ext->isr_lock );  \r
1112                 err = request_irq(\r
1113                         &dev->ext->interruptInfo,\r
1114                         &dev->ext->isr_lock.lock        ,\r
1115                         mthca_is_memfree(dev) ? mthca_arbel_interrupt : mthca_tavor_interrupt,\r
1116                         dev,\r
1117                         &dev->ext->int_obj\r
1118                   );\r
1119                 if (err)\r
1120                         goto err_out_cmd;\r
1121                 dev->eq_table.have_irq = 1;\r
1122 \r
1123                 /* init DPC stuff */\r
1124                 for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
1125                         spin_lock_init( &dev->eq_table.eq[i].lock );    \r
1126                         KeInitializeDpc(\r
1127                                 &dev->eq_table.eq[i].dpc,\r
1128                                 mthca_is_memfree(dev) ?\r
1129                                         mthca_arbel_dpc :\r
1130                                         mthca_tavor_dpc,\r
1131                                 dev->eq_table.eq + i);\r
1132                         dev->eq_table.eq[i].eq_num = i;\r
1133                 }\r
1134         }\r
1135 \r
1136         err = mthca_MAP_EQ(dev, async_mask(dev),\r
1137                            0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status);\r
1138         if (err)\r
1139                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for async EQ %d failed (%d)\n",\r
1140                            dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err));\r
1141         if (status)\r
1142                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for async EQ %d returned status 0x%02x\n",\r
1143                            dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, status));\r
1144         err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,\r
1145                            0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status);\r
1146         if (err)\r
1147                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for cmd EQ %d failed (%d)\n",\r
1148                            dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err));\r
1149         if (status)\r
1150                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for cmd EQ %d returned status 0x%02x\n",\r
1151                            dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status));\r
1152 \r
1153         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
1154                 if (mthca_is_memfree(dev))\r
1155                         arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);\r
1156                 else\r
1157                         tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);\r
1158 \r
1159 #if 1//WORKAROUND_POLL_EQ\r
1160         { /* Create a thread for polling EQs in case of missing interrupts from the card  */\r
1161                 NTSTATUS status;\r
1162                 OBJECT_ATTRIBUTES       attr;\r
1163                 HANDLE  handle;\r
1164 \r
1165                 KeInitializeEvent(&dev->eq_table.thread_start_event, SynchronizationEvent, FALSE);\r
1166                 KeInitializeEvent(&dev->eq_table.thread_stop_event, SynchronizationEvent, FALSE);\r
1167                 dev->eq_table.bTerminated = FALSE;\r
1168                 dev->eq_table.threadObject = NULL;\r
1169                 InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );\r
1170                 status = PsCreateSystemThread( &handle, \r
1171                         THREAD_ALL_ACCESS, &attr, NULL, NULL, eq_polling_thread, dev );\r
1172                 if (NT_SUCCESS(status)) {\r
1173                         status = ObReferenceObjectByHandle(\r
1174                                 handle,\r
1175                                 THREAD_ALL_ACCESS,\r
1176                                 NULL,\r
1177                                 KernelMode,\r
1178                                 &dev->eq_table.threadObject,\r
1179                                 NULL\r
1180                                 );\r
1181 \r
1182                         ASSERT(status == STATUS_SUCCESS); //\r
1183 \r
1184                         status = ZwClose(handle);\r
1185 \r
1186                         ASSERT(NT_SUCCESS(status)); // Should always succeed\r
1187 \r
1188                 }\r
1189         }\r
1190 #endif\r
1191 \r
1192         return 0;\r
1193 \r
1194 err_out_cmd:\r
1195         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]);\r
1196 \r
1197 err_out_async:\r
1198         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]);\r
1199 \r
1200 err_out_comp:\r
1201         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]);\r
1202 \r
1203 err_out_unmap:\r
1204         mthca_unmap_eq_regs(dev);\r
1205 \r
1206 err_out_free:\r
1207         mthca_alloc_cleanup(&dev->eq_table.alloc);\r
1208         HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("mthca_init_eq  failed %d\n",err));\r
1209         return err;\r
1210 }\r
1211 \r
1212 void mthca_cleanup_eq_table(struct mthca_dev *dev)\r
1213 {\r
1214         u8 status;\r
1215         int i;\r
1216 \r
1217 #if 1//WORKAROUND_POLL_EQ\r
1218         /* stop the EQ polling thread */\r
1219         if (dev->eq_table.threadObject) { \r
1220                 #define WAIT_TIME_MS    3000\r
1221                 NTSTATUS status;\r
1222                 LARGE_INTEGER  wait_time;\r
1223                 LONG signalled;\r
1224 \r
1225                 dev->eq_table.bTerminated = TRUE;\r
1226 \r
1227                 /* signal polling stopped in case it is not */\r
1228                 signalled = KeSetEvent(         \r
1229                         &dev->eq_table.thread_stop_event, IO_NO_INCREMENT, FALSE );\r
1230 \r
1231                 /* wait for completion of the thread */\r
1232                 wait_time.QuadPart = -(int64_t)(((uint64_t)WAIT_TIME_MS) * 10000);\r
1233                 status = KeWaitForSingleObject( dev->eq_table.threadObject,\r
1234                         Executive, KernelMode, FALSE, &wait_time );\r
1235                 ASSERT(status == STATUS_SUCCESS);\r
1236 \r
1237                 ObDereferenceObject(dev->eq_table.threadObject);\r
1238 \r
1239                 /* cleanup */\r
1240                 dev->eq_table.threadObject = NULL;\r
1241         }\r
1242 #endif\r
1243 \r
1244         mthca_free_irqs(dev);\r
1245 \r
1246         mthca_MAP_EQ(dev, async_mask(dev),\r
1247                      1, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status);\r
1248         mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,\r
1249                      1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status);\r
1250 \r
1251         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
1252                 mthca_free_eq(dev, &dev->eq_table.eq[i]);\r
1253 \r
1254         mthca_unmap_eq_regs(dev);\r
1255 \r
1256         mthca_alloc_cleanup(&dev->eq_table.alloc);\r
1257 }\r
1258 \r
1259 \r
1260 \r
1261 \r