2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 * Implementation of osm_vl15_t.
39 * This object represents the VL15 Interface object.
40 * This object is part of the opensm family of objects.
45 #endif /* HAVE_CONFIG_H */
48 #include <iba/ib_types.h>
49 #include <complib/cl_thread.h>
50 #include <vendor/osm_vendor_api.h>
51 #include <opensm/osm_vl15intf.h>
52 #include <opensm/osm_madw.h>
53 #include <opensm/osm_log.h>
54 #include <opensm/osm_helper.h>
56 /**********************************************************************
57 **********************************************************************/
59 static void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw)
61 ib_api_status_t status;
64 Non-response-expected mads are not throttled on the wire
65 since we can have no confirmation that they arrived
68 if (p_madw->resp_expected == TRUE)
70 Note that other threads may not see the response MAD
71 arrive before send() even returns.
72 In that case, the wire count would temporarily go negative.
73 To avoid this confusion, preincrement the counts on the
74 assumption that send() will succeed.
76 cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire);
78 cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent);
80 cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent);
82 status = osm_vendor_send(osm_madw_get_bind_handle(p_madw),
83 p_madw, p_madw->resp_expected);
85 if (status == IB_SUCCESS) {
86 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
87 "%u QP0 MADs on wire, %u outstanding, "
88 "%u unicasts sent, %u total sent\n",
89 p_vl->p_stats->qp0_mads_outstanding_on_wire,
90 p_vl->p_stats->qp0_mads_outstanding,
91 p_vl->p_stats->qp0_unicasts_sent,
92 p_vl->p_stats->qp0_mads_sent);
96 OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: "
97 "MAD send failed (%s)\n", ib_get_err_str(status));
100 The MAD was never successfully sent, so
101 fix up the pre-incremented count values.
104 /* Decrement qp0_mads_sent that were incremented in the code above.
105 qp0_mads_outstanding will be decremented by send error callback
106 (called by osm_vendor_send() */
107 cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent);
108 if (!p_madw->resp_expected)
109 cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent);
112 static void __osm_vl15_poller(IN void *p_ptr)
114 ib_api_status_t status;
116 osm_vl15_t *const p_vl = (osm_vl15_t *) p_ptr;
119 OSM_LOG_ENTER(p_vl->p_log);
121 if (p_vl->thread_state == OSM_THREAD_STATE_NONE)
122 p_vl->thread_state = OSM_THREAD_STATE_RUN;
124 while (p_vl->thread_state == OSM_THREAD_STATE_RUN) {
126 Start servicing the FIFOs by pulling off MAD wrappers
127 and passing them to the transport interface.
128 There are lots of corner cases here so tread carefully.
130 The unicast FIFO has priority, since somebody is waiting
131 for a timely response.
133 cl_spinlock_acquire(&p_vl->lock);
135 if (cl_qlist_count(&p_vl->ufifo) != 0)
136 p_fifo = &p_vl->ufifo;
138 p_fifo = &p_vl->rfifo;
140 p_madw = (osm_madw_t *) cl_qlist_remove_head(p_fifo);
142 cl_spinlock_release(&p_vl->lock);
144 if (p_madw != (osm_madw_t *) cl_qlist_end(p_fifo)) {
145 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
146 "Servicing p_madw = %p\n", p_madw);
147 if (osm_log_is_active(p_vl->p_log, OSM_LOG_FRAMES))
148 osm_dump_dr_smp(p_vl->p_log,
149 osm_madw_get_smp_ptr(p_madw),
152 vl15_send_mad(p_vl, p_madw);
155 The VL15 FIFO is empty, so we have nothing left to do.
157 status = cl_event_wait_on(&p_vl->signal,
158 EVENT_NO_TIMEOUT, TRUE);
160 while ((p_vl->p_stats->qp0_mads_outstanding_on_wire >=
161 (int32_t) p_vl->max_wire_smps) &&
162 (p_vl->thread_state == OSM_THREAD_STATE_RUN)) {
163 status = cl_event_wait_on(&p_vl->signal,
164 EVENT_NO_TIMEOUT, TRUE);
165 if (status != CL_SUCCESS) {
166 OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E02: "
167 "Event wait failed (%s)\n",
168 CL_STATUS_MSG(status));
175 since we abort immediately when the state != OSM_THREAD_STATE_RUN
176 we might have some mads on the queues. After the thread exits
177 the vl15 destroy routine should put these mads back...
180 OSM_LOG_EXIT(p_vl->p_log);
183 /**********************************************************************
184 **********************************************************************/
185 void osm_vl15_construct(IN osm_vl15_t * const p_vl)
187 memset(p_vl, 0, sizeof(*p_vl));
188 p_vl->state = OSM_VL15_STATE_INIT;
189 p_vl->thread_state = OSM_THREAD_STATE_NONE;
190 cl_event_construct(&p_vl->signal);
191 cl_spinlock_construct(&p_vl->lock);
192 cl_qlist_init(&p_vl->rfifo);
193 cl_qlist_init(&p_vl->ufifo);
194 cl_thread_construct(&p_vl->poller);
197 /**********************************************************************
198 **********************************************************************/
200 osm_vl15_destroy(IN osm_vl15_t * const p_vl, IN struct osm_mad_pool *p_pool)
204 OSM_LOG_ENTER(p_vl->p_log);
207 Signal our threads that we're leaving.
209 p_vl->thread_state = OSM_THREAD_STATE_EXIT;
212 Don't trigger unless event has been initialized.
213 Destroy the thread before we tear down the other objects.
215 if (p_vl->state != OSM_VL15_STATE_INIT)
216 cl_event_signal(&p_vl->signal);
218 cl_thread_destroy(&p_vl->poller);
221 Return the outstanding messages to the pool
224 cl_spinlock_acquire(&p_vl->lock);
226 while (!cl_is_qlist_empty(&p_vl->rfifo)) {
227 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
228 osm_mad_pool_put(p_pool, p_madw);
230 while (!cl_is_qlist_empty(&p_vl->ufifo)) {
231 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
232 osm_mad_pool_put(p_pool, p_madw);
235 cl_spinlock_release(&p_vl->lock);
237 cl_event_destroy(&p_vl->signal);
238 p_vl->state = OSM_VL15_STATE_INIT;
239 cl_spinlock_destroy(&p_vl->lock);
241 OSM_LOG_EXIT(p_vl->p_log);
244 /**********************************************************************
245 **********************************************************************/
247 osm_vl15_init(IN osm_vl15_t * const p_vl,
248 IN osm_vendor_t * const p_vend,
249 IN osm_log_t * const p_log,
250 IN osm_stats_t * const p_stats, IN const int32_t max_wire_smps)
252 ib_api_status_t status = IB_SUCCESS;
254 OSM_LOG_ENTER(p_log);
256 p_vl->p_vend = p_vend;
258 p_vl->p_stats = p_stats;
259 p_vl->max_wire_smps = max_wire_smps;
261 status = cl_event_init(&p_vl->signal, FALSE);
262 if (status != IB_SUCCESS)
265 p_vl->state = OSM_VL15_STATE_READY;
267 status = cl_spinlock_init(&p_vl->lock);
268 if (status != IB_SUCCESS)
272 Initialize the thread after all other dependent objects
273 have been initialized.
275 status = cl_thread_init(&p_vl->poller, __osm_vl15_poller, p_vl,
277 if (status != IB_SUCCESS)
285 /**********************************************************************
286 **********************************************************************/
287 void osm_vl15_poll(IN osm_vl15_t * const p_vl)
289 OSM_LOG_ENTER(p_vl->p_log);
291 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
294 If we have room for more VL15 MADs on the wire,
295 then signal the poller thread.
297 This is not an airtight check, since the poller thread
298 could be just about to send another MAD as we signal
299 the event here. To cover this rare case, the poller
300 thread checks for a spurious wake-up.
302 if (p_vl->p_stats->qp0_mads_outstanding_on_wire <
303 (int32_t) p_vl->max_wire_smps) {
304 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
305 "Signalling poller thread\n");
306 cl_event_signal(&p_vl->signal);
309 OSM_LOG_EXIT(p_vl->p_log);
312 /**********************************************************************
313 **********************************************************************/
314 void osm_vl15_post(IN osm_vl15_t * const p_vl, IN osm_madw_t * const p_madw)
316 OSM_LOG_ENTER(p_vl->p_log);
318 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
320 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, "Posting p_madw = 0x%p\n", p_madw);
323 Determine in which fifo to place the pending madw.
325 cl_spinlock_acquire(&p_vl->lock);
326 if (p_madw->resp_expected == TRUE) {
327 cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item);
328 osm_stats_inc_qp0_outstanding(p_vl->p_stats);
330 cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item);
331 cl_spinlock_release(&p_vl->lock);
333 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
334 "%u QP0 MADs on wire, %u QP0 MADs outstanding\n",
335 p_vl->p_stats->qp0_mads_outstanding_on_wire,
336 p_vl->p_stats->qp0_mads_outstanding);
340 OSM_LOG_EXIT(p_vl->p_log);
344 osm_vl15_shutdown(IN osm_vl15_t * const p_vl,
345 IN osm_mad_pool_t * const p_mad_pool)
349 OSM_LOG_ENTER(p_vl->p_log);
351 /* we only should get here after the VL15 interface was initialized */
352 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
354 /* grap a lock on the object */
355 cl_spinlock_acquire(&p_vl->lock);
357 /* go over all outstanding MADs and retire their transactions */
359 /* first we handle the list of response MADs */
360 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
361 while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->ufifo)) {
362 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
363 "Releasing Response p_madw = %p\n", p_madw);
365 osm_mad_pool_put(p_mad_pool, p_madw);
367 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
370 /* Request MADs we send out */
371 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
372 while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->rfifo)) {
373 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
374 "Releasing Request p_madw = %p\n", p_madw);
376 osm_mad_pool_put(p_mad_pool, p_madw);
377 osm_stats_dec_qp0_outstanding(p_vl->p_stats);
379 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
383 cl_spinlock_release(&p_vl->lock);
385 OSM_LOG_EXIT(p_vl->p_log);