// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022, Microsoft Corporation. All rights reserved.
*/
#include "mana_ib.h"
void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd,
u32 port)
{
struct mana_port_context *mpc;
struct net_device *ndev;
ndev = mana_ib_get_netdev(&dev->ib_dev, port);
mpc = netdev_priv(ndev);
mutex_lock(&pd->vport_mutex);
pd->vport_use_count--;
WARN_ON(pd->vport_use_count < 0);
if (!pd->vport_use_count)
mana_uncfg_vport(mpc);
mutex_unlock(&pd->vport_mutex);
}
int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd,
u32 doorbell_id)
{
struct mana_port_context *mpc;
struct net_device *ndev;
int err;
ndev = mana_ib_get_netdev(&dev->ib_dev, port);
mpc = netdev_priv(ndev);
mutex_lock(&pd->vport_mutex);
pd->vport_use_count++;
if (pd->vport_use_count > 1) {
ibdev_dbg(&dev->ib_dev,
"Skip as this PD is already configured vport\n");
mutex_unlock(&pd->vport_mutex);
return 0;
}
err = mana_cfg_vport(mpc, pd->pdn, doorbell_id);
if (err) {
pd->vport_use_count--;
mutex_unlock(&pd->vport_mutex);
ibdev_dbg(&dev->ib_dev, "Failed to configure vPort %d\n", err);
return err;
}
mutex_unlock(&pd->vport_mutex);
pd->tx_shortform_allowed = mpc->tx_shortform_allowed;
pd->tx_vp_offset = mpc->tx_vp_offset;
ibdev_dbg(&dev->ib_dev, "vport handle %llx pdid %x doorbell_id %x\n",
mpc->port_handle, pd->pdn, doorbell_id);
return 0;
}
int mana_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct mana_ib_pd *pd = container_of(ibpd, struct mana_ib_pd, ibpd);
struct ib_device *ibdev = ibpd->device;
struct gdma_create_pd_resp resp = {};
struct gdma_create_pd_req req = {};
enum gdma_pd_flags flags = 0;
struct mana_ib_dev *dev;
struct gdma_context *gc;
int err;
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
gc = mdev_to_gc(dev);
mana_gd_init_req_hdr(&req.hdr, GDMA_CREATE_PD, sizeof(req),
sizeof(resp));
req.flags = flags;
err = mana_gd_send_request(gc, sizeof(req), &req,
sizeof(resp), &resp);
if (err || resp.hdr.status) {
ibdev_dbg(&dev->ib_dev,
"Failed to get pd_id err %d status %u\n", err,
resp.hdr.status);
if (!err)
err = -EPROTO;
return err;
}
pd->pd_handle = resp.pd_handle;
pd->pdn = resp.pd_id;
ibdev_dbg(&dev->ib_dev, "pd_handle 0x%llx pd_id %d\n",
pd->pd_handle, pd->pdn);
mutex_init(&pd->vport_mutex);
pd->vport_use_count = 0;
return 0;
}
int mana_ib_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct mana_ib_pd *pd = container_of(ibpd, struct mana_ib_pd, ibpd);
struct ib_device *ibdev = ibpd->device;
struct gdma_destory_pd_resp resp = {};
struct gdma_destroy_pd_req req = {};
struct mana_ib_dev *dev;
struct gdma_context *gc;
int err;
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
gc = mdev_to_gc(dev);
mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_PD, sizeof(req),
sizeof(resp));
req.pd_handle = pd->pd_handle;
err = mana_gd_send_request(gc, sizeof(req), &req,
sizeof(resp), &resp);
if (err || resp.hdr.status) {
ibdev_dbg(&dev->ib_dev,
"Failed to destroy pd_handle 0x%llx err %d status %u",
pd->pd_handle, err, resp.hdr.status);
if (!err)
err = -EPROTO;
}
return err;
}
static int mana_gd_destroy_doorbell_page(struct gdma_context *gc,
int doorbell_page)
{
struct gdma_destroy_resource_range_req req = {};
struct gdma_resp_hdr resp = {};
int err;
mana_gd_init_req_hdr(&req.hdr, GDMA_DESTROY_RESOURCE_RANGE,
sizeof(req), sizeof(resp));
req.resource_type = GDMA_RESOURCE_DOORBELL_PAGE;
req.num_resources = 1;
req.allocated_resources = doorbell_page;
err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
if (err || resp.status) {
dev_err(gc->dev,
"Failed to destroy doorbell page: ret %d, 0x%x\n",
err, resp.status);
return err ?: -EPROTO;
}
return 0;
}
static int mana_gd_allocate_doorbell_page(struct gdma_context *gc,
int *doorbell_page)
{
struct gdma_allocate_resource_range_req req = {};
struct gdma_allocate_resource_range_resp resp = {};
int err;
mana_gd_init_req_hdr(&req.hdr