blob: 3f617b27b9543658d901dd1de36caca52371f9e5 [file] [log] [blame]
Heiko J Schickfab97222006-09-22 15:22:22 -07001/*
2 * IBM eServer eHCA Infiniband device driver for Linux on POWER
3 *
4 * Functions for EQs, NEQs and interrupts
5 *
6 * Authors: Heiko J Schick <schickhj@de.ibm.com>
7 * Khadija Souissi <souissi@de.ibm.com>
Joachim Fenkes28db6be2007-07-09 15:30:39 +02008 * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
9 * Joachim Fenkes <fenkes@de.ibm.com>
Heiko J Schickfab97222006-09-22 15:22:22 -070010 *
11 * Copyright (c) 2005 IBM Corporation
12 *
13 * All rights reserved.
14 *
15 * This source code is distributed under a dual license of GPL v2.0 and OpenIB
16 * BSD.
17 *
18 * OpenIB BSD License
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are met:
22 *
23 * Redistributions of source code must retain the above copyright notice, this
24 * list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright notice,
27 * this list of conditions and the following disclaimer in the documentation
28 * and/or other materials
29 * provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
35 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
39 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44#include "ehca_classes.h"
45#include "ehca_irq.h"
46#include "ehca_iverbs.h"
47#include "ehca_tools.h"
48#include "hcp_if.h"
49#include "hipz_fns.h"
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +010050#include "ipz_pt_fn.h"
Heiko J Schickfab97222006-09-22 15:22:22 -070051
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020052#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
53#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
54#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM( 2, 7)
55#define EQE_CQ_NUMBER EHCA_BMASK_IBM( 8, 31)
56#define EQE_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
57#define EQE_QP_TOKEN EHCA_BMASK_IBM(32, 63)
58#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32, 63)
Heiko J Schickfab97222006-09-22 15:22:22 -070059
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020060#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
61#define NEQE_EVENT_CODE EHCA_BMASK_IBM( 2, 7)
62#define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15)
63#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
64#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16)
Heiko J Schickfab97222006-09-22 15:22:22 -070065
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020066#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63)
67#define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7)
Heiko J Schickfab97222006-09-22 15:22:22 -070068
Heiko J Schickfab97222006-09-22 15:22:22 -070069static void queue_comp_task(struct ehca_cq *__cq);
70
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020071static struct ehca_comp_pool *pool;
Heiko J Schickfab97222006-09-22 15:22:22 -070072
Heiko J Schickfab97222006-09-22 15:22:22 -070073static inline void comp_event_callback(struct ehca_cq *cq)
74{
75 if (!cq->ib_cq.comp_handler)
76 return;
77
78 spin_lock(&cq->cb_lock);
79 cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context);
80 spin_unlock(&cq->cb_lock);
81
82 return;
83}
84
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020085static void print_error_data(struct ehca_shca *shca, void *data,
86 u64 *rblock, int length)
Heiko J Schickfab97222006-09-22 15:22:22 -070087{
88 u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
89 u64 resource = rblock[1];
90
91 switch (type) {
92 case 0x1: /* Queue Pair */
93 {
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +020094 struct ehca_qp *qp = (struct ehca_qp *)data;
Heiko J Schickfab97222006-09-22 15:22:22 -070095
96 /* only print error data if AER is set */
97 if (rblock[6] == 0)
98 return;
99
100 ehca_err(&shca->ib_device,
101 "QP 0x%x (resource=%lx) has errors.",
102 qp->ib_qp.qp_num, resource);
103 break;
104 }
105 case 0x4: /* Completion Queue */
106 {
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200107 struct ehca_cq *cq = (struct ehca_cq *)data;
Heiko J Schickfab97222006-09-22 15:22:22 -0700108
109 ehca_err(&shca->ib_device,
110 "CQ 0x%x (resource=%lx) has errors.",
111 cq->cq_number, resource);
112 break;
113 }
114 default:
115 ehca_err(&shca->ib_device,
Eddy L O Jansson0e6ff152007-07-31 00:38:53 -0700116 "Unknown error type: %lx on %s.",
Heiko J Schickfab97222006-09-22 15:22:22 -0700117 type, shca->ib_device.name);
118 break;
119 }
120
121 ehca_err(&shca->ib_device, "Error data is available: %lx.", resource);
122 ehca_err(&shca->ib_device, "EHCA ----- error data begin "
123 "---------------------------------------------------");
124 ehca_dmp(rblock, length, "resource=%lx", resource);
125 ehca_err(&shca->ib_device, "EHCA ----- error data end "
126 "----------------------------------------------------");
127
128 return;
129}
130
131int ehca_error_data(struct ehca_shca *shca, void *data,
132 u64 resource)
133{
134
135 unsigned long ret;
136 u64 *rblock;
137 unsigned long block_count;
138
Hoang-Nam Nguyenf2d91362007-01-09 18:04:14 +0100139 rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
Heiko J Schickfab97222006-09-22 15:22:22 -0700140 if (!rblock) {
141 ehca_err(&shca->ib_device, "Cannot allocate rblock memory.");
142 ret = -ENOMEM;
143 goto error_data1;
144 }
145
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +0100146 /* rblock must be 4K aligned and should be 4K large */
Heiko J Schickfab97222006-09-22 15:22:22 -0700147 ret = hipz_h_error_data(shca->ipz_hca_handle,
148 resource,
149 rblock,
150 &block_count);
151
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +0100152 if (ret == H_R_STATE)
Heiko J Schickfab97222006-09-22 15:22:22 -0700153 ehca_err(&shca->ib_device,
154 "No error data is available: %lx.", resource);
Heiko J Schickfab97222006-09-22 15:22:22 -0700155 else if (ret == H_SUCCESS) {
156 int length;
157
158 length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]);
159
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +0100160 if (length > EHCA_PAGESIZE)
161 length = EHCA_PAGESIZE;
Heiko J Schickfab97222006-09-22 15:22:22 -0700162
163 print_error_data(shca, data, rblock, length);
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +0100164 } else
Heiko J Schickfab97222006-09-22 15:22:22 -0700165 ehca_err(&shca->ib_device,
166 "Error data could not be fetched: %lx", resource);
Heiko J Schickfab97222006-09-22 15:22:22 -0700167
Hoang-Nam Nguyen7e28db52006-11-07 00:56:39 +0100168 ehca_free_fw_ctrlblock(rblock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700169
170error_data1:
171 return ret;
172
173}
174
Joachim Fenkes5ff70cac2007-08-31 16:03:37 +0200175static void dispatch_qp_event(struct ehca_shca *shca, struct ehca_qp *qp,
176 enum ib_event_type event_type)
177{
178 struct ib_event event;
179
180 event.device = &shca->ib_device;
181 event.event = event_type;
182
183 if (qp->ext_type == EQPT_SRQ) {
184 if (!qp->ib_srq.event_handler)
185 return;
186
187 event.element.srq = &qp->ib_srq;
188 qp->ib_srq.event_handler(&event, qp->ib_srq.srq_context);
189 } else {
190 if (!qp->ib_qp.event_handler)
191 return;
192
193 event.element.qp = &qp->ib_qp;
194 qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
195 }
196}
197
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200198static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
199 enum ib_event_type event_type, int fatal)
Heiko J Schickfab97222006-09-22 15:22:22 -0700200{
Heiko J Schickfab97222006-09-22 15:22:22 -0700201 struct ehca_qp *qp;
Heiko J Schickfab97222006-09-22 15:22:22 -0700202 u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
203
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200204 read_lock(&ehca_qp_idr_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700205 qp = idr_find(&ehca_qp_idr, token);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200206 read_unlock(&ehca_qp_idr_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700207
Heiko J Schickfab97222006-09-22 15:22:22 -0700208 if (!qp)
209 return;
210
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200211 if (fatal)
212 ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
Heiko J Schickfab97222006-09-22 15:22:22 -0700213
Joachim Fenkes5ff70cac2007-08-31 16:03:37 +0200214 dispatch_qp_event(shca, qp, fatal && qp->ext_type == EQPT_SRQ ?
215 IB_EVENT_SRQ_ERR : event_type);
Heiko J Schickfab97222006-09-22 15:22:22 -0700216
Joachim Fenkes5ff70cac2007-08-31 16:03:37 +0200217 /*
218 * eHCA only processes one WQE at a time for SRQ base QPs,
219 * so the last WQE has been processed as soon as the QP enters
220 * error state.
221 */
222 if (fatal && qp->ext_type == EQPT_SRQBASE)
223 dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
Heiko J Schickfab97222006-09-22 15:22:22 -0700224
225 return;
226}
227
228static void cq_event_callback(struct ehca_shca *shca,
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100229 u64 eqe)
Heiko J Schickfab97222006-09-22 15:22:22 -0700230{
231 struct ehca_cq *cq;
Heiko J Schickfab97222006-09-22 15:22:22 -0700232 u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
233
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200234 read_lock(&ehca_cq_idr_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700235 cq = idr_find(&ehca_cq_idr, token);
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200236 if (cq)
237 atomic_inc(&cq->nr_events);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200238 read_unlock(&ehca_cq_idr_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700239
240 if (!cq)
241 return;
242
243 ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
244
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200245 if (atomic_dec_and_test(&cq->nr_events))
246 wake_up(&cq->wait_completion);
247
Heiko J Schickfab97222006-09-22 15:22:22 -0700248 return;
249}
250
251static void parse_identifier(struct ehca_shca *shca, u64 eqe)
252{
253 u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe);
254
255 switch (identifier) {
256 case 0x02: /* path migrated */
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200257 qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG, 0);
Heiko J Schickfab97222006-09-22 15:22:22 -0700258 break;
259 case 0x03: /* communication established */
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200260 qp_event_callback(shca, eqe, IB_EVENT_COMM_EST, 0);
Heiko J Schickfab97222006-09-22 15:22:22 -0700261 break;
262 case 0x04: /* send queue drained */
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200263 qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED, 0);
Heiko J Schickfab97222006-09-22 15:22:22 -0700264 break;
265 case 0x05: /* QP error */
266 case 0x06: /* QP error */
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200267 qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL, 1);
Heiko J Schickfab97222006-09-22 15:22:22 -0700268 break;
269 case 0x07: /* CQ error */
270 case 0x08: /* CQ error */
271 cq_event_callback(shca, eqe);
272 break;
273 case 0x09: /* MRMWPTE error */
274 ehca_err(&shca->ib_device, "MRMWPTE error.");
275 break;
276 case 0x0A: /* port event */
277 ehca_err(&shca->ib_device, "Port event.");
278 break;
279 case 0x0B: /* MR access error */
280 ehca_err(&shca->ib_device, "MR access error.");
281 break;
282 case 0x0C: /* EQ error */
283 ehca_err(&shca->ib_device, "EQ error.");
284 break;
285 case 0x0D: /* P/Q_Key mismatch */
286 ehca_err(&shca->ib_device, "P/Q_Key mismatch.");
287 break;
288 case 0x10: /* sampling complete */
289 ehca_err(&shca->ib_device, "Sampling complete.");
290 break;
291 case 0x11: /* unaffiliated access error */
292 ehca_err(&shca->ib_device, "Unaffiliated access error.");
293 break;
Joachim Fenkese90d0b32007-09-11 15:34:04 +0200294 case 0x12: /* path migrating */
295 ehca_err(&shca->ib_device, "Path migrating.");
Heiko J Schickfab97222006-09-22 15:22:22 -0700296 break;
297 case 0x13: /* interface trace stopped */
298 ehca_err(&shca->ib_device, "Interface trace stopped.");
299 break;
300 case 0x14: /* first error capture info available */
Hoang-Nam Nguyen633a5ae2007-07-20 16:02:18 +0200301 ehca_info(&shca->ib_device, "First error capture available");
302 break;
303 case 0x15: /* SRQ limit reached */
304 qp_event_callback(shca, eqe, IB_EVENT_SRQ_LIMIT_REACHED, 0);
305 break;
Heiko J Schickfab97222006-09-22 15:22:22 -0700306 default:
307 ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
308 identifier, shca->ib_device.name);
309 break;
310 }
311
312 return;
313}
314
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200315static void dispatch_port_event(struct ehca_shca *shca, int port_num,
316 enum ib_event_type type, const char *msg)
Heiko J Schickfab97222006-09-22 15:22:22 -0700317{
318 struct ib_event event;
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200319
320 ehca_info(&shca->ib_device, "port %d %s.", port_num, msg);
321 event.device = &shca->ib_device;
322 event.event = type;
323 event.element.port_num = port_num;
324 ib_dispatch_event(&event);
325}
326
327static void notify_port_conf_change(struct ehca_shca *shca, int port_num)
328{
329 struct ehca_sma_attr new_attr;
330 struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr;
331
332 ehca_query_sma_attr(shca, port_num, &new_attr);
333
334 if (new_attr.sm_sl != old_attr->sm_sl ||
335 new_attr.sm_lid != old_attr->sm_lid)
336 dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE,
337 "SM changed");
338
339 if (new_attr.lid != old_attr->lid ||
340 new_attr.lmc != old_attr->lmc)
341 dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE,
342 "LID changed");
343
344 if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len ||
345 memcmp(new_attr.pkeys, old_attr->pkeys,
346 sizeof(u16) * new_attr.pkey_tbl_len))
347 dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE,
348 "P_Key changed");
349
350 *old_attr = new_attr;
351}
352
353static void parse_ec(struct ehca_shca *shca, u64 eqe)
354{
Heiko J Schickfab97222006-09-22 15:22:22 -0700355 u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
356 u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
357
358 switch (ec) {
359 case 0x30: /* port availability change */
360 if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
Heiko J Schickfab97222006-09-22 15:22:22 -0700361 shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200362 dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
363 "is active");
364 ehca_query_sma_attr(shca, port,
365 &shca->sport[port - 1].saved_attr);
Heiko J Schickfab97222006-09-22 15:22:22 -0700366 } else {
Heiko J Schickfab97222006-09-22 15:22:22 -0700367 shca->sport[port - 1].port_state = IB_PORT_DOWN;
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200368 dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
369 "is inactive");
Heiko J Schickfab97222006-09-22 15:22:22 -0700370 }
371 break;
372 case 0x31:
373 /* port configuration change
374 * disruptive change is caused by
375 * LID, PKEY or SM change
376 */
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200377 if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
378 ehca_warn(&shca->ib_device, "disruptive port "
379 "%d configuration change", port);
Heiko J Schickfab97222006-09-22 15:22:22 -0700380
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200381 shca->sport[port - 1].port_state = IB_PORT_DOWN;
382 dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
383 "is inactive");
Heiko J Schickfab97222006-09-22 15:22:22 -0700384
Joachim Fenkes8705ce52007-07-09 15:32:22 +0200385 shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
386 dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
387 "is active");
388 } else
389 notify_port_conf_change(shca, port);
Heiko J Schickfab97222006-09-22 15:22:22 -0700390 break;
391 case 0x32: /* adapter malfunction */
392 ehca_err(&shca->ib_device, "Adapter malfunction.");
393 break;
394 case 0x33: /* trace stopped */
395 ehca_err(&shca->ib_device, "Traced stopped.");
396 break;
397 default:
398 ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
399 ec, shca->ib_device.name);
400 break;
401 }
402
403 return;
404}
405
406static inline void reset_eq_pending(struct ehca_cq *cq)
407{
408 u64 CQx_EP;
409 struct h_galpa gal = cq->galpas.kernel;
410
411 hipz_galpa_store_cq(gal, cqx_ep, 0x0);
412 CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep));
413
414 return;
415}
416
David Howells7d12e782006-10-05 14:55:46 +0100417irqreturn_t ehca_interrupt_neq(int irq, void *dev_id)
Heiko J Schickfab97222006-09-22 15:22:22 -0700418{
419 struct ehca_shca *shca = (struct ehca_shca*)dev_id;
420
421 tasklet_hi_schedule(&shca->neq.interrupt_task);
422
423 return IRQ_HANDLED;
424}
425
426void ehca_tasklet_neq(unsigned long data)
427{
428 struct ehca_shca *shca = (struct ehca_shca*)data;
429 struct ehca_eqe *eqe;
430 u64 ret;
431
432 eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
433
434 while (eqe) {
435 if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
436 parse_ec(shca, eqe->entry);
437
438 eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
439 }
440
441 ret = hipz_h_reset_event(shca->ipz_hca_handle,
442 shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL);
443
444 if (ret != H_SUCCESS)
445 ehca_err(&shca->ib_device, "Can't clear notification events.");
446
447 return;
448}
449
David Howells7d12e782006-10-05 14:55:46 +0100450irqreturn_t ehca_interrupt_eq(int irq, void *dev_id)
Heiko J Schickfab97222006-09-22 15:22:22 -0700451{
452 struct ehca_shca *shca = (struct ehca_shca*)dev_id;
453
454 tasklet_hi_schedule(&shca->eq.interrupt_task);
455
456 return IRQ_HANDLED;
457}
458
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100459
460static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
461{
462 u64 eqe_value;
463 u32 token;
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100464 struct ehca_cq *cq;
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100465
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100466 eqe_value = eqe->entry;
467 ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value);
468 if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100469 ehca_dbg(&shca->ib_device, "Got completion event");
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100470 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200471 read_lock(&ehca_cq_idr_lock);
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100472 cq = idr_find(&ehca_cq_idr, token);
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200473 if (cq)
474 atomic_inc(&cq->nr_events);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200475 read_unlock(&ehca_cq_idr_lock);
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100476 if (cq == NULL) {
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100477 ehca_err(&shca->ib_device,
478 "Invalid eqe for non-existing cq token=%x",
479 token);
480 return;
481 }
482 reset_eq_pending(cq);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100483 if (ehca_scaling_code)
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100484 queue_comp_task(cq);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100485 else {
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100486 comp_event_callback(cq);
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200487 if (atomic_dec_and_test(&cq->nr_events))
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100488 wake_up(&cq->wait_completion);
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100489 }
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100490 } else {
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100491 ehca_dbg(&shca->ib_device, "Got non completion event");
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100492 parse_identifier(shca, eqe_value);
493 }
494}
495
496void ehca_process_eq(struct ehca_shca *shca, int is_irq)
497{
498 struct ehca_eq *eq = &shca->eq;
499 struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache;
500 u64 eqe_value;
501 unsigned long flags;
502 int eqe_cnt, i;
503 int eq_empty = 0;
504
505 spin_lock_irqsave(&eq->irq_spinlock, flags);
506 if (is_irq) {
507 const int max_query_cnt = 100;
508 int query_cnt = 0;
509 int int_state = 1;
510 do {
511 int_state = hipz_h_query_int_state(
512 shca->ipz_hca_handle, eq->ist);
513 query_cnt++;
514 iosync();
515 } while (int_state && query_cnt < max_query_cnt);
516 if (unlikely((query_cnt == max_query_cnt)))
517 ehca_dbg(&shca->ib_device, "int_state=%x query_cnt=%x",
518 int_state, query_cnt);
519 }
520
521 /* read out all eqes */
522 eqe_cnt = 0;
523 do {
524 u32 token;
525 eqe_cache[eqe_cnt].eqe =
526 (struct ehca_eqe *)ehca_poll_eq(shca, eq);
527 if (!eqe_cache[eqe_cnt].eqe)
528 break;
529 eqe_value = eqe_cache[eqe_cnt].eqe->entry;
530 if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
531 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200532 read_lock(&ehca_cq_idr_lock);
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100533 eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token);
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200534 if (eqe_cache[eqe_cnt].cq)
535 atomic_inc(&eqe_cache[eqe_cnt].cq->nr_events);
Joachim Fenkes26ed6872007-07-09 15:31:10 +0200536 read_unlock(&ehca_cq_idr_lock);
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100537 if (!eqe_cache[eqe_cnt].cq) {
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100538 ehca_err(&shca->ib_device,
539 "Invalid eqe for non-existing cq "
540 "token=%x", token);
541 continue;
542 }
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100543 } else
544 eqe_cache[eqe_cnt].cq = NULL;
545 eqe_cnt++;
546 } while (eqe_cnt < EHCA_EQE_CACHE_SIZE);
547 if (!eqe_cnt) {
548 if (is_irq)
549 ehca_dbg(&shca->ib_device,
550 "No eqe found for irq event");
551 goto unlock_irq_spinlock;
552 } else if (!is_irq)
553 ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt);
554 if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE))
555 ehca_dbg(&shca->ib_device, "too many eqes for one irq event");
556 /* enable irq for new packets */
557 for (i = 0; i < eqe_cnt; i++) {
558 if (eq->eqe_cache[i].cq)
559 reset_eq_pending(eq->eqe_cache[i].cq);
560 }
561 /* check eq */
562 spin_lock(&eq->spinlock);
563 eq_empty = (!ipz_eqit_eq_peek_valid(&shca->eq.ipz_queue));
564 spin_unlock(&eq->spinlock);
565 /* call completion handler for cached eqes */
566 for (i = 0; i < eqe_cnt; i++)
567 if (eq->eqe_cache[i].cq) {
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100568 if (ehca_scaling_code)
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100569 queue_comp_task(eq->eqe_cache[i].cq);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100570 else {
571 struct ehca_cq *cq = eq->eqe_cache[i].cq;
572 comp_event_callback(cq);
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200573 if (atomic_dec_and_test(&cq->nr_events))
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100574 wake_up(&cq->wait_completion);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100575 }
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100576 } else {
577 ehca_dbg(&shca->ib_device, "Got non completion event");
578 parse_identifier(shca, eq->eqe_cache[i].eqe->entry);
579 }
580 /* poll eq if not empty */
581 if (eq_empty)
582 goto unlock_irq_spinlock;
583 do {
584 struct ehca_eqe *eqe;
585 eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
586 if (!eqe)
587 break;
588 process_eqe(shca, eqe);
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100589 } while (1);
590
591unlock_irq_spinlock:
592 spin_unlock_irqrestore(&eq->irq_spinlock, flags);
593}
594
Heiko J Schickfab97222006-09-22 15:22:22 -0700595void ehca_tasklet_eq(unsigned long data)
596{
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100597 ehca_process_eq((struct ehca_shca*)data, 1);
Heiko J Schickfab97222006-09-22 15:22:22 -0700598}
599
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200600static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
Heiko J Schickfab97222006-09-22 15:22:22 -0700601{
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100602 int cpu;
603 unsigned long flags;
Heiko J Schickfab97222006-09-22 15:22:22 -0700604
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100605 WARN_ON_ONCE(!in_interrupt());
Heiko J Schickfab97222006-09-22 15:22:22 -0700606 if (ehca_debug_level)
607 ehca_dmp(&cpu_online_map, sizeof(cpumask_t), "");
608
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100609 spin_lock_irqsave(&pool->last_cpu_lock, flags);
610 cpu = next_cpu(pool->last_cpu, cpu_online_map);
611 if (cpu == NR_CPUS)
612 cpu = first_cpu(cpu_online_map);
613 pool->last_cpu = cpu;
614 spin_unlock_irqrestore(&pool->last_cpu_lock, flags);
Heiko J Schickfab97222006-09-22 15:22:22 -0700615
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100616 return cpu;
Heiko J Schickfab97222006-09-22 15:22:22 -0700617}
618
619static void __queue_comp_task(struct ehca_cq *__cq,
620 struct ehca_cpu_comp_task *cct)
621{
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100622 unsigned long flags;
Heiko J Schickfab97222006-09-22 15:22:22 -0700623
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100624 spin_lock_irqsave(&cct->task_lock, flags);
625 spin_lock(&__cq->task_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700626
627 if (__cq->nr_callbacks == 0) {
628 __cq->nr_callbacks++;
629 list_add_tail(&__cq->entry, &cct->cq_list);
630 cct->cq_jobs++;
631 wake_up(&cct->wait_queue);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100632 } else
Heiko J Schickfab97222006-09-22 15:22:22 -0700633 __cq->nr_callbacks++;
634
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100635 spin_unlock(&__cq->task_lock);
636 spin_unlock_irqrestore(&cct->task_lock, flags);
Heiko J Schickfab97222006-09-22 15:22:22 -0700637}
638
639static void queue_comp_task(struct ehca_cq *__cq)
640{
Heiko J Schickfab97222006-09-22 15:22:22 -0700641 int cpu_id;
642 struct ehca_cpu_comp_task *cct;
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100643 int cq_jobs;
644 unsigned long flags;
Heiko J Schickfab97222006-09-22 15:22:22 -0700645
Heiko J Schickfab97222006-09-22 15:22:22 -0700646 cpu_id = find_next_online_cpu(pool);
Heiko J Schickfab97222006-09-22 15:22:22 -0700647 BUG_ON(!cpu_online(cpu_id));
648
649 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100650 BUG_ON(!cct);
Heiko J Schickfab97222006-09-22 15:22:22 -0700651
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100652 spin_lock_irqsave(&cct->task_lock, flags);
653 cq_jobs = cct->cq_jobs;
654 spin_unlock_irqrestore(&cct->task_lock, flags);
655 if (cq_jobs > 0) {
Heiko J Schickfab97222006-09-22 15:22:22 -0700656 cpu_id = find_next_online_cpu(pool);
657 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100658 BUG_ON(!cct);
Heiko J Schickfab97222006-09-22 15:22:22 -0700659 }
660
661 __queue_comp_task(__cq, cct);
Heiko J Schickfab97222006-09-22 15:22:22 -0700662}
663
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200664static void run_comp_task(struct ehca_cpu_comp_task *cct)
Heiko J Schickfab97222006-09-22 15:22:22 -0700665{
666 struct ehca_cq *cq;
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100667 unsigned long flags;
Heiko J Schickfab97222006-09-22 15:22:22 -0700668
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100669 spin_lock_irqsave(&cct->task_lock, flags);
Heiko J Schickfab97222006-09-22 15:22:22 -0700670
671 while (!list_empty(&cct->cq_list)) {
672 cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100673 spin_unlock_irqrestore(&cct->task_lock, flags);
Heiko J Schickfab97222006-09-22 15:22:22 -0700674
Joachim Fenkes28db6be2007-07-09 15:30:39 +0200675 comp_event_callback(cq);
676 if (atomic_dec_and_test(&cq->nr_events))
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100677 wake_up(&cq->wait_completion);
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100678
679 spin_lock_irqsave(&cct->task_lock, flags);
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100680 spin_lock(&cq->task_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700681 cq->nr_callbacks--;
Hoang-Nam Nguyen31726792007-02-28 18:01:02 +0100682 if (!cq->nr_callbacks) {
Heiko J Schickfab97222006-09-22 15:22:22 -0700683 list_del_init(cct->cq_list.next);
684 cct->cq_jobs--;
685 }
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100686 spin_unlock(&cq->task_lock);
Heiko J Schickfab97222006-09-22 15:22:22 -0700687 }
688
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100689 spin_unlock_irqrestore(&cct->task_lock, flags);
Heiko J Schickfab97222006-09-22 15:22:22 -0700690}
691
692static int comp_task(void *__cct)
693{
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200694 struct ehca_cpu_comp_task *cct = __cct;
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100695 int cql_empty;
Heiko J Schickfab97222006-09-22 15:22:22 -0700696 DECLARE_WAITQUEUE(wait, current);
697
698 set_current_state(TASK_INTERRUPTIBLE);
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200699 while (!kthread_should_stop()) {
Heiko J Schickfab97222006-09-22 15:22:22 -0700700 add_wait_queue(&cct->wait_queue, &wait);
701
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100702 spin_lock_irq(&cct->task_lock);
703 cql_empty = list_empty(&cct->cq_list);
704 spin_unlock_irq(&cct->task_lock);
705 if (cql_empty)
Heiko J Schickfab97222006-09-22 15:22:22 -0700706 schedule();
707 else
708 __set_current_state(TASK_RUNNING);
709
710 remove_wait_queue(&cct->wait_queue, &wait);
711
Hoang-Nam Nguyen8b16cef2007-02-15 17:07:30 +0100712 spin_lock_irq(&cct->task_lock);
713 cql_empty = list_empty(&cct->cq_list);
714 spin_unlock_irq(&cct->task_lock);
715 if (!cql_empty)
Heiko J Schickfab97222006-09-22 15:22:22 -0700716 run_comp_task(__cct);
717
718 set_current_state(TASK_INTERRUPTIBLE);
719 }
720 __set_current_state(TASK_RUNNING);
721
722 return 0;
723}
724
725static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
726 int cpu)
727{
728 struct ehca_cpu_comp_task *cct;
729
730 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
731 spin_lock_init(&cct->task_lock);
732 INIT_LIST_HEAD(&cct->cq_list);
733 init_waitqueue_head(&cct->wait_queue);
734 cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu);
735
736 return cct->task;
737}
738
739static void destroy_comp_task(struct ehca_comp_pool *pool,
740 int cpu)
741{
742 struct ehca_cpu_comp_task *cct;
743 struct task_struct *task;
744 unsigned long flags_cct;
745
746 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
747
748 spin_lock_irqsave(&cct->task_lock, flags_cct);
749
750 task = cct->task;
751 cct->task = NULL;
752 cct->cq_jobs = 0;
753
754 spin_unlock_irqrestore(&cct->task_lock, flags_cct);
755
756 if (task)
757 kthread_stop(task);
Heiko J Schickfab97222006-09-22 15:22:22 -0700758}
759
Satyam Sharma9faa5592007-08-23 04:58:30 +0530760static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
Heiko J Schickfab97222006-09-22 15:22:22 -0700761{
762 struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
763 LIST_HEAD(list);
764 struct ehca_cq *cq;
765 unsigned long flags_cct;
766
767 spin_lock_irqsave(&cct->task_lock, flags_cct);
768
769 list_splice_init(&cct->cq_list, &list);
770
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200771 while (!list_empty(&list)) {
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100772 cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
Heiko J Schickfab97222006-09-22 15:22:22 -0700773
Hoang-Nam Nguyen78d8d5f2007-02-15 17:06:33 +0100774 list_del(&cq->entry);
775 __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
776 smp_processor_id()));
Heiko J Schickfab97222006-09-22 15:22:22 -0700777 }
778
779 spin_unlock_irqrestore(&cct->task_lock, flags_cct);
780
781}
782
Satyam Sharma9faa5592007-08-23 04:58:30 +0530783static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
784 unsigned long action,
785 void *hcpu)
Heiko J Schickfab97222006-09-22 15:22:22 -0700786{
787 unsigned int cpu = (unsigned long)hcpu;
788 struct ehca_cpu_comp_task *cct;
789
790 switch (action) {
791 case CPU_UP_PREPARE:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700792 case CPU_UP_PREPARE_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700793 ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
Hoang-Nam Nguyen2b943972007-07-12 17:53:47 +0200794 if (!create_comp_task(pool, cpu)) {
Heiko J Schickfab97222006-09-22 15:22:22 -0700795 ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
796 return NOTIFY_BAD;
797 }
798 break;
799 case CPU_UP_CANCELED:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700800 case CPU_UP_CANCELED_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700801 ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
802 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
803 kthread_bind(cct->task, any_online_cpu(cpu_online_map));
804 destroy_comp_task(pool, cpu);
805 break;
806 case CPU_ONLINE:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700807 case CPU_ONLINE_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700808 ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
809 cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
810 kthread_bind(cct->task, cpu);
811 wake_up_process(cct->task);
812 break;
813 case CPU_DOWN_PREPARE:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700814 case CPU_DOWN_PREPARE_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700815 ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
816 break;
817 case CPU_DOWN_FAILED:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700818 case CPU_DOWN_FAILED_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700819 ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
820 break;
821 case CPU_DEAD:
Rafael J. Wysocki8bb78442007-05-09 02:35:10 -0700822 case CPU_DEAD_FROZEN:
Heiko J Schickfab97222006-09-22 15:22:22 -0700823 ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
824 destroy_comp_task(pool, cpu);
825 take_over_work(pool, cpu);
826 break;
827 }
828
829 return NOTIFY_OK;
830}
Satyam Sharma9faa5592007-08-23 04:58:30 +0530831
832static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
833 .notifier_call = comp_pool_callback,
834 .priority = 0,
835};
Heiko J Schickfab97222006-09-22 15:22:22 -0700836
Heiko J Schickfab97222006-09-22 15:22:22 -0700837int ehca_create_comp_pool(void)
838{
Heiko J Schickfab97222006-09-22 15:22:22 -0700839 int cpu;
840 struct task_struct *task;
841
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100842 if (!ehca_scaling_code)
843 return 0;
844
Heiko J Schickfab97222006-09-22 15:22:22 -0700845 pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
846 if (pool == NULL)
847 return -ENOMEM;
848
849 spin_lock_init(&pool->last_cpu_lock);
850 pool->last_cpu = any_online_cpu(cpu_online_map);
851
852 pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
853 if (pool->cpu_comp_tasks == NULL) {
854 kfree(pool);
855 return -EINVAL;
856 }
857
858 for_each_online_cpu(cpu) {
859 task = create_comp_task(pool, cpu);
860 if (task) {
861 kthread_bind(task, cpu);
862 wake_up_process(task);
863 }
864 }
865
Satyam Sharma9faa5592007-08-23 04:58:30 +0530866 register_hotcpu_notifier(&comp_pool_callback_nb);
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100867
868 printk(KERN_INFO "eHCA scaling code enabled\n");
Heiko J Schickfab97222006-09-22 15:22:22 -0700869
870 return 0;
871}
872
873void ehca_destroy_comp_pool(void)
874{
Heiko J Schickfab97222006-09-22 15:22:22 -0700875 int i;
876
Hoang-Nam Nguyen4fd30062007-02-15 17:08:33 +0100877 if (!ehca_scaling_code)
878 return;
879
Satyam Sharma9faa5592007-08-23 04:58:30 +0530880 unregister_hotcpu_notifier(&comp_pool_callback_nb);
Heiko J Schickfab97222006-09-22 15:22:22 -0700881
882 for (i = 0; i < NR_CPUS; i++) {
883 if (cpu_online(i))
884 destroy_comp_task(pool, i);
885 }
Akinobu Mita65e5c022007-02-05 16:21:09 -0800886 free_percpu(pool->cpu_comp_tasks);
887 kfree(pool);
Heiko J Schickfab97222006-09-22 15:22:22 -0700888}