summaryrefslogtreecommitdiff
path: root/gpxe/src/drivers/net/mlx_ipoib/ib_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/drivers/net/mlx_ipoib/ib_driver.c')
-rw-r--r--gpxe/src/drivers/net/mlx_ipoib/ib_driver.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/gpxe/src/drivers/net/mlx_ipoib/ib_driver.c b/gpxe/src/drivers/net/mlx_ipoib/ib_driver.c
new file mode 100644
index 00000000..a46db7fc
--- /dev/null
+++ b/gpxe/src/drivers/net/mlx_ipoib/ib_driver.c
@@ -0,0 +1,342 @@
+/*
+ This software is available to you under a choice of one of two
+ licenses. You may choose to be licensed under the terms of the GNU
+ General Public License (GPL) Version 2, available at
+ <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
+ license, available in the LICENSE.TXT file accompanying this
+ software. These details are also available at
+ <http://openib.org/license.html>.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved.
+*/
+
+#include "ib_driver.h"
+
+static const __u8 ipv4_bcast_gid[] = {
+ 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
+};
+
+static int wait_logic_link_up(__u8 port)
+{
+ unsigned int relax_time, max_time;
+ relax_time = 500;
+ max_time = 30000; /* 30 seconds */
+ int rc;
+ unsigned int i, error = 1;
+ __u16 status;
+ struct port_info_st pi_var;
+ __u8 port_state;
+
+ for (i = 0; i < max_time; i += relax_time) {
+ rc = get_port_info(port, &pi_var, &status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ if (status == 0) {
+ port_state = (pi_var.combined4 >> 24) & 0xf;
+ //port_state= pi_var.port_state;
+ if (port_state == 4) {
+ error = 0;
+ break;
+ }
+ }
+ }
+ printf("+");
+ mdelay(relax_time);
+ }
+
+ if (i >= max_time)
+ return -1;
+
+ return 0;
+}
+
+static int ib_driver_init(struct pci_device *pci, udqp_t * ipoib_qph_p)
+{
+ int rc;
+ __u8 port;
+ __u16 status;
+ __u32 qkey;
+ __u16 mlid;
+ ud_av_t av;
+ struct ib_eqe_st ib_eqe;
+ __u8 num_eqe;
+
+ tprintf("");
+ rc = ib_device_init(pci);
+ if (rc)
+ return rc;
+
+ tprintf("");
+
+ memcpy(ib_data.bcast_gid.raw, ipv4_bcast_gid, sizeof(ipv4_bcast_gid));
+
+ port = PXE_IB_PORT;
+ rc = setup_hca(port, &ib_data.eq);
+ if (rc)
+ return rc;
+ tprintf("setup_hca() success");
+
+ ib_data.port = port;
+
+ if(print_info)
+ printf("boot port = %d\n", ib_data.port);
+
+ rc = wait_logic_link_up(port);
+ if (rc)
+ return rc;
+
+ tprintf("wait_logic_link_up() success");
+
+ rc = get_guid_info(&status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else if (status) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("get_guid_info() success");
+
+ /* this to flush stdout that contains previous chars */
+ printf(" \n");
+ if(print_info) {
+ __u8 *gid=ib_data.port_gid.raw;
+
+ printf("\n");
+ printf("port GID=%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:"
+ "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\n",
+ gid[0],gid[1],gid[2],gid[3],gid[4],gid[5],gid[6],gid[7],
+ gid[8],gid[9],gid[10],gid[11],gid[12],gid[13],gid[14],gid[15]);
+ }
+
+ rc = get_pkey_tbl(NULL, &status);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else if (status) {
+ eprintf("");
+ return rc;
+ }
+ rc = create_mads_qp(&ib_data.mads_qp,
+ &ib_data.mads_snd_cq, &ib_data.mads_rcv_cq);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("attempt to join mcast group ...");
+ rc = join_mc_group(&qkey, &mlid, 1);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("join_mc_group() successfull qkey=0x%lx, mlid=0x%x",
+ qkey, mlid);
+ }
+
+ rc = create_ipoib_qp(&ib_data.ipoib_qp,
+ &ib_data.ipoib_snd_cq,
+ &ib_data.ipoib_rcv_cq, qkey);
+ if (rc) {
+ eprintf("");
+ return rc;
+ }
+
+ tprintf("create_ipoib_qp() success");
+ *ipoib_qph_p = ib_data.ipoib_qp;
+
+ tprintf("register qp to receive mcast...");
+ rc = add_qp_to_mcast_group(ib_data.bcast_gid, 1);
+ if (rc) {
+ eprintf("");
+ return rc;
+ } else {
+ tprintf("add_qp_to_mcast_group() success");
+ }
+
+ /* create a broadcast group ud AV */
+ av = alloc_ud_av();
+ if (!av) {
+ eprintf("");
+ return -1;
+ }
+ tprintf("alloc_ud_av() success");
+ modify_av_params(av, mlid, 1, 0, 0, &ib_data.bcast_gid, BCAST_QPN);
+ tprintf("modify_av_params() success");
+ ib_data.bcast_av = av;
+
+ do {
+ rc = poll_eq(&ib_eqe, &num_eqe);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+ if (num_eqe) {
+ tprintf("num_eqe=%d", num_eqe);
+ }
+ tprintf("num_eqe=%d", num_eqe);
+ } while (num_eqe);
+ tprintf("eq is drained");
+
+ clear_interrupt();
+
+ return rc;
+}
+
+static int ib_driver_close(int fw_fatal)
+{
+ int rc, ret = 0;
+ __u32 qkey;
+ __u16 mlid;
+
+ rc = ib_device_close();
+ if (rc) {
+ eprintf("ib_device_close() failed");
+ ret = 1;
+ }
+
+ tprintf("");
+ if (!fw_fatal) {
+ rc = join_mc_group(&qkey, &mlid, 0);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("join_mc_group(leave) success");
+
+ rc = add_qp_to_mcast_group(ib_data.bcast_gid, 0);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("add_qp_to_mcast_group(remove) success");
+
+ rc = cmd_close_ib(ib_data.port);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ tprintf("cmd_close_ib(%d) success", ib_data.port);
+
+ if (destroy_udqp(ib_data.mads_qp)) {
+ eprintf("");
+ ret = 1;
+ }
+
+ if (destroy_udqp(ib_data.ipoib_qp)) {
+ eprintf("");
+ ret = 1;
+ }
+ }
+
+ rc = cmd_close_hca(fw_fatal);
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+
+ if (!fw_fatal) {
+ rc = cmd_sys_dis();
+ if (rc) {
+ eprintf("");
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+static int poll_cqe_tout(cq_t cqh, __u16 tout, void **wqe, int *good_p)
+{
+ int rc;
+ struct ib_cqe_st ib_cqe;
+ __u8 num_cqes;
+ unsigned long end;
+
+ end = currticks() + tout;
+ do {
+ rc = ib_poll_cq(cqh, &ib_cqe, &num_cqes);
+ if (rc)
+ return rc;
+
+ if (num_cqes == 1) {
+ if (good_p) {
+ *good_p = ib_cqe.is_error ? 0 : 1;
+ }
+ if (wqe)
+ *wqe = ib_cqe.wqe;
+ return 0;
+ }
+ }
+ while (currticks() < end);
+
+ return -1;
+}
+
+static u8 *get_port_gid(void)
+{
+ return ib_data.port_gid.raw;
+}
+
+static __u32 ib_get_qpn(udqp_t qph)
+{
+ __u32 qpn;
+
+ qpn = dev_get_qpn(qph);
+
+ return qpn;
+}
+
+static int drain_eq(void)
+{
+ __u8 num_eqe = 0, tot_eqe = 0;
+ int rc;
+
+ do {
+ tot_eqe += num_eqe;
+ rc = poll_eq(ib_data.eq, &num_eqe);
+ if (rc) {
+ eprintf("");
+ return -1;
+ }
+
+ tprintf("num_eqe=%d", num_eqe);
+ } while (num_eqe);
+ tprintf("eq is drained");
+ if (tot_eqe) {
+ tprintf("got %d eqes", tot_eqe);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int poll_error_buf(void)
+{
+ __u32 *ptr= dev_ib_data.error_buf_addr;
+ __u32 i;
+
+ for (i=0; i<dev_ib_data.error_buf_size; ++i, ptr++) {
+ if ( readl(ptr) ) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+