2 * -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
3 * vim:expandtab:shiftwidth=8:tabstop=8:
7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 only,
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License version 2 for more details (a copy is included
17 * in the LICENSE file that accompanied this code).
19 * You should have received a copy of the GNU General Public License
20 * version 2 along with this program; If not, see [sun.com URL with a
23 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24 * CA 95054 USA or visit www.sun.com if you need additional information or
30 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
31 * Use is subject to license terms.
33 * Copyright (C) 2006 Myricom, Inc.
36 * This file is part of Lustre, http://www.lustre.org/
37 * Lustre is a trademark of Sun Microsystems, Inc.
39 * lnet/klnds/mxlnd/mxlnd.c
41 * Author: Eric Barton <eric@bartonsoftware.com>
42 * Author: Scott Atchley <atchley at myri.com>
49 .lnd_startup = mxlnd_startup,
50 .lnd_shutdown = mxlnd_shutdown,
52 .lnd_send = mxlnd_send,
53 .lnd_recv = mxlnd_recv,
56 kmx_data_t kmxlnd_data;
59 * mxlnd_ctx_free - free ctx struct
60 * @ctx - a kmx_peer pointer
62 * The calling function should remove the ctx from the ctx list first
66 mxlnd_ctx_free(struct kmx_ctx *ctx)
68 if (ctx == NULL) return;
70 if (ctx->mxc_page != NULL) {
71 __free_page(ctx->mxc_page);
72 spin_lock(&kmxlnd_data.kmx_global_lock);
73 kmxlnd_data.kmx_mem_used -= MXLND_EAGER_SIZE;
74 spin_unlock(&kmxlnd_data.kmx_global_lock);
77 if (ctx->mxc_seg_list != NULL) {
78 LASSERT(ctx->mxc_nseg > 0);
79 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
82 MXLND_FREE (ctx, sizeof (*ctx));
87 * mxlnd_ctx_alloc - allocate and initialize a new ctx struct
88 * @ctxp - address of a kmx_ctx pointer
90 * Returns 0 on success and -EINVAL, -ENOMEM on failure
93 mxlnd_ctx_alloc(struct kmx_ctx **ctxp, enum kmx_req_type type)
96 struct kmx_ctx *ctx = NULL;
98 if (ctxp == NULL) return -EINVAL;
100 MXLND_ALLOC(ctx, sizeof (*ctx));
102 CDEBUG(D_NETERROR, "Cannot allocate ctx\n");
105 memset(ctx, 0, sizeof(*ctx));
106 spin_lock_init(&ctx->mxc_lock);
108 ctx->mxc_type = type;
109 ctx->mxc_page = alloc_page (GFP_KERNEL);
110 if (ctx->mxc_page == NULL) {
111 CDEBUG(D_NETERROR, "Can't allocate page\n");
115 spin_lock(&kmxlnd_data.kmx_global_lock);
116 kmxlnd_data.kmx_mem_used += MXLND_EAGER_SIZE;
117 spin_unlock(&kmxlnd_data.kmx_global_lock);
118 ctx->mxc_msg = (struct kmx_msg *)((char *)page_address(ctx->mxc_page));
119 ctx->mxc_seg.segment_ptr = MX_PA_TO_U64(lnet_page2phys(ctx->mxc_page));
120 ctx->mxc_state = MXLND_CTX_IDLE;
131 * mxlnd_ctx_init - reset ctx struct to the default values
132 * @ctx - a kmx_ctx pointer
135 mxlnd_ctx_init(struct kmx_ctx *ctx)
137 if (ctx == NULL) return;
139 /* do not change mxc_type */
140 ctx->mxc_incarnation = 0;
141 ctx->mxc_deadline = 0;
142 ctx->mxc_state = MXLND_CTX_IDLE;
143 /* ignore mxc_global_list */
144 if (ctx->mxc_list.next != NULL && !list_empty(&ctx->mxc_list)) {
145 if (ctx->mxc_peer != NULL) spin_lock(&ctx->mxc_lock);
146 list_del_init(&ctx->mxc_list);
147 if (ctx->mxc_peer != NULL) spin_unlock(&ctx->mxc_lock);
149 /* ignore mxc_rx_list */
150 /* ignore mxc_lock */
152 ctx->mxc_peer = NULL;
153 ctx->mxc_conn = NULL;
155 /* ignore mxc_page */
156 ctx->mxc_lntmsg[0] = NULL;
157 ctx->mxc_lntmsg[1] = NULL;
158 ctx->mxc_msg_type = 0;
159 ctx->mxc_cookie = 0LL;
160 ctx->mxc_match = 0LL;
161 /* ctx->mxc_seg.segment_ptr points to mxc_page */
162 ctx->mxc_seg.segment_length = 0;
163 if (ctx->mxc_seg_list != NULL) {
164 LASSERT(ctx->mxc_nseg > 0);
165 MXLND_FREE(ctx->mxc_seg_list, ctx->mxc_nseg * sizeof(mx_ksegment_t));
167 ctx->mxc_seg_list = NULL;
170 ctx->mxc_mxreq = NULL;
171 memset(&ctx->mxc_status, 0, sizeof(mx_status_t));
175 ctx->mxc_msg->mxm_type = 0;
176 ctx->mxc_msg->mxm_credits = 0;
177 ctx->mxc_msg->mxm_nob = 0;
178 ctx->mxc_msg->mxm_seq = 0;
184 * mxlnd_free_txs - free kmx_txs and associated pages
186 * Called from mxlnd_shutdown()
191 struct kmx_ctx *tx = NULL;
192 struct kmx_ctx *next = NULL;
194 list_for_each_entry_safe(tx, next, &kmxlnd_data.kmx_txs, mxc_global_list) {
195 list_del_init(&tx->mxc_global_list);
202 * mxlnd_init_txs - allocate tx descriptors then stash on txs and idle tx lists
204 * Called from mxlnd_startup()
205 * returns 0 on success, else -ENOMEM
212 struct kmx_ctx *tx = NULL;
214 for (i = 0; i < *kmxlnd_tunables.kmx_ntx; i++) {
215 ret = mxlnd_ctx_alloc(&tx, MXLND_REQ_TX);
221 /* in startup(), no locks required */
222 list_add_tail(&tx->mxc_global_list, &kmxlnd_data.kmx_txs);
223 list_add_tail(&tx->mxc_list, &kmxlnd_data.kmx_tx_idle);
229 * mxlnd_free_rxs - free initial kmx_rx descriptors and associated pages
231 * Called from mxlnd_shutdown()
236 struct kmx_ctx *rx = NULL;
237 struct kmx_ctx *next = NULL;
239 list_for_each_entry_safe(rx, next, &kmxlnd_data.kmx_rxs, mxc_global_list) {
240 list_del_init(&rx->mxc_global_list);
247 * mxlnd_init_rxs - allocate initial rx descriptors
249 * Called from startup(). We create MXLND_MAX_PEERS plus MXLND_NTX
250 * rx descriptors. We create one for each potential peer to handle
251 * the initial connect request. We create on for each tx in case the
252 * send requires a non-eager receive.
254 * Returns 0 on success, else -ENOMEM
261 struct kmx_ctx *rx = NULL;
263 for (i = 0; i < (*kmxlnd_tunables.kmx_ntx + *kmxlnd_tunables.kmx_max_peers); i++) {
264 ret = mxlnd_ctx_alloc(&rx, MXLND_REQ_RX);
270 /* in startup(), no locks required */
271 list_add_tail(&rx->mxc_global_list, &kmxlnd_data.kmx_rxs);
272 list_add_tail(&rx->mxc_list, &kmxlnd_data.kmx_rx_idle);
278 * mxlnd_free_peers - free peers
280 * Called from mxlnd_shutdown()
283 mxlnd_free_peers(void)
286 struct kmx_peer *peer = NULL;
287 struct kmx_peer *next = NULL;
289 for (i = 0; i < MXLND_HASH_SIZE; i++) {
290 list_for_each_entry_safe(peer, next, &kmxlnd_data.kmx_peers[i], mxp_peers) {
291 list_del_init(&peer->mxp_peers);
292 if (peer->mxp_conn) mxlnd_conn_decref(peer->mxp_conn);
293 mxlnd_peer_decref(peer);
299 mxlnd_host_alloc(struct kmx_host **hostp)
301 struct kmx_host *host = NULL;
303 MXLND_ALLOC(host, sizeof (*host));
305 CDEBUG(D_NETERROR, "Cannot allocate host\n");
308 memset(host, 0, sizeof(*host));
309 spin_lock_init(&host->mxh_lock);
317 mxlnd_host_free(struct kmx_host *host)
319 if (host == NULL) return;
321 if (host->mxh_hostname != NULL)
322 MXLND_FREE(host->mxh_hostname, strlen(host->mxh_hostname) + 1);
324 MXLND_FREE(host, sizeof(*host));
329 * mxlnd_free_hosts - free kmx_hosts
331 * Called from mxlnd_shutdown()
334 mxlnd_free_hosts(void)
336 struct kmx_host *host = NULL;
337 struct kmx_host *next = NULL;
339 list_for_each_entry_safe(host, next, &kmxlnd_data.kmx_hosts, mxh_list) {
340 list_del_init(&host->mxh_list);
341 mxlnd_host_free(host);
347 #define str(s) xstr(s)
348 #define MXLND_MAX_BOARD 4 /* we expect hosts to have fewer NICs than this */
349 #define MXLND_MAX_EP_ID 16 /* we expect hosts to have less than this endpoints */
351 /* this parses a line that consists of:
353 * IP HOSTNAME BOARD ENDPOINT ID
354 * 169.192.0.113 mds01 0 3
356 * By default MX uses the alias (short hostname). If you override
357 * it using mx_hostname to use the FQDN or some other name, the hostname
358 * here must match exactly.
361 /* MX_MAX_HOSTNAME_LEN = 80. See myriexpress.h */
363 mxlnd_parse_line(char *line)
368 u32 ip[4] = { 0, 0, 0, 0 };
369 char hostname[MX_MAX_HOSTNAME_LEN];
372 struct kmx_host *host = NULL;
374 if (line == NULL) return -1;
378 if (len == 0) return -1;
380 /* convert tabs to spaces */
381 for (i = 0; i < len; i++) {
382 if (line[i] == '\t') line[i] = ' ';
385 memset(&hostname, 0 , sizeof(hostname));
386 ret = sscanf(line, "%d.%d.%d.%d %" str(MX_MAX_HOSTNAME_LEN) "s %d %d",
387 &ip[0], &ip[1], &ip[2], &ip[3], hostname, &board, &ep_id);
393 /* check for valid values */
394 /* we assume a valid IP address (all <= 255), number of NICs,
395 * and number of endpoint IDs */
396 if (ip[0] > 255 || ip [1] > 255 || ip[2] > 255 || ip[3] > 255 ||
397 board > MXLND_MAX_BOARD || ep_id > MXLND_MAX_EP_ID) {
398 CDEBUG(D_NETERROR, "Illegal value in \"%s\". Ignoring "
399 "this host.\n", line);
403 ret = mxlnd_host_alloc(&host);
404 if (ret != 0) return -1;
406 host->mxh_addr = ((ip[0]<<24)|(ip[1]<<16)|(ip[2]<<8)|ip[3]);
407 len = strlen(hostname);
408 MXLND_ALLOC(host->mxh_hostname, len + 1);
409 if (host->mxh_hostname == NULL) {
410 mxlnd_host_free(host);
413 memset(host->mxh_hostname, 0, len + 1);
414 strncpy(host->mxh_hostname, hostname, len);
415 host->mxh_board = board;
416 host->mxh_ep_id = ep_id;
418 spin_lock(&kmxlnd_data.kmx_hosts_lock);
419 list_add_tail(&host->mxh_list, &kmxlnd_data.kmx_hosts);
420 spin_unlock(&kmxlnd_data.kmx_hosts_lock);
426 mxlnd_print_hosts(void)
429 struct kmx_host *host = NULL;
431 list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
433 u32 addr = host->mxh_addr;
435 ip[0] = (addr >> 24) & 0xff;
436 ip[1] = (addr >> 16) & 0xff;
437 ip[2] = (addr >> 8) & 0xff;
439 CDEBUG(D_NET, "\tip= %d.%d.%d.%d\n\thost= %s\n\tboard= %d\n\tep_id= %d\n\n",
440 ip[0], ip[1], ip[2], ip[3],
441 host->mxh_hostname, host->mxh_board, host->mxh_ep_id);
447 #define MXLND_BUFSIZE (PAGE_SIZE - 1)
450 mxlnd_parse_hosts(char *filename)
454 s32 bufsize = MXLND_BUFSIZE;
457 struct file *filp = NULL;
458 struct inode *inode = NULL;
464 if (filename == NULL) return -1;
466 filp = filp_open(filename, O_RDONLY, 0);
468 CERROR("filp_open() failed for %s\n", filename);
472 inode = filp->f_dentry->d_inode;
473 if (!S_ISREG(inode->i_mode)) {
474 CERROR("%s is not a regular file\n", filename);
478 size = (s32) inode->i_size;
479 if (size < MXLND_BUFSIZE) bufsize = size;
481 MXLND_ALLOC(buf, allocd + 1);
483 CERROR("Cannot allocate buf\n");
484 filp_close(filp, current->files);
488 while (offset < size) {
489 memset(buf, 0, bufsize + 1);
490 ret = kernel_read(filp, (unsigned long) offset, buf, (unsigned long) bufsize);
492 CDEBUG(D_NETERROR, "kernel_read() returned %d - closing %s\n", ret, filename);
493 filp_close(filp, current->files);
494 MXLND_FREE(buf, allocd + 1);
498 if (ret < bufsize) bufsize = ret;
500 while (buf_off < bufsize) {
501 sep = strchr(buf + buf_off, '\n');
504 line = buf + buf_off;
506 ret = mxlnd_parse_line(line);
507 if (ret != 0 && strlen(line) != 0) {
508 CDEBUG(D_NETERROR, "Failed to parse \"%s\". Ignoring this host.\n", line);
510 buf_off += strlen(line) + 1;
512 /* last line or we need to read more */
513 line = buf + buf_off;
514 ret = mxlnd_parse_line(line);
516 bufsize -= strlen(line) + 1;
518 buf_off += strlen(line) + 1;
522 bufsize = MXLND_BUFSIZE;
525 MXLND_FREE(buf, allocd + 1);
526 filp_close(filp, current->files);
533 * mxlnd_init_mx - open the endpoint, set out ID, register the EAGER callback
534 * @ni - the network interface
536 * Returns 0 on success, -1 on failure
539 mxlnd_init_mx(lnet_ni_t *ni)
544 mx_endpoint_addr_t addr;
545 u32 board = *kmxlnd_tunables.kmx_board;
546 u32 ep_id = *kmxlnd_tunables.kmx_ep_id;
548 struct kmx_host *host = NULL;
551 if (mxret != MX_SUCCESS) {
552 CERROR("mx_init() failed with %s (%d)\n", mx_strerror(mxret), mxret);
556 ret = mxlnd_parse_hosts(*kmxlnd_tunables.kmx_hosts);
558 if (*kmxlnd_tunables.kmx_hosts != NULL) {
559 CERROR("mxlnd_parse_hosts(%s) failed\n", *kmxlnd_tunables.kmx_hosts);
565 list_for_each_entry(host, &kmxlnd_data.kmx_hosts, mxh_list) {
566 if (strcmp(host->mxh_hostname, system_utsname.nodename) == 0) {
567 /* override the defaults and module parameters with
568 * the info from the hosts file */
569 board = host->mxh_board;
570 ep_id = host->mxh_ep_id;
571 kmxlnd_data.kmx_localhost = host;
572 CDEBUG(D_NET, "my hostname is %s board %d ep_id %d\n", kmxlnd_data.kmx_localhost->mxh_hostname, kmxlnd_data.kmx_localhost->mxh_board, kmxlnd_data.kmx_localhost->mxh_ep_id);
579 CERROR("no host entry found for localhost\n");
584 mxret = mx_open_endpoint(board, ep_id, MXLND_MSG_MAGIC,
585 NULL, 0, &kmxlnd_data.kmx_endpt);
586 if (mxret != MX_SUCCESS) {
587 CERROR("mx_open_endpoint() failed with %d\n", mxret);
592 mx_get_endpoint_addr(kmxlnd_data.kmx_endpt, &addr);
593 mx_decompose_endpoint_addr(addr, &nic_id, &ep_id);
595 LASSERT(host != NULL);
596 ni->ni_nid = LNET_MKNID(LNET_NIDNET(ni->ni_nid), host->mxh_addr);
598 CDEBUG(D_NET, "My NID is 0x%llx\n", ni->ni_nid);
600 /* this will catch all unexpected receives. */
601 mxret = mx_register_unexp_handler(kmxlnd_data.kmx_endpt,
602 (mx_unexp_handler_t) mxlnd_unexpected_recv,
604 if (mxret != MX_SUCCESS) {
605 CERROR("mx_register_unexp_callback() failed with %s\n",
607 mx_close_endpoint(kmxlnd_data.kmx_endpt);
611 mxret = mx_set_request_timeout(kmxlnd_data.kmx_endpt, NULL, MXLND_COMM_TIMEOUT/HZ*1000);
612 if (mxret != MX_SUCCESS) {
613 CERROR("mx_set_request_timeout() failed with %s\n",
615 mx_close_endpoint(kmxlnd_data.kmx_endpt);
624 * mxlnd_thread_start - spawn a kernel thread with this function
625 * @fn - function pointer
626 * @arg - pointer to the parameter data
628 * Returns 0 on success and a negative value on failure
631 mxlnd_thread_start(int (*fn)(void *arg), void *arg)
634 int i = (int) ((long) arg);
636 atomic_inc(&kmxlnd_data.kmx_nthreads);
637 init_completion(&kmxlnd_data.kmx_completions[i]);
639 pid = kernel_thread (fn, arg, 0);
641 CERROR("kernel_thread() failed with %d\n", pid);
642 atomic_dec(&kmxlnd_data.kmx_nthreads);
648 * mxlnd_thread_stop - decrement thread counter
650 * The thread returns 0 when it detects shutdown.
651 * We are simply decrementing the thread counter.
654 mxlnd_thread_stop(long id)
657 atomic_dec (&kmxlnd_data.kmx_nthreads);
658 complete(&kmxlnd_data.kmx_completions[i]);
662 * mxlnd_shutdown - stop IO, clean up state
663 * @ni - LNET interface handle
665 * No calls to the LND should be made after calling this function.
668 mxlnd_shutdown (lnet_ni_t *ni)
671 int nthreads = 2 + *kmxlnd_tunables.kmx_n_waitd;
673 LASSERT (ni == kmxlnd_data.kmx_ni);
674 LASSERT (ni->ni_data == &kmxlnd_data);
675 CDEBUG(D_NET, "in shutdown()\n");
677 CDEBUG(D_MALLOC, "before MXLND cleanup: libcfs_kmemory %d "
678 "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory),
679 kmxlnd_data.kmx_mem_used);
681 switch (kmxlnd_data.kmx_init) {
685 CDEBUG(D_NET, "setting shutdown = 1\n");
686 /* set shutdown and wakeup request_waitds */
687 kmxlnd_data.kmx_shutdown = 1;
689 mx_wakeup(kmxlnd_data.kmx_endpt);
690 up(&kmxlnd_data.kmx_tx_queue_sem);
695 case MXLND_INIT_THREADS:
697 CDEBUG(D_NET, "waiting on threads\n");
698 /* wait for threads to complete */
699 for (i = 0; i < nthreads; i++) {
700 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
702 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
704 CDEBUG(D_NET, "freeing completions\n");
705 MXLND_FREE(kmxlnd_data.kmx_completions,
706 MXLND_NCOMPLETIONS * sizeof(struct completion));
712 CDEBUG(D_NET, "stopping mx\n");
714 /* wakeup waiters if they missed the above.
715 * close endpoint to stop all traffic.
716 * this will cancel and cleanup all requests, etc. */
718 mx_wakeup(kmxlnd_data.kmx_endpt);
719 mx_close_endpoint(kmxlnd_data.kmx_endpt);
722 CDEBUG(D_NET, "mxlnd_free_hosts();\n");
729 CDEBUG(D_NET, "freeing rxs\n");
731 /* free all rxs and associated pages */
738 CDEBUG(D_NET, "freeing txs\n");
740 /* free all txs and associated pages */
745 case MXLND_INIT_DATA:
747 CDEBUG(D_NET, "freeing peers\n");
754 case MXLND_INIT_NOTHING:
757 CDEBUG(D_NET, "shutdown complete\n");
759 CDEBUG(D_MALLOC, "after MXLND cleanup: libcfs_kmemory %d "
760 "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory),
761 kmxlnd_data.kmx_mem_used);
763 kmxlnd_data.kmx_init = MXLND_INIT_NOTHING;
769 * mxlnd_startup - initialize state, open an endpoint, start IO
770 * @ni - LNET interface handle
772 * Initialize state, open an endpoint, start monitoring threads.
773 * Should only be called once.
776 mxlnd_startup (lnet_ni_t *ni)
780 int nthreads = 2; /* for timeoutd and tx_queued */
783 LASSERT (ni->ni_lnd == &the_kmxlnd);
785 if (kmxlnd_data.kmx_init != MXLND_INIT_NOTHING) {
786 CERROR("Only 1 instance supported\n");
789 CDEBUG(D_MALLOC, "before MXLND startup: libcfs_kmemory %d "
790 "kmx_mem_used %ld\n", atomic_read (&libcfs_kmemory),
791 kmxlnd_data.kmx_mem_used);
793 /* reserve 1/2 of tx for connect request messages */
794 ni->ni_maxtxcredits = *kmxlnd_tunables.kmx_ntx / 2;
795 ni->ni_peertxcredits = *kmxlnd_tunables.kmx_credits;
796 if (ni->ni_maxtxcredits < ni->ni_peertxcredits)
797 ni->ni_maxtxcredits = ni->ni_peertxcredits;
800 memset (&kmxlnd_data, 0, sizeof (kmxlnd_data));
802 kmxlnd_data.kmx_ni = ni;
803 ni->ni_data = &kmxlnd_data;
805 do_gettimeofday(&tv);
806 kmxlnd_data.kmx_incarnation = (((__u64)tv.tv_sec) * 1000000) + tv.tv_usec;
807 CDEBUG(D_NET, "my incarnation is %lld\n", kmxlnd_data.kmx_incarnation);
809 spin_lock_init (&kmxlnd_data.kmx_global_lock);
811 INIT_LIST_HEAD (&kmxlnd_data.kmx_conn_req);
812 spin_lock_init (&kmxlnd_data.kmx_conn_lock);
813 sema_init(&kmxlnd_data.kmx_conn_sem, 0);
815 INIT_LIST_HEAD (&kmxlnd_data.kmx_hosts);
816 spin_lock_init (&kmxlnd_data.kmx_hosts_lock);
818 for (i = 0; i < MXLND_HASH_SIZE; i++) {
819 INIT_LIST_HEAD (&kmxlnd_data.kmx_peers[i]);
821 rwlock_init (&kmxlnd_data.kmx_peers_lock);
823 INIT_LIST_HEAD (&kmxlnd_data.kmx_txs);
824 INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_idle);
825 spin_lock_init (&kmxlnd_data.kmx_tx_idle_lock);
826 kmxlnd_data.kmx_tx_next_cookie = 1;
827 INIT_LIST_HEAD (&kmxlnd_data.kmx_tx_queue);
828 spin_lock_init (&kmxlnd_data.kmx_tx_queue_lock);
829 sema_init(&kmxlnd_data.kmx_tx_queue_sem, 0);
831 INIT_LIST_HEAD (&kmxlnd_data.kmx_rxs);
832 spin_lock_init (&kmxlnd_data.kmx_rxs_lock);
833 INIT_LIST_HEAD (&kmxlnd_data.kmx_rx_idle);
834 spin_lock_init (&kmxlnd_data.kmx_rx_idle_lock);
836 kmxlnd_data.kmx_init = MXLND_INIT_DATA;
837 /*****************************************************/
839 ret = mxlnd_init_txs();
841 CERROR("Can't alloc tx descs: %d\n", ret);
844 kmxlnd_data.kmx_init = MXLND_INIT_TXS;
845 /*****************************************************/
847 ret = mxlnd_init_rxs();
849 CERROR("Can't alloc rx descs: %d\n", ret);
852 kmxlnd_data.kmx_init = MXLND_INIT_RXS;
853 /*****************************************************/
855 ret = mxlnd_init_mx(ni);
857 CERROR("Can't init mx\n");
861 kmxlnd_data.kmx_init = MXLND_INIT_MX;
862 /*****************************************************/
866 nthreads += *kmxlnd_tunables.kmx_n_waitd;
867 MXLND_ALLOC (kmxlnd_data.kmx_completions,
868 nthreads * sizeof(struct completion));
869 if (kmxlnd_data.kmx_completions == NULL) {
870 CERROR("failed to alloc kmxlnd_data.kmx_completions\n");
873 memset(kmxlnd_data.kmx_completions, 0,
874 nthreads * sizeof(struct completion));
877 CDEBUG(D_NET, "using %d %s in mx_wait_any()\n",
878 *kmxlnd_tunables.kmx_n_waitd,
879 *kmxlnd_tunables.kmx_n_waitd == 1 ? "thread" : "threads");
881 for (i = 0; i < *kmxlnd_tunables.kmx_n_waitd; i++) {
882 ret = mxlnd_thread_start(mxlnd_request_waitd, (void*)((long)i));
884 CERROR("Starting mxlnd_request_waitd[%d] failed with %d\n", i, ret);
885 kmxlnd_data.kmx_shutdown = 1;
886 mx_wakeup(kmxlnd_data.kmx_endpt);
887 for (--i; i >= 0; i--) {
888 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
890 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
891 MXLND_FREE(kmxlnd_data.kmx_completions,
892 MXLND_NCOMPLETIONS * sizeof(struct completion));
897 ret = mxlnd_thread_start(mxlnd_tx_queued, (void*)((long)i++));
899 CERROR("Starting mxlnd_tx_queued failed with %d\n", ret);
900 kmxlnd_data.kmx_shutdown = 1;
901 mx_wakeup(kmxlnd_data.kmx_endpt);
902 for (--i; i >= 0; i--) {
903 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
905 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
906 MXLND_FREE(kmxlnd_data.kmx_completions,
907 MXLND_NCOMPLETIONS * sizeof(struct completion));
910 ret = mxlnd_thread_start(mxlnd_timeoutd, (void*)((long)i++));
912 CERROR("Starting mxlnd_timeoutd failed with %d\n", ret);
913 kmxlnd_data.kmx_shutdown = 1;
914 mx_wakeup(kmxlnd_data.kmx_endpt);
915 up(&kmxlnd_data.kmx_tx_queue_sem);
916 for (--i; i >= 0; i--) {
917 wait_for_completion(&kmxlnd_data.kmx_completions[i]);
919 LASSERT(atomic_read(&kmxlnd_data.kmx_nthreads) == 0);
920 MXLND_FREE(kmxlnd_data.kmx_completions,
921 MXLND_NCOMPLETIONS * sizeof(struct completion));
926 kmxlnd_data.kmx_init = MXLND_INIT_THREADS;
927 /*****************************************************/
929 kmxlnd_data.kmx_init = MXLND_INIT_ALL;
930 CDEBUG(D_MALLOC, "startup complete (kmx_mem_used %ld)\n", kmxlnd_data.kmx_mem_used);
934 CERROR("mxlnd_startup failed\n");
939 static int mxlnd_init(void)
941 lnet_register_lnd(&the_kmxlnd);
945 static void mxlnd_exit(void)
947 lnet_unregister_lnd(&the_kmxlnd);
951 module_init(mxlnd_init);
952 module_exit(mxlnd_exit);
954 MODULE_LICENSE("GPL");
955 MODULE_AUTHOR("Myricom, Inc. - help@myri.com");
956 MODULE_DESCRIPTION("Kernel MyrinetExpress LND");
957 MODULE_VERSION("0.5.0");