[ofw] [RFC] [PATCH 3/3] libibverbs: winof port of device routines

Sean Hefty sean.hefty at intel.com
Mon Jun 2 10:31:13 PDT 2008


Implementation for libibverbs device related calls (get device list, open/
close device, get event, etc.).

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
/*
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
 *
 * This software is available to you under the OpenIB.org BSD license
 * below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * 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 AWV
 * 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.
 */

#include <stdio.h>
#include <infiniband/verbs.h>
#include <rdma/winverbs.h>

IWVProvider *prov;

struct verbs_device
{
	struct ibv_device	device;
	uint64_t			guid;
	uint8_t				phys_port_cnt;
};

struct verbs_port
{
	OVERLAPPED			overlap;
	DWORD				event_flag;
};

#define EVENT_PORT_NONE	-1

struct verbs_context
{
	struct ibv_context	context;
	struct verbs_device	device;
	HANDLE				*event;
	struct verbs_port	*port;
	uint8_t				event_port_num;
};

__declspec(dllexport)
struct ibv_device **ibv_get_device_list(int *num)
{
	WV_DEVICE_ATTRIBUTES attr;
	struct verbs_device *dev_array;
	struct ibv_device **pdev_array;
	UINT64 *guid;
	SIZE_T size, cnt;
	HRESULT hr;

	if (prov == NULL) {
		hr = WvGetObject(IID_IWVProvider, (LPVOID*) &prov);
		if (FAILED(hr)) {
			goto err1;
		}	
	}

	cnt = 0;
	size = sizeof(UINT64);

	while ((size / sizeof(UINT64)) > cnt) {
		if (cnt > 0) {
			delete guid;
		}

		cnt = size / sizeof(UINT64);
		guid = new UINT64[cnt];
		if (guid == NULL) {
			goto err1;
		}

		hr = prov->QueryDeviceList(guid, &size);
		if (FAILED(hr)) {
			goto err2;
		}
	}

	*num = (int) (size / sizeof(UINT64));
	dev_array = new struct verbs_device[*num];
	pdev_array = new struct ibv_device*[*num];
	if (dev_array == NULL || pdev_array == NULL) {
		goto err2;
	}

	for (cnt = 0; cnt < (SIZE_T) *num; cnt++) {
		pdev_array[cnt] = &dev_array[cnt].device;
		hr = prov->QueryDevice(guid[cnt], &attr);
		if (FAILED(hr)) {
			goto err3;
		}

		sscanf(dev_array[cnt].device.name, "ibv_device 0x%x", guid[cnt]);
		dev_array[cnt].device.node_type = IBV_NODE_UNKNOWN;
		dev_array[cnt].device.transport_type = (ibv_transport_type) attr.DeviceType;
		dev_array[cnt].guid = guid[cnt];
		dev_array[cnt].phys_port_cnt = attr.PhysPortCount;
	}

	return pdev_array;

err3:
	ibv_free_device_list(pdev_array);
err2:
	delete guid;
err1:
	*num = 0;
	return NULL;
}

__declspec(dllexport)
void ibv_free_device_list(struct ibv_device **list)
{
	delete CONTAINING_RECORD(list[0], struct verbs_device, device);
	delete list;
}

__declspec(dllexport)
const char *ibv_get_device_name(struct ibv_device *device)
{
	return device->name;
}

__declspec(dllexport)
uint64_t ibv_get_device_guid(struct ibv_device *device)
{
	return CONTAINING_RECORD(device, struct verbs_device, device)->guid;
}

__declspec(dllexport)
struct ibv_context *ibv_open_device(struct ibv_device *device)
{
	struct verbs_device *vdev;
	struct verbs_context *vcontext;
	HRESULT hr;
	int i;

	vdev = CONTAINING_RECORD(device, struct verbs_device, device);
	vcontext = new struct verbs_context;
	if (vcontext == NULL) {
		return NULL;
	}
	memcpy(&vcontext->device, vdev, sizeof(struct verbs_device));
	vcontext->event_port_num = EVENT_PORT_NONE;

	vcontext->port = new struct verbs_port[vdev->phys_port_cnt];
	if (vcontext->port == NULL) {
		goto err1;
	}

	vcontext->event = new HANDLE[vdev->phys_port_cnt];
	if (vcontext->event == NULL) {
		goto err2;
	}

	hr = prov->OpenDevice(vdev->guid, &vcontext->context.cmd_if);
	if (FAILED(hr)) {
		goto err3;
	}

	for (i = 0; i < vdev->phys_port_cnt; i++) {
		vcontext->event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
		if (vcontext->event[i] == NULL) {
			goto err4;
		}
		vcontext->port[i].overlap.hEvent = vcontext->event[i];
		vcontext->port[i].event_flag = 0;

		vcontext->context.cmd_if->Notify((UINT8) i,
										 &vcontext->port[i].overlap,
										 &vcontext->port[i].event_flag);
	}

	return &vcontext->context;

err4:
	while (--i >= 0) {
		CloseHandle(vcontext->event[i]);
	}
err3:
	delete vcontext->event;
err2:
	delete vcontext->port;
err1:
	delete vcontext;
	return NULL;
}

__declspec(dllexport)
int ibv_close_device(struct ibv_context *context)
{
	struct verbs_context *vcontext;
	int i;

	vcontext = CONTAINING_RECORD(context, struct verbs_context, context);
	context->cmd_if->CancelOverlappedRequests();

	for (i = 0; i < vcontext->device.phys_port_cnt; i++) {
		CloseHandle(vcontext->event[i]);
	}

	context->cmd_if->Release();
	delete vcontext->event;
	delete vcontext->port;
	delete vcontext;
	return 0;
}

static enum ibv_event_type ibv_get_port_event_state(struct verbs_context *vcontext)
{
	WV_PORT_ATTRIBUTES attr;
	HRESULT hr;

	hr = vcontext->context.cmd_if->QueryPort(vcontext->event_port_num, &attr);
	if (FAILED(hr)) {
		return IBV_EVENT_PORT_ERR;
	}

	return (attr.State == WvPortActive) ?
		   IBV_EVENT_PORT_ACTIVE : IBV_EVENT_PORT_ERR;
}

static int ibv_report_port_event(struct verbs_context *vcontext,
								 struct ibv_async_event *event)
{
	struct verbs_port *port;
	int ret = 0;

	port = &vcontext->port[vcontext->event_port_num];
	event->element.port_num = vcontext->event_port_num;

	if (port->event_flag & WV_EVENT_ERROR) {
		event->event_type = IBV_EVENT_DEVICE_FATAL;
		port->event_flag = 0;
	} else if (port->event_flag & WV_EVENT_STATE) {
		event->event_type = ibv_get_port_event_state(vcontext);
		port->event_flag = 0;
	} else if (port->event_flag & WV_EVENT_MANAGEMENT) {
		event->event_type = IBV_EVENT_SM_CHANGE;
		port->event_flag = 0;
	} else if (port->event_flag & WV_EVENT_LINK_ADDRESS) {
		event->event_type = IBV_EVENT_LID_CHANGE;
		port->event_flag &= ~WV_EVENT_LINK_ADDRESS;
	} else if (port->event_flag & WV_EVENT_PARTITION) {
		event->event_type = IBV_EVENT_PKEY_CHANGE;
		port->event_flag &= ~WV_EVENT_PARTITION;
	} else {
		port->event_flag = 0;
		ret = -1;
	}
	
	if (port->event_flag == 0) {
		vcontext->context.cmd_if->Notify(vcontext->event_port_num,
										 &port->overlap, &port->event_flag);
		vcontext->event_port_num = EVENT_PORT_NONE;
	}
	return ret;
}

__declspec(dllexport)
int ibv_get_async_event(struct ibv_context *context,
						struct ibv_async_event *event)
{
	struct verbs_context *vcontext;
	HRESULT hr;
	int i;

	vcontext = CONTAINING_RECORD(context, struct verbs_context, context);
	if (vcontext->event_port_num != EVENT_PORT_NONE) {
		if (ibv_report_port_event(vcontext, event) == 0) {
			return 0;
		}
	}

	hr = WaitForMultipleObjects(vcontext->device.phys_port_cnt,
								vcontext->event, FALSE, context->timeout);
	if (hr == WAIT_TIMEOUT) {
		return hr;
	} else if (hr == WAIT_FAILED) {
		return HRESULT_FROM_WIN32(GetLastError());
	}

	vcontext->event_port_num = (UINT8) hr;
	return ibv_report_port_event(vcontext, event);
}

__declspec(dllexport)
void ibv_ack_async_event(struct ibv_async_event *event)
{
	// Only device/port level events are currently supported
	// nothing to do here at the moment
}





More information about the ofw mailing list