162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2016 Hisilicon Limited.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/pci.h>
3462306a36Sopenharmony_ci#include "hns_roce_device.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_civoid hns_roce_init_pd_table(struct hns_roce_dev *hr_dev)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct hns_roce_ida *pd_ida = &hr_dev->pd_ida;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ida_init(&pd_ida->ida);
4162306a36Sopenharmony_ci	pd_ida->max = hr_dev->caps.num_pds - 1;
4262306a36Sopenharmony_ci	pd_ida->min = hr_dev->caps.reserved_pds;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint hns_roce_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct ib_device *ib_dev = ibpd->device;
4862306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
4962306a36Sopenharmony_ci	struct hns_roce_ida *pd_ida = &hr_dev->pd_ida;
5062306a36Sopenharmony_ci	struct hns_roce_pd *pd = to_hr_pd(ibpd);
5162306a36Sopenharmony_ci	int ret = 0;
5262306a36Sopenharmony_ci	int id;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	id = ida_alloc_range(&pd_ida->ida, pd_ida->min, pd_ida->max,
5562306a36Sopenharmony_ci			     GFP_KERNEL);
5662306a36Sopenharmony_ci	if (id < 0) {
5762306a36Sopenharmony_ci		ibdev_err(ib_dev, "failed to alloc pd, id = %d.\n", id);
5862306a36Sopenharmony_ci		return -ENOMEM;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	pd->pdn = (unsigned long)id;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (udata) {
6362306a36Sopenharmony_ci		struct hns_roce_ib_alloc_pd_resp resp = {.pdn = pd->pdn};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		ret = ib_copy_to_udata(udata, &resp,
6662306a36Sopenharmony_ci				       min(udata->outlen, sizeof(resp)));
6762306a36Sopenharmony_ci		if (ret) {
6862306a36Sopenharmony_ci			ida_free(&pd_ida->ida, id);
6962306a36Sopenharmony_ci			ibdev_err(ib_dev, "failed to copy to udata, ret = %d\n", ret);
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return ret;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciint hns_roce_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	ida_free(&hr_dev->pd_ida.ida, (int)to_hr_pd(pd)->pdn);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciint hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct hns_roce_ida *uar_ida = &hr_dev->uar_ida;
8862306a36Sopenharmony_ci	int id;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Using bitmap to manager UAR index */
9162306a36Sopenharmony_ci	id = ida_alloc_range(&uar_ida->ida, uar_ida->min, uar_ida->max,
9262306a36Sopenharmony_ci			     GFP_KERNEL);
9362306a36Sopenharmony_ci	if (id < 0) {
9462306a36Sopenharmony_ci		ibdev_err(&hr_dev->ib_dev, "failed to alloc uar id(%d).\n", id);
9562306a36Sopenharmony_ci		return -ENOMEM;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	uar->logic_idx = (unsigned long)id;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (uar->logic_idx > 0 && hr_dev->caps.phy_num_uars > 1)
10062306a36Sopenharmony_ci		uar->index = (uar->logic_idx - 1) %
10162306a36Sopenharmony_ci			     (hr_dev->caps.phy_num_uars - 1) + 1;
10262306a36Sopenharmony_ci	else
10362306a36Sopenharmony_ci		uar->index = 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	uar->pfn = ((pci_resource_start(hr_dev->pci_dev, 2)) >> PAGE_SHIFT);
10662306a36Sopenharmony_ci	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_DIRECT_WQE)
10762306a36Sopenharmony_ci		hr_dev->dwqe_page = pci_resource_start(hr_dev->pci_dev, 4);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_civoid hns_roce_init_uar_table(struct hns_roce_dev *hr_dev)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct hns_roce_ida *uar_ida = &hr_dev->uar_ida;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	ida_init(&uar_ida->ida);
11762306a36Sopenharmony_ci	uar_ida->max = hr_dev->caps.num_uars - 1;
11862306a36Sopenharmony_ci	uar_ida->min = hr_dev->caps.reserved_uars;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic int hns_roce_xrcd_alloc(struct hns_roce_dev *hr_dev, u32 *xrcdn)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct hns_roce_ida *xrcd_ida = &hr_dev->xrcd_ida;
12462306a36Sopenharmony_ci	int id;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	id = ida_alloc_range(&xrcd_ida->ida, xrcd_ida->min, xrcd_ida->max,
12762306a36Sopenharmony_ci			     GFP_KERNEL);
12862306a36Sopenharmony_ci	if (id < 0) {
12962306a36Sopenharmony_ci		ibdev_err(&hr_dev->ib_dev, "failed to alloc xrcdn(%d).\n", id);
13062306a36Sopenharmony_ci		return -ENOMEM;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	*xrcdn = (u32)id;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_civoid hns_roce_init_xrcd_table(struct hns_roce_dev *hr_dev)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct hns_roce_ida *xrcd_ida = &hr_dev->xrcd_ida;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	ida_init(&xrcd_ida->ida);
14262306a36Sopenharmony_ci	xrcd_ida->max = hr_dev->caps.num_xrcds - 1;
14362306a36Sopenharmony_ci	xrcd_ida->min = hr_dev->caps.reserved_xrcds;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciint hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ib_xrcd->device);
14962306a36Sopenharmony_ci	struct hns_roce_xrcd *xrcd = to_hr_xrcd(ib_xrcd);
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC))
15362306a36Sopenharmony_ci		return -EOPNOTSUPP;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ret = hns_roce_xrcd_alloc(hr_dev, &xrcd->xrcdn);
15662306a36Sopenharmony_ci	if (ret)
15762306a36Sopenharmony_ci		return ret;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciint hns_roce_dealloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct hns_roce_dev *hr_dev = to_hr_dev(ib_xrcd->device);
16562306a36Sopenharmony_ci	u32 xrcdn = to_hr_xrcd(ib_xrcd)->xrcdn;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	ida_free(&hr_dev->xrcd_ida.ida, (int)xrcdn);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
171