// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
* Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
*/
#include <linux/dma-mapping.h>
#include <net/addrconf.h>
#include <rdma/uverbs_ioctl.h>
#include "rxe.h"
#include "rxe_loc.h"
#include "rxe_queue.h"
#include "rxe_hw_counters.h"
static int rxe_query_device(struct ib_device *dev,
struct ib_device_attr *attr,
struct ib_udata *uhw)
{
struct rxe_dev *rxe = to_rdev(dev);
if (uhw->inlen || uhw->outlen)
return -EINVAL;
*attr = rxe->attr;
return 0;
}
static int rxe_query_port(struct ib_device *dev,
u8 port_num, struct ib_port_attr *attr)
{
struct rxe_dev *rxe = to_rdev(dev);
struct rxe_port *port;
int rc;
port = &rxe->port;
/* *attr being zeroed by the caller, avoid zeroing it here */
*attr = port->attr;
mutex_lock(&rxe->usdev_lock);
rc = ib_get_eth_speed(dev, port_num, &attr->active_speed,
&attr->active_width);
if (attr->state == IB_PORT_ACTIVE)
attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
else if (dev_get_flags(rxe->ndev) & IFF_UP)
attr->phys_state = IB_PORT_PHYS_STATE_POLLING;
else
attr->phys_state = IB_PORT_PHYS_STATE_DISABLED;
mutex_unlock(&rxe->usdev_lock);
return rc;
}
static int rxe_query_pkey(struct ib_device *device,
u8 port_num, u16 index, u16 *pkey)
{
if (index > 0)
return -EINVAL;
*pkey = IB_DEFAULT_PKEY_FULL;
return 0;
}
static int rxe_modify_device(struct ib_device *dev,
int mask, struct ib_device_modify *attr)
{
struct rxe_dev *rxe = to_rdev(dev);
if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID |
IB_DEVICE_MODIFY_NODE_DESC))
return -EOPNOTSUPP;
if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID)
rxe->attr.sys_image_guid = cpu_to_be64(attr->sys_image_guid);
if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
memcpy(rxe->ib_dev.node_desc,
attr->node_desc, sizeof(rxe->ib_dev.node_desc));
}
return 0;
}
static int rxe_modify_port(struct ib_device *dev,
u8 port_num, int mask, struct ib_port_modify *attr)
{
struct rxe_dev *rxe = to_rdev(dev);
struct rxe_port *port;
port = &rxe->port;
port->attr.port_cap_flags |= attr->set_port_cap_mask;
port->attr.port_cap_flags &= ~attr->clr_port_cap_mask;
if (mask & IB_PORT_RESET_QKEY_CNTR)
port->attr.qkey_viol_cntr = 0;
return 0;
}
static enum rdma_link_layer rxe_get_link_layer(struct ib_device *dev,
u8 port_num)
{
return IB_LINK_LAYER_ETHERNET;
}
static int rxe_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
{
struct rxe_dev *rxe = to_rdev(uctx->device);
struct rxe_ucontext *uc = to_ruc(uctx);
return rxe_add_to_pool(&rxe->uc_pool, &uc->pelem);
}
static void rxe_dealloc_ucontext(struct ib_ucontext *ibuc)
{
struct rxe_ucontext *uc = to_ruc(ibuc);
rxe_drop_ref(uc);
}
static int rxe_port_immutable(struct ib_device *dev, u8 port_num,
struct ib_port_immutable *immutable)
{
int err;
struct ib_port_attr attr;
immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
err = ib_query_port(dev, port_num, &attr);
if (err)