111dea71d175572f31d8530331803876977c2808
[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 static int mthca_create_eq(struct mthca_dev *dev,\r
600                                      int nent,\r
601                                      u8 intr,\r
602                                      struct mthca_eq *eq)\r
603 {\r
604         int npages;\r
605         u64 *dma_list = NULL;\r
606         struct mthca_mailbox *mailbox;\r
607         struct mthca_eq_context *eq_context;\r
608         int err = -ENOMEM;\r
609         int i;\r
610         u8 status;\r
611         \r
612         HCA_ENTER(HCA_DBG_INIT);\r
613         eq->dev  = dev; \r
614         eq->nent = roundup_pow_of_two(max(nent, 2));\r
615         npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;\r
616 \r
617         eq->page_list = kmalloc(npages * sizeof *eq->page_list,\r
618                                 GFP_KERNEL);\r
619         if (!eq->page_list)\r
620                 goto err_out;\r
621 \r
622         for (i = 0; i < npages; ++i)\r
623                 eq->page_list[i].page = NULL;\r
624 \r
625         dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL);\r
626         if (!dma_list)\r
627                 goto err_out_free;\r
628 \r
629         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);\r
630         if (IS_ERR(mailbox))\r
631                 goto err_out_free;\r
632         eq_context = mailbox->buf;\r
633 \r
634         for (i = 0; i < npages; ++i) {\r
635                 alloc_dma_zmem_map(dev, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &eq->page_list[i]);\r
636                 if (!eq->page_list[i].page)\r
637                         goto err_out_free_pages;\r
638                 dma_list[i] = eq->page_list[i].dma_address;\r
639         }\r
640 \r
641         for (i = 0; i < eq->nent; ++i)\r
642                 set_eqe_hw(get_eqe(eq, i));\r
643 \r
644         eq->eqn = mthca_alloc(&dev->eq_table.alloc);\r
645         if (eq->eqn == -1)\r
646                 goto err_out_free_pages;\r
647 \r
648         err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,\r
649                                   dma_list, PAGE_SHIFT, npages,\r
650                                   0, npages * PAGE_SIZE,\r
651                                   MTHCA_MPT_FLAG_LOCAL_WRITE |\r
652                                   MTHCA_MPT_FLAG_LOCAL_READ,\r
653                                   &eq->mr);\r
654         if (err)\r
655                 goto err_out_free_eq;\r
656 \r
657         RtlZeroMemory(eq_context, sizeof *eq_context);\r
658         eq_context->flags           = cl_hton32(MTHCA_EQ_STATUS_OK   |\r
659                                                   MTHCA_EQ_OWNER_HW    |\r
660                                                   MTHCA_EQ_STATE_ARMED |\r
661                                                   MTHCA_EQ_FLAG_TR);\r
662         if (mthca_is_memfree(dev))\r
663                 eq_context->flags  |= cl_hton32(MTHCA_EQ_STATE_ARBEL);\r
664 \r
665         eq_context->logsize_usrpage = cl_hton32((ffs(eq->nent) - 1) << 24);\r
666         if (mthca_is_memfree(dev)) {\r
667                 eq_context->arbel_pd = cl_hton32(dev->driver_pd.pd_num);\r
668         } else {\r
669                 eq_context->logsize_usrpage |= cl_hton32(dev->driver_uar.index);\r
670                 eq_context->tavor_pd         = cl_hton32(dev->driver_pd.pd_num);\r
671         }\r
672         eq_context->intr            = intr;\r
673         eq_context->lkey            = cl_hton32(eq->mr.ibmr.lkey);\r
674 \r
675         err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);\r
676         if (err) {\r
677                 HCA_PRINT(TRACE_LEVEL_WARNING ,HCA_DBG_LOW ,("SW2HW_EQ failed (%d)\n", err));\r
678                 goto err_out_free_mr;\r
679         }\r
680         if (status) {\r
681                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_LOW,("SW2HW_EQ returned status 0x%02x\n",\r
682                            status));\r
683                 err = -EINVAL;\r
684                 goto err_out_free_mr;\r
685         }\r
686 \r
687         kfree(dma_list);\r
688         mthca_free_mailbox(dev, mailbox);\r
689 \r
690         eq->eqn_mask   = _byteswap_ulong(1 << eq->eqn);\r
691         eq->cons_index = 0;\r
692 \r
693         dev->eq_table.arm_mask |= eq->eqn_mask;\r
694 \r
695         HCA_PRINT(TRACE_LEVEL_INFORMATION ,HCA_DBG_INIT ,("Allocated EQ %d with %d entries\n",\r
696                   eq->eqn, eq->nent));\r
697 \r
698         HCA_EXIT(HCA_DBG_INIT);\r
699         return err;\r
700 \r
701  err_out_free_mr:\r
702         mthca_free_mr(dev, &eq->mr);\r
703 \r
704  err_out_free_eq:\r
705         mthca_free(&dev->eq_table.alloc, eq->eqn);\r
706 \r
707  err_out_free_pages:\r
708         for (i = 0; i < npages; ++i) {\r
709                 if (eq->page_list[i].page) {\r
710                         free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL);\r
711                 }\r
712         }\r
713         mthca_free_mailbox(dev, mailbox);\r
714 \r
715  err_out_free:\r
716         kfree(eq->page_list);\r
717         kfree(dma_list);\r
718 \r
719  err_out:\r
720         HCA_EXIT(HCA_DBG_INIT);\r
721         return err;\r
722 }\r
723 \r
724 static void mthca_free_eq(struct mthca_dev *dev,\r
725                           struct mthca_eq *eq)\r
726 {\r
727         struct mthca_mailbox *mailbox;\r
728         int err;\r
729         u8 status;\r
730         int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /\r
731                 PAGE_SIZE;\r
732         int i;\r
733 \r
734         mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);\r
735         if (IS_ERR(mailbox))\r
736                 return;\r
737 \r
738         err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);\r
739         if (err)\r
740                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_LOW  ,("HW2SW_EQ failed (%d)\n", err));\r
741         if (status)\r
742                 HCA_PRINT(TRACE_LEVEL_WARNING  ,HCA_DBG_LOW  ,("HW2SW_EQ returned status 0x%02x\n", status));\r
743 \r
744         dev->eq_table.arm_mask &= ~eq->eqn_mask;\r
745 \r
746         { // debug print\r
747                 HCA_PRINT(TRACE_LEVEL_VERBOSE  ,HCA_DBG_LOW  ,("Dumping EQ context %02x:\n", eq->eqn));\r
748                 for (i = 0; i < sizeof (struct mthca_eq_context) / 4; i=i+4) {\r
749                         HCA_PRINT(TRACE_LEVEL_VERBOSE ,HCA_DBG_LOW ,("[%02x] %08x %08x %08x %08x\n", i,\r
750                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + i * 4)),\r
751                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4)),\r
752                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+2)*4)),\r
753                                         cl_ntoh32(*(u32*)((u8*)mailbox->buf + (i+1)*4))));\r
754                                         \r
755                 }\r
756         }\r
757 \r
758         mthca_free_mr(dev, &eq->mr);\r
759         for (i = 0; i < npages; ++i) {\r
760                 free_dma_mem_map(dev, &eq->page_list[i], PCI_DMA_BIDIRECTIONAL);\r
761         }\r
762 \r
763         kfree(eq->page_list);\r
764         mthca_free_mailbox(dev, mailbox);\r
765 }\r
766 \r
767 static void mthca_free_irqs(struct mthca_dev *dev)\r
768 {\r
769         if (dev->eq_table.have_irq)\r
770                 free_irq(dev->ext->int_obj);\r
771 #ifdef MSI_SUPPORT      \r
772         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
773                 if (dev->eq_table.eq[i].have_irq)\r
774                         free_irq(dev->eq_table.eq[i].msi_x_vector,\r
775                                  dev->eq_table.eq + i);\r
776 #endif          \r
777 }\r
778 \r
779 static int mthca_map_reg(struct mthca_dev *dev,\r
780                                    u64 offset, unsigned long size,\r
781                                    void __iomem **map, SIZE_T *map_size)\r
782 {\r
783         u64 base = pci_resource_start(dev, HCA_BAR_TYPE_HCR);\r
784         *map = ioremap(base + offset, size, map_size);\r
785         if (!*map) \r
786                 return -ENOMEM;\r
787         return 0;\r
788 }\r
789 \r
790 static void mthca_unmap_reg(struct mthca_dev *dev, u64 offset,\r
791                             unsigned long size, void __iomem *map, SIZE_T map_size)\r
792 {\r
793         UNREFERENCED_PARAMETER(dev);\r
794         UNREFERENCED_PARAMETER(size);\r
795         UNREFERENCED_PARAMETER(offset);\r
796         iounmap(map, map_size);\r
797 }\r
798 \r
799 static int mthca_map_eq_regs(struct mthca_dev *dev)\r
800 {\r
801         u64 mthca_base;\r
802 \r
803         mthca_base = pci_resource_start(dev, HCA_BAR_TYPE_HCR);\r
804 \r
805         if (mthca_is_memfree(dev)) {\r
806                 /*\r
807                  * We assume that the EQ arm and EQ set CI registers\r
808                  * fall within the first BAR.  We can't trust the\r
809                  * values firmware gives us, since those addresses are\r
810                  * valid on the HCA's side of the PCI bus but not\r
811                  * necessarily the host side.\r
812                  */\r
813                 if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
814                                   dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
815                                   &dev->clr_base, &dev->clr_base_size)) {\r
816                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, "\r
817                                   "aborting.\n"));\r
818                         return -ENOMEM;\r
819                 }\r
820 \r
821                 /*\r
822                  * Add 4 because we limit ourselves to EQs 0 ... 31,\r
823                  * so we only need the low word of the register.\r
824                  */\r
825                 if (mthca_map_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
826                                         dev->fw.arbel.eq_arm_base) + 4, 4,\r
827                                   &dev->eq_regs.arbel.eq_arm, &dev->eq_regs.arbel.eq_arm_size)) {\r
828                         HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Couldn't map EQ arm register, aborting.\n"));\r
829                         mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
830                                         dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
831                                         dev->clr_base, dev->clr_base_size);\r
832                         return -ENOMEM;\r
833                 }\r
834 \r
835                 if (mthca_map_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
836                                   dev->fw.arbel.eq_set_ci_base,\r
837                                   MTHCA_EQ_SET_CI_SIZE,\r
838                                   &dev->eq_regs.arbel.eq_set_ci_base,\r
839                                   &dev->eq_regs.arbel.eq_set_ci_base_size\r
840                                   )) {\r
841                         HCA_PRINT(TRACE_LEVEL_ERROR  ,HCA_DBG_LOW  ,("Couldn't map EQ CI register, aborting.\n"));\r
842                         mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
843                                               dev->fw.arbel.eq_arm_base) + 4, 4,\r
844                                         dev->eq_regs.arbel.eq_arm, dev->eq_regs.arbel.eq_arm_size);\r
845                         mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
846                                         dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
847                                         dev->clr_base, dev->clr_base_size);\r
848                         return -ENOMEM;\r
849                 }\r
850         } else {\r
851                 if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
852                                   &dev->clr_base, &dev->clr_base_size)) {\r
853                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map interrupt clear register, "\r
854                                   "aborting.\n"));\r
855                         return -ENOMEM;\r
856                 }\r
857 \r
858                 if (mthca_map_reg(dev, MTHCA_ECR_BASE,\r
859                                   MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,\r
860                                   &dev->eq_regs.tavor.ecr_base,  &dev->eq_regs.tavor.ecr_base_size)) {\r
861                         HCA_PRINT(TRACE_LEVEL_ERROR,HCA_DBG_LOW,("Couldn't map ecr register, "\r
862                                   "aborting.\n"));\r
863                         mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
864                                         dev->clr_base, dev->clr_base_size);\r
865                         return -ENOMEM;\r
866                 }\r
867         }\r
868 \r
869         return 0;\r
870 \r
871 }\r
872 \r
873 static void mthca_unmap_eq_regs(struct mthca_dev *dev)\r
874 {\r
875         if (mthca_is_memfree(dev)) {\r
876                 mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
877                                 dev->fw.arbel.eq_set_ci_base,\r
878                                 MTHCA_EQ_SET_CI_SIZE,\r
879                                 dev->eq_regs.arbel.eq_set_ci_base, \r
880                                 dev->eq_regs.arbel.eq_set_ci_base_size);\r
881                 mthca_unmap_reg(dev, ((pci_resource_len(dev, 0) - 1) &\r
882                                 dev->fw.arbel.eq_arm_base) + 4, 4,\r
883                         dev->eq_regs.arbel.eq_arm,\r
884                         dev->eq_regs.arbel.eq_arm_size);\r
885                 mthca_unmap_reg(dev, (pci_resource_len(dev, 0) - 1) &\r
886                                 dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,\r
887                                 dev->clr_base, dev->clr_base_size);\r
888         } else {\r
889                 mthca_unmap_reg(dev, MTHCA_ECR_BASE,\r
890                                 MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,\r
891                                 dev->eq_regs.tavor.ecr_base, \r
892                                 dev->eq_regs.tavor.ecr_base_size);\r
893                 mthca_unmap_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,\r
894                                 dev->clr_base, dev->clr_base_size);\r
895         }\r
896 }\r
897 \r
898 int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)\r
899 {\r
900         int ret;\r
901         u8 status;\r
902 \r
903         /*\r
904          * We assume that mapping one page is enough for the whole EQ\r
905          * context table.  This is fine with all current HCAs, because\r
906          * we only use 32 EQs and each EQ uses 32 bytes of context\r
907          * memory, or 1 KB total.\r
908          */\r
909         dev->eq_table.icm_virt = icm_virt;\r
910         alloc_dma_zmem_map(dev,PAGE_SIZE, PCI_DMA_BIDIRECTIONAL, &dev->eq_table.sg);\r
911         if (!dev->eq_table.sg.page)\r
912                 return -ENOMEM;\r
913 \r
914         ret = mthca_MAP_ICM_page(dev, dev->eq_table.sg.dma_address, icm_virt, &status);\r
915         if (!ret && status)\r
916                 ret = -EINVAL;\r
917         if (ret) \r
918                 free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL );\r
919 \r
920         return ret;\r
921 }\r
922 \r
923 void mthca_unmap_eq_icm(struct mthca_dev *dev)\r
924 {\r
925         u8 status;\r
926 \r
927         mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, PAGE_SIZE / 4096, &status);\r
928         free_dma_mem_map(dev, &dev->eq_table.sg, PCI_DMA_BIDIRECTIONAL );\r
929 }\r
930 \r
931 int mthca_init_eq_table(struct mthca_dev *dev)\r
932 {\r
933         int err;\r
934         u8 status;\r
935         u8 intr;\r
936         int i;\r
937         \r
938         HCA_ENTER(HCA_DBG_INIT);\r
939         err = mthca_alloc_init(&dev->eq_table.alloc,\r
940                                dev->limits.num_eqs,\r
941                                dev->limits.num_eqs - 1,\r
942                                dev->limits.reserved_eqs);\r
943         if (err)\r
944                 return err;\r
945 \r
946         err = mthca_map_eq_regs(dev);\r
947         if (err)\r
948                 goto err_out_free;\r
949 \r
950 #ifdef MSI_SUPPORT\r
951         if (dev->mthca_flags & MTHCA_FLAG_MSI ||\r
952             dev->mthca_flags & MTHCA_FLAG_MSI_X) {\r
953                 dev->eq_table.clr_mask = 0;\r
954         } else\r
955 #endif  \r
956         {\r
957                 dev->eq_table.clr_mask =\r
958                         _byteswap_ulong(1 << (dev->eq_table.inta_pin & 31));\r
959                 dev->eq_table.clr_int  = dev->clr_base +\r
960                         (dev->eq_table.inta_pin < 32 ? 4 : 0);\r
961         }\r
962 \r
963         dev->eq_table.arm_mask = 0;\r
964 \r
965         intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?\r
966                 128 : dev->eq_table.inta_pin;\r
967 \r
968         err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,\r
969                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,\r
970                               &dev->eq_table.eq[MTHCA_EQ_COMP]);\r
971         if (err)\r
972                 goto err_out_unmap;\r
973 \r
974         err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,\r
975                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,\r
976                               &dev->eq_table.eq[MTHCA_EQ_ASYNC]);\r
977         if (err)\r
978                 goto err_out_comp;\r
979 \r
980         err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,\r
981                               (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,\r
982                               &dev->eq_table.eq[MTHCA_EQ_CMD]);\r
983         if (err)\r
984                 goto err_out_async;\r
985 \r
986 #ifdef MSI_SUPPORT\r
987         if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {\r
988                 static const char *eq_name[] = {\r
989                         [MTHCA_EQ_COMP]  = DRV_NAME " (comp)",\r
990                         [MTHCA_EQ_ASYNC] = DRV_NAME " (async)",\r
991                         [MTHCA_EQ_CMD]   = DRV_NAME " (cmd)"\r
992                 };\r
993 \r
994                 for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
995                         err = request_irq(dev->eq_table.eq[i].msi_x_vector,\r
996                                           mthca_is_memfree(dev) ?\r
997                                           mthca_arbel_msi_x_interrupt :\r
998                                           mthca_tavor_msi_x_interrupt,\r
999                                           0, eq_name[i], dev->eq_table.eq + i);\r
1000                         if (err)\r
1001                                 goto err_out_cmd;\r
1002                         dev->eq_table.eq[i].have_irq = 1;\r
1003                         /* init DPC stuff something like that */\r
1004                         spin_lock_init( &dev->eq_table.eq[i].lock );    \r
1005                         dev->dpc_lock = 0;\r
1006                         KeInitializeDpc(\r
1007                                 &dev->eq_table.eq[i].dpc,\r
1008                                 mthca_is_memfree(dev) ?\r
1009                                         mthca_arbel_msi_x_dpc :\r
1010                                         mthca_tavor_msi_x_dpc,\r
1011                                 dev->eq_table.eq + i);\r
1012                 }\r
1013         } else \r
1014 #endif  \r
1015         {\r
1016                 spin_lock_init( &dev->ext->isr_lock );  \r
1017                 err = request_irq(\r
1018                         &dev->ext->interruptInfo,\r
1019                         &dev->ext->isr_lock.lock        ,\r
1020                         mthca_is_memfree(dev) ? mthca_arbel_interrupt : mthca_tavor_interrupt,\r
1021                         dev,\r
1022                         &dev->ext->int_obj\r
1023                   );\r
1024                 if (err)\r
1025                         goto err_out_cmd;\r
1026                 dev->eq_table.have_irq = 1;\r
1027 \r
1028                 /* init DPC stuff */\r
1029                 for (i = 0; i < MTHCA_NUM_EQ; ++i) {\r
1030                         spin_lock_init( &dev->eq_table.eq[i].lock );    \r
1031                         KeInitializeDpc(\r
1032                                 &dev->eq_table.eq[i].dpc,\r
1033                                 mthca_is_memfree(dev) ?\r
1034                                         mthca_arbel_dpc :\r
1035                                         mthca_tavor_dpc,\r
1036                                 dev->eq_table.eq + i);\r
1037                         dev->eq_table.eq[i].eq_num = i;\r
1038                 }\r
1039         }\r
1040 \r
1041         err = mthca_MAP_EQ(dev, async_mask(dev),\r
1042                            0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status);\r
1043         if (err)\r
1044                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for async EQ %d failed (%d)\n",\r
1045                            dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err));\r
1046         if (status)\r
1047                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for async EQ %d returned status 0x%02x\n",\r
1048                            dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, status));\r
1049         err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,\r
1050                            0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status);\r
1051         if (err)\r
1052                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT, ("MAP_EQ for cmd EQ %d failed (%d)\n",\r
1053                            dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err));\r
1054         if (status)\r
1055                 HCA_PRINT(TRACE_LEVEL_WARNING,HCA_DBG_INIT,("MAP_EQ for cmd EQ %d returned status 0x%02x\n",\r
1056                            dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status));\r
1057 \r
1058         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
1059                 if (mthca_is_memfree(dev))\r
1060                         arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);\r
1061                 else\r
1062                         tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);\r
1063 \r
1064         return 0;\r
1065 \r
1066 err_out_cmd:\r
1067         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]);\r
1068 \r
1069 err_out_async:\r
1070         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]);\r
1071 \r
1072 err_out_comp:\r
1073         mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]);\r
1074 \r
1075 err_out_unmap:\r
1076         mthca_unmap_eq_regs(dev);\r
1077 \r
1078 err_out_free:\r
1079         mthca_alloc_cleanup(&dev->eq_table.alloc);\r
1080         HCA_PRINT(TRACE_LEVEL_ERROR ,HCA_DBG_INIT ,("mthca_init_eq  failed %d\n",err));\r
1081         return err;\r
1082 }\r
1083 \r
1084 void mthca_cleanup_eq_table(struct mthca_dev *dev)\r
1085 {\r
1086         u8 status;\r
1087         int i;\r
1088 \r
1089         mthca_free_irqs(dev);\r
1090 \r
1091         mthca_MAP_EQ(dev, async_mask(dev),\r
1092                      1, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status);\r
1093         mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,\r
1094                      1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status);\r
1095 \r
1096         for (i = 0; i < MTHCA_NUM_EQ; ++i)\r
1097                 mthca_free_eq(dev, &dev->eq_table.eq[i]);\r
1098 \r
1099         mthca_unmap_eq_regs(dev);\r
1100 \r
1101         mthca_alloc_cleanup(&dev->eq_table.alloc);\r
1102 }\r
1103 \r
1104 \r
1105 \r
1106 \r