Commit 443b9a14 authored by Serge Semin's avatar Serge Semin Committed by Jon Mason

NTB: Alter MW API to support multi-ports devices

Multi-port NTB devices permit to share a memory between all accessible peers.
Memory Windows API is altered to correspondingly initialize and map memory
windows for such devices:
 ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
for shared buffer with specified peer device.
 ntb_mw_get_align(pidx, widx); - get alignment and size restriction parameters
to properly allocate inbound memory region.
 ntb_peer_mw_count(); - get number of outbound memory windows.
 ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window

If hardware supports inbound translation configured on the local ntb port:
 ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
memory window so a peer device could access it.
 ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
memory window.

If hardware supports outbound translation configured on the peer ntb port:
 ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
window retrieved from a peer device
 ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
outbound memory window
Signed-off-by: default avatarSerge Semin <fancer.lancer@gmail.com>
Acked-by: default avatarAllen Hubbe <Allen.Hubbe@dell.com>
Signed-off-by: default avatarJon Mason <jdmason@kudzu.us>
parent 4e8c11b7
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved. * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -13,6 +14,7 @@ ...@@ -13,6 +14,7 @@
* BSD LICENSE * BSD LICENSE
* *
* Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved. * Copyright (C) 2016 Advanced Micro Devices, Inc. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -79,40 +81,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx) ...@@ -79,40 +81,42 @@ static int ndev_mw_to_bar(struct amd_ntb_dev *ndev, int idx)
return 1 << idx; return 1 << idx;
} }
static int amd_ntb_mw_count(struct ntb_dev *ntb) static int amd_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{ {
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
return ntb_ndev(ntb)->mw_count; return ntb_ndev(ntb)->mw_count;
} }
static int amd_ntb_mw_get_range(struct ntb_dev *ntb, int idx, static int amd_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
phys_addr_t *base, resource_size_t *addr_align,
resource_size_t *size, resource_size_t *size_align,
resource_size_t *align, resource_size_t *size_max)
resource_size_t *align_size)
{ {
struct amd_ntb_dev *ndev = ntb_ndev(ntb); struct amd_ntb_dev *ndev = ntb_ndev(ntb);
int bar; int bar;
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
bar = ndev_mw_to_bar(ndev, idx); bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0) if (bar < 0)
return bar; return bar;
if (base) if (addr_align)
*base = pci_resource_start(ndev->ntb.pdev, bar); *addr_align = SZ_4K;
if (size)
*size = pci_resource_len(ndev->ntb.pdev, bar);
if (align) if (size_align)
*align = SZ_4K; *size_align = 1;
if (align_size) if (size_max)
*align_size = 1; *size_max = pci_resource_len(ndev->ntb.pdev, bar);
return 0; return 0;
} }
static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size) dma_addr_t addr, resource_size_t size)
{ {
struct amd_ntb_dev *ndev = ntb_ndev(ntb); struct amd_ntb_dev *ndev = ntb_ndev(ntb);
...@@ -122,6 +126,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, ...@@ -122,6 +126,9 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base_addr, limit, reg_val; u64 base_addr, limit, reg_val;
int bar; int bar;
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
bar = ndev_mw_to_bar(ndev, idx); bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0) if (bar < 0)
return bar; return bar;
...@@ -284,6 +291,31 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb) ...@@ -284,6 +291,31 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
return 0; return 0;
} }
static int amd_ntb_peer_mw_count(struct ntb_dev *ntb)
{
/* The same as for inbound MWs */
return ntb_ndev(ntb)->mw_count;
}
static int amd_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
phys_addr_t *base, resource_size_t *size)
{
struct amd_ntb_dev *ndev = ntb_ndev(ntb);
int bar;
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
if (base)
*base = pci_resource_start(ndev->ntb.pdev, bar);
if (size)
*size = pci_resource_len(ndev->ntb.pdev, bar);
return 0;
}
static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb) static u64 amd_ntb_db_valid_mask(struct ntb_dev *ntb)
{ {
return ntb_ndev(ntb)->db_valid_mask; return ntb_ndev(ntb)->db_valid_mask;
...@@ -431,8 +463,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb, ...@@ -431,8 +463,10 @@ static int amd_ntb_peer_spad_write(struct ntb_dev *ntb,
static const struct ntb_dev_ops amd_ntb_ops = { static const struct ntb_dev_ops amd_ntb_ops = {
.mw_count = amd_ntb_mw_count, .mw_count = amd_ntb_mw_count,
.mw_get_range = amd_ntb_mw_get_range, .mw_get_align = amd_ntb_mw_get_align,
.mw_set_trans = amd_ntb_mw_set_trans, .mw_set_trans = amd_ntb_mw_set_trans,
.peer_mw_count = amd_ntb_peer_mw_count,
.peer_mw_get_addr = amd_ntb_peer_mw_get_addr,
.link_is_up = amd_ntb_link_is_up, .link_is_up = amd_ntb_link_is_up,
.link_enable = amd_ntb_link_enable, .link_enable = amd_ntb_link_enable,
.link_disable = amd_ntb_link_disable, .link_disable = amd_ntb_link_disable,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* *
* Copyright(c) 2012 Intel Corporation. All rights reserved. * Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
* *
* Copyright(c) 2012 Intel Corporation. All rights reserved. * Copyright(c) 2012 Intel Corporation. All rights reserved.
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -1035,20 +1037,26 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev) ...@@ -1035,20 +1037,26 @@ static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev)
debugfs_remove_recursive(ndev->debugfs_dir); debugfs_remove_recursive(ndev->debugfs_dir);
} }
static int intel_ntb_mw_count(struct ntb_dev *ntb) static int intel_ntb_mw_count(struct ntb_dev *ntb, int pidx)
{ {
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
return ntb_ndev(ntb)->mw_count; return ntb_ndev(ntb)->mw_count;
} }
static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx, static int intel_ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int idx,
phys_addr_t *base, resource_size_t *addr_align,
resource_size_t *size, resource_size_t *size_align,
resource_size_t *align, resource_size_t *size_max)
resource_size_t *align_size)
{ {
struct intel_ntb_dev *ndev = ntb_ndev(ntb); struct intel_ntb_dev *ndev = ntb_ndev(ntb);
resource_size_t bar_size, mw_size;
int bar; int bar;
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
if (idx >= ndev->b2b_idx && !ndev->b2b_off) if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1; idx += 1;
...@@ -1056,24 +1064,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx, ...@@ -1056,24 +1064,26 @@ static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx,
if (bar < 0) if (bar < 0)
return bar; return bar;
if (base) bar_size = pci_resource_len(ndev->ntb.pdev, bar);
*base = pci_resource_start(ndev->ntb.pdev, bar) +
(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
if (size) if (idx == ndev->b2b_idx)
*size = pci_resource_len(ndev->ntb.pdev, bar) - mw_size = bar_size - ndev->b2b_off;
(idx == ndev->b2b_idx ? ndev->b2b_off : 0); else
mw_size = bar_size;
if (addr_align)
*addr_align = pci_resource_len(ndev->ntb.pdev, bar);
if (align) if (size_align)
*align = pci_resource_len(ndev->ntb.pdev, bar); *size_align = 1;
if (align_size) if (size_max)
*align_size = 1; *size_max = mw_size;
return 0; return 0;
} }
static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size) dma_addr_t addr, resource_size_t size)
{ {
struct intel_ntb_dev *ndev = ntb_ndev(ntb); struct intel_ntb_dev *ndev = ntb_ndev(ntb);
...@@ -1083,6 +1093,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, ...@@ -1083,6 +1093,9 @@ static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val; u64 base, limit, reg_val;
int bar; int bar;
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
if (idx >= ndev->b2b_idx && !ndev->b2b_off) if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1; idx += 1;
...@@ -1249,6 +1262,36 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb) ...@@ -1249,6 +1262,36 @@ static int intel_ntb_link_disable(struct ntb_dev *ntb)
return 0; return 0;
} }
static int intel_ntb_peer_mw_count(struct ntb_dev *ntb)
{
/* Numbers of inbound and outbound memory windows match */
return ntb_ndev(ntb)->mw_count;
}
static int intel_ntb_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
phys_addr_t *base, resource_size_t *size)
{
struct intel_ntb_dev *ndev = ntb_ndev(ntb);
int bar;
if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1;
bar = ndev_mw_to_bar(ndev, idx);
if (bar < 0)
return bar;
if (base)
*base = pci_resource_start(ndev->ntb.pdev, bar) +
(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
if (size)
*size = pci_resource_len(ndev->ntb.pdev, bar) -
(idx == ndev->b2b_idx ? ndev->b2b_off : 0);
return 0;
}
static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb) static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb)
{ {
return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB); return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB);
...@@ -1902,7 +1945,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb, ...@@ -1902,7 +1945,7 @@ static int intel_ntb3_link_enable(struct ntb_dev *ntb,
return 0; return 0;
} }
static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx, static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
dma_addr_t addr, resource_size_t size) dma_addr_t addr, resource_size_t size)
{ {
struct intel_ntb_dev *ndev = ntb_ndev(ntb); struct intel_ntb_dev *ndev = ntb_ndev(ntb);
...@@ -1912,6 +1955,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx, ...@@ -1912,6 +1955,9 @@ static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx,
u64 base, limit, reg_val; u64 base, limit, reg_val;
int bar; int bar;
if (pidx != NTB_DEF_PEER_IDX)
return -EINVAL;
if (idx >= ndev->b2b_idx && !ndev->b2b_off) if (idx >= ndev->b2b_idx && !ndev->b2b_off)
idx += 1; idx += 1;
...@@ -2906,8 +2952,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = { ...@@ -2906,8 +2952,10 @@ static const struct intel_ntb_xlat_reg skx_sec_xlat = {
/* operations for primary side of local ntb */ /* operations for primary side of local ntb */
static const struct ntb_dev_ops intel_ntb_ops = { static const struct ntb_dev_ops intel_ntb_ops = {
.mw_count = intel_ntb_mw_count, .mw_count = intel_ntb_mw_count,
.mw_get_range = intel_ntb_mw_get_range, .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb_mw_set_trans, .mw_set_trans = intel_ntb_mw_set_trans,
.peer_mw_count = intel_ntb_peer_mw_count,
.peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.link_is_up = intel_ntb_link_is_up, .link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb_link_enable, .link_enable = intel_ntb_link_enable,
.link_disable = intel_ntb_link_disable, .link_disable = intel_ntb_link_disable,
...@@ -2932,8 +2980,10 @@ static const struct ntb_dev_ops intel_ntb_ops = { ...@@ -2932,8 +2980,10 @@ static const struct ntb_dev_ops intel_ntb_ops = {
static const struct ntb_dev_ops intel_ntb3_ops = { static const struct ntb_dev_ops intel_ntb3_ops = {
.mw_count = intel_ntb_mw_count, .mw_count = intel_ntb_mw_count,
.mw_get_range = intel_ntb_mw_get_range, .mw_get_align = intel_ntb_mw_get_align,
.mw_set_trans = intel_ntb3_mw_set_trans, .mw_set_trans = intel_ntb3_mw_set_trans,
.peer_mw_count = intel_ntb_peer_mw_count,
.peer_mw_get_addr = intel_ntb_peer_mw_get_addr,
.link_is_up = intel_ntb_link_is_up, .link_is_up = intel_ntb_link_is_up,
.link_enable = intel_ntb3_link_enable, .link_enable = intel_ntb3_link_enable,
.link_disable = intel_ntb_link_disable, .link_disable = intel_ntb_link_disable,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
* BSD LICENSE * BSD LICENSE
* *
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
......
...@@ -673,7 +673,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw) ...@@ -673,7 +673,7 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
if (!mw->virt_addr) if (!mw->virt_addr)
return; return;
ntb_mw_clear_trans(nt->ndev, num_mw); ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->buff_size, dma_free_coherent(&pdev->dev, mw->buff_size,
mw->virt_addr, mw->dma_addr); mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0; mw->xlat_size = 0;
...@@ -730,7 +730,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, ...@@ -730,7 +730,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
} }
/* Notify HW the memory location of the receive buffer */ /* Notify HW the memory location of the receive buffer */
rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size); rc = ntb_mw_set_trans(nt->ndev, PIDX, num_mw, mw->dma_addr,
mw->xlat_size);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw); dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw);
ntb_free_mw(nt, num_mw); ntb_free_mw(nt, num_mw);
...@@ -1058,7 +1059,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) ...@@ -1058,7 +1059,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
int node; int node;
int rc, i; int rc, i;
mw_count = ntb_mw_count(ndev); mw_count = ntb_mw_count(ndev, PIDX);
if (!ndev->ops->mw_set_trans) {
dev_err(&ndev->dev, "Inbound MW based NTB API is required\n");
return -EINVAL;
}
if (ntb_db_is_unsafe(ndev)) if (ntb_db_is_unsafe(ndev))
dev_dbg(&ndev->dev, dev_dbg(&ndev->dev,
...@@ -1100,8 +1106,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) ...@@ -1100,8 +1106,13 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
for (i = 0; i < mw_count; i++) { for (i = 0; i < mw_count; i++) {
mw = &nt->mw_vec[i]; mw = &nt->mw_vec[i];
rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size, rc = ntb_mw_get_align(ndev, PIDX, i, &mw->xlat_align,
&mw->xlat_align, &mw->xlat_align_size); &mw->xlat_align_size, NULL);
if (rc)
goto err1;
rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr,
&mw->phys_size);
if (rc) if (rc)
goto err1; goto err1;
......
...@@ -455,7 +455,7 @@ static void perf_free_mw(struct perf_ctx *perf) ...@@ -455,7 +455,7 @@ static void perf_free_mw(struct perf_ctx *perf)
if (!mw->virt_addr) if (!mw->virt_addr)
return; return;
ntb_mw_clear_trans(perf->ntb, 0); ntb_mw_clear_trans(perf->ntb, PIDX, 0);
dma_free_coherent(&pdev->dev, mw->buf_size, dma_free_coherent(&pdev->dev, mw->buf_size,
mw->virt_addr, mw->dma_addr); mw->virt_addr, mw->dma_addr);
mw->xlat_size = 0; mw->xlat_size = 0;
...@@ -491,7 +491,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size) ...@@ -491,7 +491,7 @@ static int perf_set_mw(struct perf_ctx *perf, resource_size_t size)
mw->buf_size = 0; mw->buf_size = 0;
} }
rc = ntb_mw_set_trans(perf->ntb, 0, mw->dma_addr, mw->xlat_size); rc = ntb_mw_set_trans(perf->ntb, PIDX, 0, mw->dma_addr, mw->xlat_size);
if (rc) { if (rc) {
dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n"); dev_err(&perf->ntb->dev, "Unable to set mw0 translation\n");
perf_free_mw(perf); perf_free_mw(perf);
...@@ -562,8 +562,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf) ...@@ -562,8 +562,12 @@ static int perf_setup_mw(struct ntb_dev *ntb, struct perf_ctx *perf)
mw = &perf->mw; mw = &perf->mw;
rc = ntb_mw_get_range(ntb, 0, &mw->phys_addr, &mw->phys_size, rc = ntb_mw_get_align(ntb, PIDX, 0, &mw->xlat_align,
&mw->xlat_align, &mw->xlat_align_size); &mw->xlat_align_size, NULL);
if (rc)
return rc;
rc = ntb_peer_mw_get_addr(ntb, 0, &mw->phys_addr, &mw->phys_size);
if (rc) if (rc)
return rc; return rc;
...@@ -767,6 +771,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb) ...@@ -767,6 +771,11 @@ static int perf_probe(struct ntb_client *client, struct ntb_dev *ntb)
return -EIO; return -EIO;
} }
if (!ntb->ops->mw_set_trans) {
dev_err(&ntb->dev, "Need inbound MW based NTB API\n");
return -EINVAL;
}
if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT) if (ntb_peer_port_count(ntb) != NTB_DEF_PEER_CNT)
dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n"); dev_warn(&ntb->dev, "Multi-port NTB devices unsupported\n");
......
...@@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION); ...@@ -119,7 +119,8 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESCRIPTION); MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
#define MAX_MWS 16 /* It is rare to have hadrware with greater than six MWs */
#define MAX_MWS 6
/* Only two-ports devices are supported */ /* Only two-ports devices are supported */
#define PIDX NTB_DEF_PEER_IDX #define PIDX NTB_DEF_PEER_IDX
...@@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size) ...@@ -670,28 +671,27 @@ static int tool_setup_mw(struct tool_ctx *tc, int idx, size_t req_size)
{ {
int rc; int rc;
struct tool_mw *mw = &tc->mws[idx]; struct tool_mw *mw = &tc->mws[idx];
phys_addr_t base; resource_size_t size, align_addr, align_size;
resource_size_t size, align, align_size;
char buf[16]; char buf[16];
if (mw->peer) if (mw->peer)
return 0; return 0;
rc = ntb_mw_get_range(tc->ntb, idx, &base, &size, &align, rc = ntb_mw_get_align(tc->ntb, PIDX, idx, &align_addr,
&align_size); &align_size, &size);
if (rc) if (rc)
return rc; return rc;
mw->size = min_t(resource_size_t, req_size, size); mw->size = min_t(resource_size_t, req_size, size);
mw->size = round_up(mw->size, align); mw->size = round_up(mw->size, align_addr);
mw->size = round_up(mw->size, align_size); mw->size = round_up(mw->size, align_size);
mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size, mw->peer = dma_alloc_coherent(&tc->ntb->pdev->dev, mw->size,
&mw->peer_dma, GFP_KERNEL); &mw->peer_dma, GFP_KERNEL);
if (!mw->peer) if (!mw->peer || !IS_ALIGNED(mw->peer_dma, align_addr))
return -ENOMEM; return -ENOMEM;
rc = ntb_mw_set_trans(tc->ntb, idx, mw->peer_dma, mw->size); rc = ntb_mw_set_trans(tc->ntb, PIDX, idx, mw->peer_dma, mw->size);
if (rc) if (rc)
goto err_free_dma; goto err_free_dma;
...@@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx) ...@@ -718,7 +718,7 @@ static void tool_free_mw(struct tool_ctx *tc, int idx)
struct tool_mw *mw = &tc->mws[idx]; struct tool_mw *mw = &tc->mws[idx];
if (mw->peer) { if (mw->peer) {
ntb_mw_clear_trans(tc->ntb, idx); ntb_mw_clear_trans(tc->ntb, PIDX, idx);
dma_free_coherent(&tc->ntb->pdev->dev, mw->size, dma_free_coherent(&tc->ntb->pdev->dev, mw->size,
mw->peer, mw->peer,
mw->peer_dma); mw->peer_dma);
...@@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep, ...@@ -744,8 +744,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
phys_addr_t base; phys_addr_t base;
resource_size_t mw_size; resource_size_t mw_size;
resource_size_t align; resource_size_t align_addr;
resource_size_t align_size; resource_size_t align_size;
resource_size_t max_size;
buf_size = min_t(size_t, size, 512); buf_size = min_t(size_t, size, 512);
...@@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep, ...@@ -753,8 +754,9 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ntb_mw_get_range(mw->tc->ntb, mw->idx, ntb_mw_get_align(mw->tc->ntb, PIDX, mw->idx,
&base, &mw_size, &align, &align_size); &align_addr, &align_size, &max_size);
ntb_peer_mw_get_addr(mw->tc->ntb, mw->idx, &base, &mw_size);
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"Peer MW %d Information:\n", mw->idx); "Peer MW %d Information:\n", mw->idx);
...@@ -769,12 +771,16 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep, ...@@ -769,12 +771,16 @@ static ssize_t tool_peer_mw_trans_read(struct file *filep,
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"Alignment \t%lld\n", "Alignment \t%lld\n",
(unsigned long long)align); (unsigned long long)align_addr);
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"Size Alignment \t%lld\n", "Size Alignment \t%lld\n",
(unsigned long long)align_size); (unsigned long long)align_size);
off += scnprintf(buf + off, buf_size - off,
"Size Max \t%lld\n",
(unsigned long long)max_size);
off += scnprintf(buf + off, buf_size - off, off += scnprintf(buf + off, buf_size - off,
"Ready \t%c\n", "Ready \t%c\n",
(mw->peer) ? 'Y' : 'N'); (mw->peer) ? 'Y' : 'N');
...@@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx) ...@@ -829,8 +835,7 @@ static int tool_init_mw(struct tool_ctx *tc, int idx)
phys_addr_t base; phys_addr_t base;
int rc; int rc;
rc = ntb_mw_get_range(tc->ntb, idx, &base, &mw->win_size, rc = ntb_peer_mw_get_addr(tc->ntb, idx, &base, &mw->win_size);
NULL, NULL);
if (rc) if (rc)
return rc; return rc;
...@@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) ...@@ -915,6 +920,12 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
int rc; int rc;
int i; int i;
if (!ntb->ops->mw_set_trans) {
dev_dbg(&ntb->dev, "need inbound MW based NTB API\n");
rc = -EINVAL;
goto err_tc;
}
if (ntb_db_is_unsafe(ntb)) if (ntb_db_is_unsafe(ntb))
dev_dbg(&ntb->dev, "doorbell is unsafe\n"); dev_dbg(&ntb->dev, "doorbell is unsafe\n");
...@@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb) ...@@ -933,7 +944,7 @@ static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
tc->ntb = ntb; tc->ntb = ntb;
init_waitqueue_head(&tc->link_wq); init_waitqueue_head(&tc->link_wq);
tc->mw_count = min(ntb_mw_count(tc->ntb), MAX_MWS); tc->mw_count = min(ntb_mw_count(tc->ntb, PIDX), MAX_MWS);
for (i = 0; i < tc->mw_count; i++) { for (i = 0; i < tc->mw_count; i++) {
rc = tool_init_mw(tc, i); rc = tool_init_mw(tc, i);
if (rc) if (rc)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* GPL LICENSE SUMMARY * GPL LICENSE SUMMARY
* *
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
* BSD LICENSE * BSD LICENSE
* *
* Copyright (C) 2015 EMC Corporation. All Rights Reserved. * Copyright (C) 2015 EMC Corporation. All Rights Reserved.
* Copyright (C) 2016 T-Platforms. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
...@@ -201,9 +203,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) ...@@ -201,9 +203,13 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
* @link_enable: See ntb_link_enable(). * @link_enable: See ntb_link_enable().
* @link_disable: See ntb_link_disable(). * @link_disable: See ntb_link_disable().
* @mw_count: See ntb_mw_count(). * @mw_count: See ntb_mw_count().
* @mw_get_range: See ntb_mw_get_range(). * @mw_get_align: See ntb_mw_get_align().
* @mw_set_trans: See ntb_mw_set_trans(). * @mw_set_trans: See ntb_mw_set_trans().
* @mw_clear_trans: See ntb_mw_clear_trans(). * @mw_clear_trans: See ntb_mw_clear_trans().
* @peer_mw_count: See ntb_peer_mw_count().
* @peer_mw_get_addr: See ntb_peer_mw_get_addr().
* @peer_mw_set_trans: See ntb_peer_mw_set_trans().
* @peer_mw_clear_trans:See ntb_peer_mw_clear_trans().
* @db_is_unsafe: See ntb_db_is_unsafe(). * @db_is_unsafe: See ntb_db_is_unsafe().
* @db_valid_mask: See ntb_db_valid_mask(). * @db_valid_mask: See ntb_db_valid_mask().
* @db_vector_count: See ntb_db_vector_count(). * @db_vector_count: See ntb_db_vector_count().
...@@ -241,13 +247,20 @@ struct ntb_dev_ops { ...@@ -241,13 +247,20 @@ struct ntb_dev_ops {
enum ntb_speed max_speed, enum ntb_width max_width); enum ntb_speed max_speed, enum ntb_width max_width);
int (*link_disable)(struct ntb_dev *ntb); int (*link_disable)(struct ntb_dev *ntb);
int (*mw_count)(struct ntb_dev *ntb); int (*mw_count)(struct ntb_dev *ntb, int pidx);
int (*mw_get_range)(struct ntb_dev *ntb, int idx, int (*mw_get_align)(struct ntb_dev *ntb, int pidx, int widx,
phys_addr_t *base, resource_size_t *size, resource_size_t *addr_align,
resource_size_t *align, resource_size_t *align_size); resource_size_t *size_align,
int (*mw_set_trans)(struct ntb_dev *ntb, int idx, resource_size_t *size_max);
int (*mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size); dma_addr_t addr, resource_size_t size);
int (*mw_clear_trans)(struct ntb_dev *ntb, int idx); int (*mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
int (*peer_mw_count)(struct ntb_dev *ntb);
int (*peer_mw_get_addr)(struct ntb_dev *ntb, int widx,
phys_addr_t *base, resource_size_t *size);
int (*peer_mw_set_trans)(struct ntb_dev *ntb, int pidx, int widx,
u64 addr, resource_size_t size);
int (*peer_mw_clear_trans)(struct ntb_dev *ntb, int pidx, int widx);
int (*db_is_unsafe)(struct ntb_dev *ntb); int (*db_is_unsafe)(struct ntb_dev *ntb);
u64 (*db_valid_mask)(struct ntb_dev *ntb); u64 (*db_valid_mask)(struct ntb_dev *ntb);
...@@ -295,9 +308,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) ...@@ -295,9 +308,13 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
ops->link_enable && ops->link_enable &&
ops->link_disable && ops->link_disable &&
ops->mw_count && ops->mw_count &&
ops->mw_get_range && ops->mw_get_align &&
ops->mw_set_trans && (ops->mw_set_trans ||
ops->peer_mw_set_trans) &&
/* ops->mw_clear_trans && */ /* ops->mw_clear_trans && */
ops->peer_mw_count &&
ops->peer_mw_get_addr &&
/* ops->peer_mw_clear_trans && */
/* ops->db_is_unsafe && */ /* ops->db_is_unsafe && */
ops->db_valid_mask && ops->db_valid_mask &&
...@@ -655,79 +672,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb) ...@@ -655,79 +672,180 @@ static inline int ntb_link_disable(struct ntb_dev *ntb)
} }
/** /**
* ntb_mw_count() - get the number of memory windows * ntb_mw_count() - get the number of inbound memory windows, which could
* be created for a specified peer device
* @ntb: NTB device context. * @ntb: NTB device context.
* @pidx: Port index of peer device.
* *
* Hardware and topology may support a different number of memory windows. * Hardware and topology may support a different number of memory windows.
* Moreover different peer devices can support different number of memory
* windows. Simply speaking this method returns the number of possible inbound
* memory windows to share with specified peer device.
* *
* Return: the number of memory windows. * Return: the number of memory windows.
*/ */
static inline int ntb_mw_count(struct ntb_dev *ntb) static inline int ntb_mw_count(struct ntb_dev *ntb, int pidx)
{ {
return ntb->ops->mw_count(ntb); return ntb->ops->mw_count(ntb, pidx);
} }
/** /**
* ntb_mw_get_range() - get the range of a memory window * ntb_mw_get_align() - get the restriction parameters of inbound memory window
* @ntb: NTB device context. * @ntb: NTB device context.
* @idx: Memory window number. * @pidx: Port index of peer device.
* @base: OUT - the base address for mapping the memory window * @widx: Memory window index.
* @size: OUT - the size for mapping the memory window * @addr_align: OUT - the base alignment for translating the memory window
* @align: OUT - the base alignment for translating the memory window * @size_align: OUT - the size alignment for translating the memory window
* @align_size: OUT - the size alignment for translating the memory window * @size_max: OUT - the maximum size of the memory window
* *
* Get the range of a memory window. NULL may be given for any output * Get the alignments of an inbound memory window with specified index.
* parameter if the value is not needed. The base and size may be used for * NULL may be given for any output parameter if the value is not needed.
* mapping the memory window, to access the peer memory. The alignment and * The alignment and size parameters may be used for allocation of proper
* size may be used for translating the memory window, for the peer to access * shared memory.
* memory on the local system. *
* * Return: Zero on success, otherwise a negative error number.
* Return: Zero on success, otherwise an error number.
*/ */
static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx, static inline int ntb_mw_get_align(struct ntb_dev *ntb, int pidx, int widx,
phys_addr_t *base, resource_size_t *size, resource_size_t *addr_align,
resource_size_t *align, resource_size_t *align_size) resource_size_t *size_align,
resource_size_t *size_max)
{ {
return ntb->ops->mw_get_range(ntb, idx, base, size, return ntb->ops->mw_get_align(ntb, pidx, widx, addr_align, size_align,
align, align_size); size_max);
} }
/** /**
* ntb_mw_set_trans() - set the translation of a memory window * ntb_mw_set_trans() - set the translation of an inbound memory window
* @ntb: NTB device context. * @ntb: NTB device context.
* @idx: Memory window number. * @pidx: Port index of peer device.
* @addr: The dma address local memory to expose to the peer. * @widx: Memory window index.
* @addr: The dma address of local memory to expose to the peer.
* @size: The size of the local memory to expose to the peer. * @size: The size of the local memory to expose to the peer.
* *
* Set the translation of a memory window. The peer may access local memory * Set the translation of a memory window. The peer may access local memory
* through the window starting at the address, up to the size. The address * through the window starting at the address, up to the size. The address
* must be aligned to the alignment specified by ntb_mw_get_range(). The size * and size must be aligned in compliance with restrictions of
* must be aligned to the size alignment specified by ntb_mw_get_range(). * ntb_mw_get_align(). The region size should not exceed the size_max parameter
* of that method.
*
* This method may not be implemented due to the hardware specific memory
* windows interface.
* *
* Return: Zero on success, otherwise an error number. * Return: Zero on success, otherwise an error number.
*/ */
static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx, static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
dma_addr_t addr, resource_size_t size) dma_addr_t addr, resource_size_t size)
{ {
return ntb->ops->mw_set_trans(ntb, idx, addr, size); if (!ntb->ops->mw_set_trans)
return 0;
return ntb->ops->mw_set_trans(ntb, pidx, widx, addr, size);
} }
/** /**
* ntb_mw_clear_trans() - clear the translation of a memory window * ntb_mw_clear_trans() - clear the translation address of an inbound memory
* window
* @ntb: NTB device context. * @ntb: NTB device context.
* @idx: Memory window number. * @pidx: Port index of peer device.
* @widx: Memory window index.
* *
* Clear the translation of a memory window. The peer may no longer access * Clear the translation of an inbound memory window. The peer may no longer
* local memory through the window. * access local memory through the window.
* *
* Return: Zero on success, otherwise an error number. * Return: Zero on success, otherwise an error number.
*/ */
static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx) static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int pidx, int widx)
{ {
if (!ntb->ops->mw_clear_trans) if (!ntb->ops->mw_clear_trans)
return ntb->ops->mw_set_trans(ntb, idx, 0, 0); return ntb_mw_set_trans(ntb, pidx, widx, 0, 0);
return ntb->ops->mw_clear_trans(ntb, pidx, widx);
}
/**
* ntb_peer_mw_count() - get the number of outbound memory windows, which could
* be mapped to access a shared memory
* @ntb: NTB device context.
*
* Hardware and topology may support a different number of memory windows.
* This method returns the number of outbound memory windows supported by
* local device.
*
* Return: the number of memory windows.
*/
static inline int ntb_peer_mw_count(struct ntb_dev *ntb)
{
return ntb->ops->peer_mw_count(ntb);
}
/**
* ntb_peer_mw_get_addr() - get map address of an outbound memory window
* @ntb: NTB device context.
* @widx: Memory window index (within ntb_peer_mw_count() return value).
* @base: OUT - the base address of mapping region.
* @size: OUT - the size of mapping region.
*
* Get base and size of memory region to map. NULL may be given for any output
* parameter if the value is not needed. The base and size may be used for
* mapping the memory window, to access the peer memory.
*
* Return: Zero on success, otherwise a negative error number.
*/
static inline int ntb_peer_mw_get_addr(struct ntb_dev *ntb, int widx,
phys_addr_t *base, resource_size_t *size)
{
return ntb->ops->peer_mw_get_addr(ntb, widx, base, size);
}
/**
* ntb_peer_mw_set_trans() - set a translation address of a memory window
* retrieved from a peer device
* @ntb: NTB device context.
* @pidx: Port index of peer device the translation address received from.
* @widx: Memory window index.
* @addr: The dma address of the shared memory to access.
* @size: The size of the shared memory to access.
*
* Set the translation of an outbound memory window. The local device may
* access shared memory allocated by a peer device sent the address.
*
* This method may not be implemented due to the hardware specific memory
* windows interface, so a translation address can be only set on the side,
* where shared memory (inbound memory windows) is allocated.
*
* Return: Zero on success, otherwise an error number.
*/
static inline int ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
u64 addr, resource_size_t size)
{
if (!ntb->ops->peer_mw_set_trans)
return 0;
return ntb->ops->peer_mw_set_trans(ntb, pidx, widx, addr, size);
}
/**
* ntb_peer_mw_clear_trans() - clear the translation address of an outbound
* memory window
* @ntb: NTB device context.
* @pidx: Port index of peer device.
* @widx: Memory window index.
*
* Clear the translation of a outbound memory window. The local device may no
* longer access a shared memory through the window.
*
* This method may not be implemented due to the hardware specific memory
* windows interface.
*
* Return: Zero on success, otherwise an error number.
*/
static inline int ntb_peer_mw_clear_trans(struct ntb_dev *ntb, int pidx,
int widx)
{
if (!ntb->ops->peer_mw_clear_trans)
return ntb_peer_mw_set_trans(ntb, pidx, widx, 0, 0);
return ntb->ops->mw_clear_trans(ntb, idx); return ntb->ops->peer_mw_clear_trans(ntb, pidx, widx);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment