* your option) any later version.
*/
+#include <errno.h>
+#include <gpxe/pci.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/infiniband.h>
+
+struct mlx_nic {
+};
+
/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
}
}
+/**
+ * Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int mlx_open ( struct net_device *netdev ) {
+ return 0;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev Network device
+ */
+static void mlx_close ( struct net_device *netdev ) {
+}
+
+#warning "Broadcast address?"
+static uint8_t ib_broadcast[IB_ALEN] = { 0xff, };
+
+
+/**
+ * Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int mlx_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf ) {
+ struct ibhdr *ibhdr = iobuf->data;
+
+ DBG ( "Sending packet:\n" );
+ // DBG_HD ( iobuf->data, iob_len ( iobuf ) );
+
+ DBG ( "Peer:\n" );
+ DBG_HD ( &ibhdr->peer[0], IB_ALEN );
+ DBG ( "Bcast:\n" );
+ DBG_HD ( &ib_broadcast[0], IB_ALEN );
+
+ iob_pull ( iobuf, sizeof ( *ibhdr ) );
+
+ if ( memcmp ( ibhdr->peer, ib_broadcast, IB_ALEN ) == 0 ) {
+ printf ( "Sending broadcast packet\n" );
+ return send_bcast_packet ( ibhdr->proto, iobuf->data,
+ iob_len ( iobuf ) );
+ } else {
+ printf ( "Sending unicast packet\n" );
+ return send_ucast_packet ( ibhdr->peer, ibhdr->proto,
+ iobuf->data, iob_len ( iobuf ) );
+ }
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void mlx_poll ( struct net_device *netdev ) {
+ struct ib_cqe_st ib_cqe;
+ uint8_t num_cqes;
+ unsigned int len;
+ struct io_buffer *iobuf;
+ void *buf;
+ int rc;
+
+ if ( ( rc = poll_error_buf() ) != 0 ) {
+ DBG ( "poll_error_buf() failed: %s\n", strerror ( rc ) );
+ return;
+ }
+
+ if ( ( rc = drain_eq() ) != 0 ) {
+ DBG ( "drain_eq() failed: %s\n", strerror ( rc ) );
+ return;
+ }
+
+ if ( ( rc = ib_poll_cq ( ipoib_data.rcv_cqh, &ib_cqe,
+ &num_cqes ) ) != 0 ) {
+ DBG ( "ib_poll_cq() failed: %s\n", strerror ( rc ) );
+ return;
+ }
+
+ if ( ! num_cqes )
+ return;
+
+ if ( ib_cqe.is_error ) {
+ DBG ( "cqe error\n" );
+ free_wqe ( ib_cqe.wqe );
+ return;
+ }
+
+ len = ib_cqe.count;
+ iobuf = alloc_iob ( len );
+ if ( ! iobuf ) {
+ DBG ( "out of memory\n" );
+ free_wqe ( ib_cqe.wqe );
+ return;
+ }
+ memcpy ( iob_put ( iobuf, len ), buf, len );
+ DBG ( "Received packet:\n" );
+ DBG_HD ( iobuf->data, iob_len ( iobuf ) );
+
+ netdev_rx ( netdev, iobuf );
+
+ free_wqe ( ib_cqe.wqe );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev Network device
+ * @v enable Interrupts should be enabled
+ */
+static void mlx_irq ( struct net_device *netdev, int enable ) {
+}
+
+static struct net_device_operations mlx_operations = {
+ .open = mlx_open,
+ .close = mlx_close,
+ .transmit = mlx_transmit,
+ .poll = mlx_poll,
+ .irq = mlx_irq,
+};
+
/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
}
}
+/**
+ * Remove PCI device
+ *
+ * @v pci PCI device
+ */
+static void mlx_remove ( struct pci_device *pci ) {
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct mlx_nic *mlx = netdev->priv;
+
+ unregister_netdev ( netdev );
+ ipoib_close(0);
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
static struct nic_operations mt25218_operations = {
.connect = dummy_connect,
.poll = mt25218_poll,
return 0;
}
-static struct pci_device_id mt25218_nics[] = {
+/**
+ * Probe PCI device
+ *
+ * @v pci PCI device
+ * @v id PCI ID
+ * @ret rc Return status code
+ */
+static int mlx_probe ( struct pci_device *pci,
+ const struct pci_device_id *id __unused ) {
+ struct net_device *netdev;
+ struct mlx_nic *mlx;
+ int rc;
+
+ /* Allocate net device */
+ netdev = alloc_ibdev ( sizeof ( *mlx ) );
+ if ( ! netdev )
+ return -ENOMEM;
+ netdev_init ( netdev, &mlx_operations );
+ mlx = netdev->priv;
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( mlx, 0, sizeof ( *mlx ) );
+
+ /* Fix up PCI device */
+ adjust_pci_device ( pci );
+
+ /* Initialise hardware */
+ if ( ( rc = ipoib_init ( pci ) ) != 0 )
+ goto err_ipoib_init;
+ memcpy ( netdev->ll_addr, ipoib_data.port_gid_raw, IB_ALEN );
+
+ /* Register network device */
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register_netdev;
+
+ return 0;
+
+ err_register_netdev:
+ err_ipoib_init:
+ ipoib_close(0);
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ return rc;
+}
+
+static struct pci_device_id mlx_nics[] = {
PCI_ROM(0x15b3, 0x6282, "MT25218", "MT25218 HCA driver"),
PCI_ROM(0x15b3, 0x6274, "MT25204", "MT25204 HCA driver"),
};
-PCI_DRIVER ( mt25218_driver, mt25218_nics, PCI_NO_CLASS );
-
-DRIVER ( "MT25218", nic_driver, pci_driver, mt25218_driver,
- mt25218_probe, mt25218_disable );
+struct pci_driver mlx_driver __pci_driver = {
+ .ids = mlx_nics,
+ .id_count = ( sizeof ( mlx_nics ) / sizeof ( mlx_nics[0] ) ),
+ .probe = mlx_probe,
+ .remove = mlx_remove,
+};
--- /dev/null
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <gpxe/if_arp.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/infiniband.h>
+
+/** @file
+ *
+ * Infiniband protocol
+ *
+ */
+
+/** Infiniband broadcast MAC address */
+static uint8_t ib_broadcast[IB_ALEN] = { 0xff, };
+
+/**
+ * Transmit Infiniband packet
+ *
+ * @v iobuf I/O buffer
+ * @v netdev Network device
+ * @v net_protocol Network-layer protocol
+ * @v ll_dest Link-layer destination address
+ *
+ * Prepends the Infiniband link-layer header and transmits the packet.
+ */
+static int ib_tx ( struct io_buffer *iobuf, struct net_device *netdev,
+ struct net_protocol *net_protocol, const void *ll_dest ) {
+ struct ibhdr *ibhdr = iob_push ( iobuf, sizeof ( *ibhdr ) );
+
+
+ /* Build Infiniband header */
+ memcpy ( ibhdr->peer, ll_dest, IB_ALEN );
+ ibhdr->proto = net_protocol->net_proto;
+ ibhdr->reserved = 0;
+
+ /* Hand off to network device */
+ return netdev_tx ( netdev, iobuf );
+}
+
+/**
+ * Process received Infiniband packet
+ *
+ * @v iobuf I/O buffer
+ * @v netdev Network device
+ *
+ * Strips off the Infiniband link-layer header and passes up to the
+ * network-layer protocol.
+ */
+static int ib_rx ( struct io_buffer *iobuf, struct net_device *netdev ) {
+ struct ibhdr *ibhdr = iobuf->data;
+
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( *ibhdr ) ) {
+ DBG ( "Infiniband packet too short (%d bytes)\n",
+ iob_len ( iobuf ) );
+ free_iob ( iobuf );
+ return -EINVAL;
+ }
+
+ /* Strip off Infiniband header */
+ iob_pull ( iobuf, sizeof ( *ibhdr ) );
+
+ /* Hand off to network-layer protocol */
+ return net_rx ( iobuf, netdev, ibhdr->proto, ibhdr->peer );
+}
+
+/**
+ * Transcribe Infiniband address
+ *
+ * @v ll_addr Link-layer address
+ * @ret string Link-layer address in human-readable format
+ */
+const char * ib_ntoa ( const void *ll_addr ) {
+ static char buf[61];
+ const uint8_t *ib_addr = ll_addr;
+ unsigned int i;
+ char *p = buf;
+
+ for ( i = 0 ; i < IB_ALEN ; i++ ) {
+ p += sprintf ( p, ":%02x", ib_addr[i] );
+ }
+ return ( buf + 1 );
+}
+
+/** Infiniband protocol */
+struct ll_protocol infiniband_protocol __ll_protocol = {
+ .name = "Infiniband",
+ .ll_proto = htons ( ARPHRD_INFINIBAND ),
+ .ll_addr_len = IB_ALEN,
+ .ll_header_len = IB_HLEN,
+ .ll_broadcast = ib_broadcast,
+ .tx = ib_tx,
+ .rx = ib_rx,
+ .ntoa = ib_ntoa,
+};