A very significant modification to NTB in this series.
An abstraction layer was added to allow the hardware and clients to be easily added. This required rewriting the NTB transport layer for this abstraction layer. This modification will allow future "high performance" NTB clients. In addition to this change, a number of performance modifications were added. These changes include NUMA enablement, using CPU memcpy instead of asyncdma, and modification of NTB layer MTU size. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJVmCNDAAoJEG5mS6x6i9IjI/QQAINNe7XCENdIL8iQZU2NDWCB BmVhQjKKnS5d774qrCIc/29FoxolTo4MG5H7j1zyGUUrx0mWbjrvRMA4AGt+yE0p Xf4DvFUi+Ptmf/dxlzxwt7ySBAQtAJiPRK0xJjEUqXpJqR/u5eTcsG2og7rXnXE1 DHtgqmh05D4Noi725yyn4qqVrqnUnFtgJ0hp6s7BE5ReeNPJNrD5yRpByEH81TBw +FiUHoCIuhZ4taGbfUU3G6lbBoWqztV8RmjI1AQGRGiij5BmYNZUBTEuSoEt86Df jxoLIz+77A9SGKejSmZbomeeBT3FnlnwHurC8hKdlqF05m3BebiTlCGEmddUdRAa u+8v/z5lmCaxH2Bg0rdQFn1HIvwtnToT4N3nfRtOkywg8tDHfYv2s1IaGO9bosJn XaIS5TR548IgEcsrIjJPX8ab/Q7nBUPkhaIEtXLyPdo41rON7J8aaJnv7bjPq/22 BoHU8fIoiYjIsiDPpsIgRAEXSTz8pr3uHU68NDR8R8pzf9OoysZQV9vy7N04YKTy 3Hr+AtEmiPel9YIx9Z8rgvLoMzP/nyxecJeFqUQpLkVR5YWdI50eg5TO9lBMU6Io hqROco8RUxJDC5J3IE75eWpc2YIxUsNo+5IFsxbNJ78OnY6GiF+pWnKx5rxwxs/G YHILdVMg/OBbVX3+fvJV =CyfQ -----END PGP SIGNATURE----- Merge tag 'ntb-4.2' of git://github.com/jonmason/ntb Pull NTB updates from Jon Mason: "This includes a pretty significant reworking of the NTB core code, but has already produced some significant performance improvements. An abstraction layer was added to allow the hardware and clients to be easily added. This required rewriting the NTB transport layer for this abstraction layer. This modification will allow future "high performance" NTB clients. In addition to this change, a number of performance modifications were added. These changes include NUMA enablement, using CPU memcpy instead of asyncdma, and modification of NTB layer MTU size" * tag 'ntb-4.2' of git://github.com/jonmason/ntb: (22 commits) NTB: Add split BAR output for debugfs stats NTB: Change WARN_ON_ONCE to pr_warn_once on unsafe NTB: Print driver name and version in module init NTB: Increase transport MTU to 64k from 16k NTB: Rename Intel code names to platform names NTB: Default to CPU memcpy for performance NTB: Improve performance with write combining NTB: Use NUMA memory in Intel driver NTB: Use NUMA memory and DMA chan in transport NTB: Rate limit ntb_qp_link_work NTB: Add tool test client NTB: Add ping pong test client NTB: Add parameters for Intel SNB B2B addresses NTB: Reset transport QP link stats on down NTB: Do not advance transport RX on link down NTB: Differentiate transport link down messages NTB: Check the device ID to set errata flags NTB: Enable link for Intel root port mode in probe NTB: Read peer info from local SPAD in transport NTB: Split ntb_hw_intel and ntb_transport drivers ...
This commit is contained in:
commit
6d7c8e1b3a
|
@ -0,0 +1,127 @@
|
|||
# NTB Drivers
|
||||
|
||||
NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects
|
||||
the separate memory systems of two computers to the same PCI-Express fabric.
|
||||
Existing NTB hardware supports a common feature set, including scratchpad
|
||||
registers, doorbell registers, and memory translation windows. Scratchpad
|
||||
registers are read-and-writable registers that are accessible from either side
|
||||
of the device, so that peers can exchange a small amount of information at a
|
||||
fixed address. Doorbell registers provide a way for peers to send interrupt
|
||||
events. Memory windows allow translated read and write access to the peer
|
||||
memory.
|
||||
|
||||
## NTB Core Driver (ntb)
|
||||
|
||||
The NTB core driver defines an api wrapping the common feature set, and allows
|
||||
clients interested in NTB features to discover NTB the devices supported by
|
||||
hardware drivers. The term "client" is used here to mean an upper layer
|
||||
component making use of the NTB api. The term "driver," or "hardware driver,"
|
||||
is used here to mean a driver for a specific vendor and model of NTB hardware.
|
||||
|
||||
## NTB Client Drivers
|
||||
|
||||
NTB client drivers should register with the NTB core driver. After
|
||||
registering, the client probe and remove functions will be called appropriately
|
||||
as ntb hardware, or hardware drivers, are inserted and removed. The
|
||||
registration uses the Linux Device framework, so it should feel familiar to
|
||||
anyone who has written a pci driver.
|
||||
|
||||
### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev)
|
||||
|
||||
The primary client for NTB is the Transport client, used in tandem with NTB
|
||||
Netdev. These drivers function together to create a logical link to the peer,
|
||||
across the ntb, to exchange packets of network data. The Transport client
|
||||
establishes a logical link to the peer, and creates queue pairs to exchange
|
||||
messages and data. The NTB Netdev then creates an ethernet device using a
|
||||
Transport queue pair. Network data is copied between socket buffers and the
|
||||
Transport queue pair buffer. The Transport client may be used for other things
|
||||
besides Netdev, however no other applications have yet been written.
|
||||
|
||||
### NTB Ping Pong Test Client (ntb\_pingpong)
|
||||
|
||||
The Ping Pong test client serves as a demonstration to exercise the doorbell
|
||||
and scratchpad registers of NTB hardware, and as an example simple NTB client.
|
||||
Ping Pong enables the link when started, waits for the NTB link to come up, and
|
||||
then proceeds to read and write the doorbell scratchpad registers of the NTB.
|
||||
The peers interrupt each other using a bit mask of doorbell bits, which is
|
||||
shifted by one in each round, to test the behavior of multiple doorbell bits
|
||||
and interrupt vectors. The Ping Pong driver also reads the first local
|
||||
scratchpad, and writes the value plus one to the first peer scratchpad, each
|
||||
round before writing the peer doorbell register.
|
||||
|
||||
Module Parameters:
|
||||
|
||||
* unsafe - Some hardware has known issues with scratchpad and doorbell
|
||||
registers. By default, Ping Pong will not attempt to exercise such
|
||||
hardware. You may override this behavior at your own risk by setting
|
||||
unsafe=1.
|
||||
* delay\_ms - Specify the delay between receiving a doorbell
|
||||
interrupt event and setting the peer doorbell register for the next
|
||||
round.
|
||||
* init\_db - Specify the doorbell bits to start new series of rounds. A new
|
||||
series begins once all the doorbell bits have been shifted out of
|
||||
range.
|
||||
* dyndbg - It is suggested to specify dyndbg=+p when loading this module, and
|
||||
then to observe debugging output on the console.
|
||||
|
||||
### NTB Tool Test Client (ntb\_tool)
|
||||
|
||||
The Tool test client serves for debugging, primarily, ntb hardware and drivers.
|
||||
The Tool provides access through debugfs for reading, setting, and clearing the
|
||||
NTB doorbell, and reading and writing scratchpads.
|
||||
|
||||
The Tool does not currently have any module parameters.
|
||||
|
||||
Debugfs Files:
|
||||
|
||||
* *debugfs*/ntb\_tool/*hw*/ - A directory in debugfs will be created for each
|
||||
NTB device probed by the tool. This directory is shortened to *hw*
|
||||
below.
|
||||
* *hw*/db - This file is used to read, set, and clear the local doorbell. Not
|
||||
all operations may be supported by all hardware. To read the doorbell,
|
||||
read the file. To set the doorbell, write `s` followed by the bits to
|
||||
set (eg: `echo 's 0x0101' > db`). To clear the doorbell, write `c`
|
||||
followed by the bits to clear.
|
||||
* *hw*/mask - This file is used to read, set, and clear the local doorbell mask.
|
||||
See *db* for details.
|
||||
* *hw*/peer\_db - This file is used to read, set, and clear the peer doorbell.
|
||||
See *db* for details.
|
||||
* *hw*/peer\_mask - This file is used to read, set, and clear the peer doorbell
|
||||
mask. See *db* for details.
|
||||
* *hw*/spad - This file is used to read and write local scratchpads. To read
|
||||
the values of all scratchpads, read the file. To write values, write a
|
||||
series of pairs of scratchpad number and value
|
||||
(eg: `echo '4 0x123 7 0xabc' > spad`
|
||||
# to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively).
|
||||
* *hw*/peer\_spad - This file is used to read and write peer scratchpads. See
|
||||
*spad* for details.
|
||||
|
||||
## NTB Hardware Drivers
|
||||
|
||||
NTB hardware drivers should register devices with the NTB core driver. After
|
||||
registering, clients probe and remove functions will be called.
|
||||
|
||||
### NTB Intel Hardware Driver (ntb\_hw\_intel)
|
||||
|
||||
The Intel hardware driver supports NTB on Xeon and Atom CPUs.
|
||||
|
||||
Module Parameters:
|
||||
|
||||
* b2b\_mw\_idx - If the peer ntb is to be accessed via a memory window, then use
|
||||
this memory window to access the peer ntb. A value of zero or positive
|
||||
starts from the first mw idx, and a negative value starts from the last
|
||||
mw idx. Both sides MUST set the same value here! The default value is
|
||||
`-1`.
|
||||
* b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if
|
||||
the memory window is large enough, still allow the client to use the
|
||||
second half of the memory window for address translation to the peer.
|
||||
* xeon\_b2b\_usd\_bar2\_addr64 - If using B2B topology on Xeon hardware, use
|
||||
this 64 bit address on the bus between the NTB devices for the window
|
||||
at BAR2, on the upstream side of the link.
|
||||
* xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_usd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_usd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_dsd\_bar2\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_dsd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_dsd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
|
||||
* xeon\_b2b\_dsd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*.
|
12
MAINTAINERS
12
MAINTAINERS
|
@ -7212,15 +7212,25 @@ F: drivers/power/bq27x00_battery.c
|
|||
F: drivers/power/isp1704_charger.c
|
||||
F: drivers/power/rx51_battery.c
|
||||
|
||||
NTB DRIVER
|
||||
NTB DRIVER CORE
|
||||
M: Jon Mason <jdmason@kudzu.us>
|
||||
M: Dave Jiang <dave.jiang@intel.com>
|
||||
M: Allen Hubbe <Allen.Hubbe@emc.com>
|
||||
S: Supported
|
||||
W: https://github.com/jonmason/ntb/wiki
|
||||
T: git git://github.com/jonmason/ntb.git
|
||||
F: drivers/ntb/
|
||||
F: drivers/net/ntb_netdev.c
|
||||
F: include/linux/ntb.h
|
||||
F: include/linux/ntb_transport.h
|
||||
|
||||
NTB INTEL DRIVER
|
||||
M: Jon Mason <jdmason@kudzu.us>
|
||||
M: Dave Jiang <dave.jiang@intel.com>
|
||||
S: Supported
|
||||
W: https://github.com/jonmason/ntb/wiki
|
||||
T: git git://github.com/jonmason/ntb.git
|
||||
F: drivers/ntb/hw/intel/
|
||||
|
||||
NTFS FILESYSTEM
|
||||
M: Anton Altaparmakov <anton@tuxera.com>
|
||||
|
|
|
@ -217,8 +217,8 @@ config NET_POLL_CONTROLLER
|
|||
def_bool NETPOLL
|
||||
|
||||
config NTB_NETDEV
|
||||
tristate "Virtual Ethernet over NTB"
|
||||
depends on NTB
|
||||
tristate "Virtual Ethernet over NTB Transport"
|
||||
depends on NTB_TRANSPORT
|
||||
|
||||
config RIONET
|
||||
tristate "RapidIO Ethernet over messaging driver support"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
|
@ -13,6 +14,7 @@
|
|||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -40,7 +42,7 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Intel PCIe NTB Network Linux driver
|
||||
* PCIe NTB Network Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
|
@ -50,6 +52,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ntb.h>
|
||||
#include <linux/ntb_transport.h>
|
||||
|
||||
#define NTB_NETDEV_VER "0.7"
|
||||
|
||||
|
@ -70,26 +73,19 @@ struct ntb_netdev {
|
|||
|
||||
static LIST_HEAD(dev_list);
|
||||
|
||||
static void ntb_netdev_event_handler(void *data, int status)
|
||||
static void ntb_netdev_event_handler(void *data, int link_is_up)
|
||||
{
|
||||
struct net_device *ndev = data;
|
||||
struct ntb_netdev *dev = netdev_priv(ndev);
|
||||
|
||||
netdev_dbg(ndev, "Event %x, Link %x\n", status,
|
||||
netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up,
|
||||
ntb_transport_link_query(dev->qp));
|
||||
|
||||
switch (status) {
|
||||
case NTB_LINK_DOWN:
|
||||
netif_carrier_off(ndev);
|
||||
break;
|
||||
case NTB_LINK_UP:
|
||||
if (!ntb_transport_link_query(dev->qp))
|
||||
return;
|
||||
|
||||
if (link_is_up) {
|
||||
if (ntb_transport_link_query(dev->qp))
|
||||
netif_carrier_on(ndev);
|
||||
break;
|
||||
default:
|
||||
netdev_warn(ndev, "Unsupported event type %d\n", status);
|
||||
} else {
|
||||
netif_carrier_off(ndev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,8 +156,6 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
|
|||
struct ntb_netdev *dev = netdev_priv(ndev);
|
||||
int rc;
|
||||
|
||||
netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len);
|
||||
|
||||
rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
@ -322,20 +316,26 @@ static const struct ntb_queue_handlers ntb_netdev_handlers = {
|
|||
.event_handler = ntb_netdev_event_handler,
|
||||
};
|
||||
|
||||
static int ntb_netdev_probe(struct pci_dev *pdev)
|
||||
static int ntb_netdev_probe(struct device *client_dev)
|
||||
{
|
||||
struct ntb_dev *ntb;
|
||||
struct net_device *ndev;
|
||||
struct pci_dev *pdev;
|
||||
struct ntb_netdev *dev;
|
||||
int rc;
|
||||
|
||||
ndev = alloc_etherdev(sizeof(struct ntb_netdev));
|
||||
ntb = dev_ntb(client_dev->parent);
|
||||
pdev = ntb->pdev;
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
ndev = alloc_etherdev(sizeof(*dev));
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev = netdev_priv(ndev);
|
||||
dev->ndev = ndev;
|
||||
dev->pdev = pdev;
|
||||
BUG_ON(!dev->pdev);
|
||||
ndev->features = NETIF_F_HIGHDMA;
|
||||
|
||||
ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
||||
|
@ -349,7 +349,8 @@ static int ntb_netdev_probe(struct pci_dev *pdev)
|
|||
ndev->netdev_ops = &ntb_netdev_ops;
|
||||
ndev->ethtool_ops = &ntb_ethtool_ops;
|
||||
|
||||
dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers);
|
||||
dev->qp = ntb_transport_create_queue(ndev, client_dev,
|
||||
&ntb_netdev_handlers);
|
||||
if (!dev->qp) {
|
||||
rc = -EIO;
|
||||
goto err;
|
||||
|
@ -372,12 +373,17 @@ err:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void ntb_netdev_remove(struct pci_dev *pdev)
|
||||
static void ntb_netdev_remove(struct device *client_dev)
|
||||
{
|
||||
struct ntb_dev *ntb;
|
||||
struct net_device *ndev;
|
||||
struct pci_dev *pdev;
|
||||
struct ntb_netdev *dev;
|
||||
bool found = false;
|
||||
|
||||
ntb = dev_ntb(client_dev->parent);
|
||||
pdev = ntb->pdev;
|
||||
|
||||
list_for_each_entry(dev, &dev_list, list) {
|
||||
if (dev->pdev == pdev) {
|
||||
found = true;
|
||||
|
@ -396,7 +402,7 @@ static void ntb_netdev_remove(struct pci_dev *pdev)
|
|||
free_netdev(ndev);
|
||||
}
|
||||
|
||||
static struct ntb_client ntb_netdev_client = {
|
||||
static struct ntb_transport_client ntb_netdev_client = {
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.probe = ntb_netdev_probe,
|
||||
|
@ -407,16 +413,16 @@ static int __init ntb_netdev_init_module(void)
|
|||
{
|
||||
int rc;
|
||||
|
||||
rc = ntb_register_client_dev(KBUILD_MODNAME);
|
||||
rc = ntb_transport_register_client_dev(KBUILD_MODNAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
return ntb_register_client(&ntb_netdev_client);
|
||||
return ntb_transport_register_client(&ntb_netdev_client);
|
||||
}
|
||||
module_init(ntb_netdev_init_module);
|
||||
|
||||
static void __exit ntb_netdev_exit_module(void)
|
||||
{
|
||||
ntb_unregister_client(&ntb_netdev_client);
|
||||
ntb_unregister_client_dev(KBUILD_MODNAME);
|
||||
ntb_transport_unregister_client(&ntb_netdev_client);
|
||||
ntb_transport_unregister_client_dev(KBUILD_MODNAME);
|
||||
}
|
||||
module_exit(ntb_netdev_exit_module);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
config NTB
|
||||
tristate "Intel Non-Transparent Bridge support"
|
||||
menuconfig NTB
|
||||
tristate "Non-Transparent Bridge support"
|
||||
depends on PCI
|
||||
depends on X86
|
||||
help
|
||||
The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus
|
||||
connecting 2 systems. When configured, writes to the device's PCI
|
||||
|
@ -11,3 +10,19 @@ config NTB
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
if NTB
|
||||
|
||||
source "drivers/ntb/hw/Kconfig"
|
||||
|
||||
source "drivers/ntb/test/Kconfig"
|
||||
|
||||
config NTB_TRANSPORT
|
||||
tristate "NTB Transport Client"
|
||||
help
|
||||
This is a transport driver that enables connected systems to exchange
|
||||
messages over the ntb hardware. The transport exposes a queue pair api
|
||||
to client drivers.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif # NTB
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
obj-$(CONFIG_NTB) += ntb.o
|
||||
|
||||
ntb-objs := ntb_hw.o ntb_transport.o
|
||||
obj-$(CONFIG_NTB) += ntb.o hw/ test/
|
||||
obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
source "drivers/ntb/hw/intel/Kconfig"
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_NTB_INTEL) += intel/
|
|
@ -0,0 +1,7 @@
|
|||
config NTB_INTEL
|
||||
tristate "Intel Non-Transparent Bridge support"
|
||||
depends on X86_64
|
||||
help
|
||||
This driver supports Intel NTB on capable Xeon and Atom hardware.
|
||||
|
||||
If unsure, say N.
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Intel PCIe NTB Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef NTB_HW_INTEL_H
|
||||
#define NTB_HW_INTEL_H
|
||||
|
||||
#include <linux/ntb.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E
|
||||
|
||||
/* Intel Xeon hardware */
|
||||
|
||||
#define XEON_PBAR23LMT_OFFSET 0x0000
|
||||
#define XEON_PBAR45LMT_OFFSET 0x0008
|
||||
#define XEON_PBAR4LMT_OFFSET 0x0008
|
||||
#define XEON_PBAR5LMT_OFFSET 0x000c
|
||||
#define XEON_PBAR23XLAT_OFFSET 0x0010
|
||||
#define XEON_PBAR45XLAT_OFFSET 0x0018
|
||||
#define XEON_PBAR4XLAT_OFFSET 0x0018
|
||||
#define XEON_PBAR5XLAT_OFFSET 0x001c
|
||||
#define XEON_SBAR23LMT_OFFSET 0x0020
|
||||
#define XEON_SBAR45LMT_OFFSET 0x0028
|
||||
#define XEON_SBAR4LMT_OFFSET 0x0028
|
||||
#define XEON_SBAR5LMT_OFFSET 0x002c
|
||||
#define XEON_SBAR23XLAT_OFFSET 0x0030
|
||||
#define XEON_SBAR45XLAT_OFFSET 0x0038
|
||||
#define XEON_SBAR4XLAT_OFFSET 0x0038
|
||||
#define XEON_SBAR5XLAT_OFFSET 0x003c
|
||||
#define XEON_SBAR0BASE_OFFSET 0x0040
|
||||
#define XEON_SBAR23BASE_OFFSET 0x0048
|
||||
#define XEON_SBAR45BASE_OFFSET 0x0050
|
||||
#define XEON_SBAR4BASE_OFFSET 0x0050
|
||||
#define XEON_SBAR5BASE_OFFSET 0x0054
|
||||
#define XEON_SBDF_OFFSET 0x005c
|
||||
#define XEON_NTBCNTL_OFFSET 0x0058
|
||||
#define XEON_PDOORBELL_OFFSET 0x0060
|
||||
#define XEON_PDBMSK_OFFSET 0x0062
|
||||
#define XEON_SDOORBELL_OFFSET 0x0064
|
||||
#define XEON_SDBMSK_OFFSET 0x0066
|
||||
#define XEON_USMEMMISS_OFFSET 0x0070
|
||||
#define XEON_SPAD_OFFSET 0x0080
|
||||
#define XEON_PBAR23SZ_OFFSET 0x00d0
|
||||
#define XEON_PBAR45SZ_OFFSET 0x00d1
|
||||
#define XEON_PBAR4SZ_OFFSET 0x00d1
|
||||
#define XEON_SBAR23SZ_OFFSET 0x00d2
|
||||
#define XEON_SBAR45SZ_OFFSET 0x00d3
|
||||
#define XEON_SBAR4SZ_OFFSET 0x00d3
|
||||
#define XEON_PPD_OFFSET 0x00d4
|
||||
#define XEON_PBAR5SZ_OFFSET 0x00d5
|
||||
#define XEON_SBAR5SZ_OFFSET 0x00d6
|
||||
#define XEON_WCCNTRL_OFFSET 0x00e0
|
||||
#define XEON_UNCERRSTS_OFFSET 0x014c
|
||||
#define XEON_CORERRSTS_OFFSET 0x0158
|
||||
#define XEON_LINK_STATUS_OFFSET 0x01a2
|
||||
#define XEON_SPCICMD_OFFSET 0x0504
|
||||
#define XEON_DEVCTRL_OFFSET 0x0598
|
||||
#define XEON_DEVSTS_OFFSET 0x059a
|
||||
#define XEON_SLINK_STATUS_OFFSET 0x05a2
|
||||
#define XEON_B2B_SPAD_OFFSET 0x0100
|
||||
#define XEON_B2B_DOORBELL_OFFSET 0x0140
|
||||
#define XEON_B2B_XLAT_OFFSETL 0x0144
|
||||
#define XEON_B2B_XLAT_OFFSETU 0x0148
|
||||
#define XEON_PPD_CONN_MASK 0x03
|
||||
#define XEON_PPD_CONN_TRANSPARENT 0x00
|
||||
#define XEON_PPD_CONN_B2B 0x01
|
||||
#define XEON_PPD_CONN_RP 0x02
|
||||
#define XEON_PPD_DEV_MASK 0x10
|
||||
#define XEON_PPD_DEV_USD 0x00
|
||||
#define XEON_PPD_DEV_DSD 0x10
|
||||
#define XEON_PPD_SPLIT_BAR_MASK 0x40
|
||||
|
||||
#define XEON_PPD_TOPO_MASK (XEON_PPD_CONN_MASK | XEON_PPD_DEV_MASK)
|
||||
#define XEON_PPD_TOPO_PRI_USD (XEON_PPD_CONN_RP | XEON_PPD_DEV_USD)
|
||||
#define XEON_PPD_TOPO_PRI_DSD (XEON_PPD_CONN_RP | XEON_PPD_DEV_DSD)
|
||||
#define XEON_PPD_TOPO_SEC_USD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_USD)
|
||||
#define XEON_PPD_TOPO_SEC_DSD (XEON_PPD_CONN_TRANSPARENT | XEON_PPD_DEV_DSD)
|
||||
#define XEON_PPD_TOPO_B2B_USD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_USD)
|
||||
#define XEON_PPD_TOPO_B2B_DSD (XEON_PPD_CONN_B2B | XEON_PPD_DEV_DSD)
|
||||
|
||||
#define XEON_MW_COUNT 2
|
||||
#define HSX_SPLIT_BAR_MW_COUNT 3
|
||||
#define XEON_DB_COUNT 15
|
||||
#define XEON_DB_LINK 15
|
||||
#define XEON_DB_LINK_BIT BIT_ULL(XEON_DB_LINK)
|
||||
#define XEON_DB_MSIX_VECTOR_COUNT 4
|
||||
#define XEON_DB_MSIX_VECTOR_SHIFT 5
|
||||
#define XEON_DB_TOTAL_SHIFT 16
|
||||
#define XEON_SPAD_COUNT 16
|
||||
|
||||
/* Intel Atom hardware */
|
||||
|
||||
#define ATOM_SBAR2XLAT_OFFSET 0x0008
|
||||
#define ATOM_PDOORBELL_OFFSET 0x0020
|
||||
#define ATOM_PDBMSK_OFFSET 0x0028
|
||||
#define ATOM_NTBCNTL_OFFSET 0x0060
|
||||
#define ATOM_SPAD_OFFSET 0x0080
|
||||
#define ATOM_PPD_OFFSET 0x00d4
|
||||
#define ATOM_PBAR2XLAT_OFFSET 0x8008
|
||||
#define ATOM_B2B_DOORBELL_OFFSET 0x8020
|
||||
#define ATOM_B2B_SPAD_OFFSET 0x8080
|
||||
#define ATOM_SPCICMD_OFFSET 0xb004
|
||||
#define ATOM_LINK_STATUS_OFFSET 0xb052
|
||||
#define ATOM_ERRCORSTS_OFFSET 0xb110
|
||||
#define ATOM_IP_BASE 0xc000
|
||||
#define ATOM_DESKEWSTS_OFFSET (ATOM_IP_BASE + 0x3024)
|
||||
#define ATOM_LTSSMERRSTS0_OFFSET (ATOM_IP_BASE + 0x3180)
|
||||
#define ATOM_LTSSMSTATEJMP_OFFSET (ATOM_IP_BASE + 0x3040)
|
||||
#define ATOM_IBSTERRRCRVSTS0_OFFSET (ATOM_IP_BASE + 0x3324)
|
||||
#define ATOM_MODPHY_PCSREG4 0x1c004
|
||||
#define ATOM_MODPHY_PCSREG6 0x1c006
|
||||
|
||||
#define ATOM_PPD_INIT_LINK 0x0008
|
||||
#define ATOM_PPD_CONN_MASK 0x0300
|
||||
#define ATOM_PPD_CONN_TRANSPARENT 0x0000
|
||||
#define ATOM_PPD_CONN_B2B 0x0100
|
||||
#define ATOM_PPD_CONN_RP 0x0200
|
||||
#define ATOM_PPD_DEV_MASK 0x1000
|
||||
#define ATOM_PPD_DEV_USD 0x0000
|
||||
#define ATOM_PPD_DEV_DSD 0x1000
|
||||
#define ATOM_PPD_TOPO_MASK (ATOM_PPD_CONN_MASK | ATOM_PPD_DEV_MASK)
|
||||
#define ATOM_PPD_TOPO_PRI_USD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_USD)
|
||||
#define ATOM_PPD_TOPO_PRI_DSD (ATOM_PPD_CONN_TRANSPARENT | ATOM_PPD_DEV_DSD)
|
||||
#define ATOM_PPD_TOPO_SEC_USD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_USD)
|
||||
#define ATOM_PPD_TOPO_SEC_DSD (ATOM_PPD_CONN_RP | ATOM_PPD_DEV_DSD)
|
||||
#define ATOM_PPD_TOPO_B2B_USD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_USD)
|
||||
#define ATOM_PPD_TOPO_B2B_DSD (ATOM_PPD_CONN_B2B | ATOM_PPD_DEV_DSD)
|
||||
|
||||
#define ATOM_MW_COUNT 2
|
||||
#define ATOM_DB_COUNT 34
|
||||
#define ATOM_DB_VALID_MASK (BIT_ULL(ATOM_DB_COUNT) - 1)
|
||||
#define ATOM_DB_MSIX_VECTOR_COUNT 34
|
||||
#define ATOM_DB_MSIX_VECTOR_SHIFT 1
|
||||
#define ATOM_DB_TOTAL_SHIFT 34
|
||||
#define ATOM_SPAD_COUNT 16
|
||||
|
||||
#define ATOM_NTB_CTL_DOWN_BIT BIT(16)
|
||||
#define ATOM_NTB_CTL_ACTIVE(x) !(x & ATOM_NTB_CTL_DOWN_BIT)
|
||||
|
||||
#define ATOM_DESKEWSTS_DBERR BIT(15)
|
||||
#define ATOM_LTSSMERRSTS0_UNEXPECTEDEI BIT(20)
|
||||
#define ATOM_LTSSMSTATEJMP_FORCEDETECT BIT(2)
|
||||
#define ATOM_IBIST_ERR_OFLOW 0x7FFF7FFF
|
||||
|
||||
#define ATOM_LINK_HB_TIMEOUT msecs_to_jiffies(1000)
|
||||
#define ATOM_LINK_RECOVERY_TIME msecs_to_jiffies(500)
|
||||
|
||||
/* Ntb control and link status */
|
||||
|
||||
#define NTB_CTL_CFG_LOCK BIT(0)
|
||||
#define NTB_CTL_DISABLE BIT(1)
|
||||
#define NTB_CTL_S2P_BAR2_SNOOP BIT(2)
|
||||
#define NTB_CTL_P2S_BAR2_SNOOP BIT(4)
|
||||
#define NTB_CTL_S2P_BAR4_SNOOP BIT(6)
|
||||
#define NTB_CTL_P2S_BAR4_SNOOP BIT(8)
|
||||
#define NTB_CTL_S2P_BAR5_SNOOP BIT(12)
|
||||
#define NTB_CTL_P2S_BAR5_SNOOP BIT(14)
|
||||
|
||||
#define NTB_LNK_STA_ACTIVE_BIT 0x2000
|
||||
#define NTB_LNK_STA_SPEED_MASK 0x000f
|
||||
#define NTB_LNK_STA_WIDTH_MASK 0x03f0
|
||||
#define NTB_LNK_STA_ACTIVE(x) (!!((x) & NTB_LNK_STA_ACTIVE_BIT))
|
||||
#define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK)
|
||||
#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4)
|
||||
|
||||
/* Use the following addresses for translation between b2b ntb devices in case
|
||||
* the hardware default values are not reliable. */
|
||||
#define XEON_B2B_BAR0_USD_ADDR 0x1000000000000000ull
|
||||
#define XEON_B2B_BAR2_USD_ADDR64 0x2000000000000000ull
|
||||
#define XEON_B2B_BAR4_USD_ADDR64 0x4000000000000000ull
|
||||
#define XEON_B2B_BAR4_USD_ADDR32 0x20000000u
|
||||
#define XEON_B2B_BAR5_USD_ADDR32 0x40000000u
|
||||
#define XEON_B2B_BAR0_DSD_ADDR 0x9000000000000000ull
|
||||
#define XEON_B2B_BAR2_DSD_ADDR64 0xa000000000000000ull
|
||||
#define XEON_B2B_BAR4_DSD_ADDR64 0xc000000000000000ull
|
||||
#define XEON_B2B_BAR4_DSD_ADDR32 0xa0000000u
|
||||
#define XEON_B2B_BAR5_DSD_ADDR32 0xc0000000u
|
||||
|
||||
/* The peer ntb secondary config space is 32KB fixed size */
|
||||
#define XEON_B2B_MIN_SIZE 0x8000
|
||||
|
||||
/* flags to indicate hardware errata */
|
||||
#define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0)
|
||||
#define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1)
|
||||
#define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2)
|
||||
|
||||
/* flags to indicate unsafe api */
|
||||
#define NTB_UNSAFE_DB BIT_ULL(0)
|
||||
#define NTB_UNSAFE_SPAD BIT_ULL(1)
|
||||
|
||||
struct intel_ntb_dev;
|
||||
|
||||
struct intel_ntb_reg {
|
||||
int (*poll_link)(struct intel_ntb_dev *ndev);
|
||||
int (*link_is_up)(struct intel_ntb_dev *ndev);
|
||||
u64 (*db_ioread)(void __iomem *mmio);
|
||||
void (*db_iowrite)(u64 db_bits, void __iomem *mmio);
|
||||
unsigned long ntb_ctl;
|
||||
resource_size_t db_size;
|
||||
int mw_bar[];
|
||||
};
|
||||
|
||||
struct intel_ntb_alt_reg {
|
||||
unsigned long db_bell;
|
||||
unsigned long db_mask;
|
||||
unsigned long spad;
|
||||
};
|
||||
|
||||
struct intel_ntb_xlat_reg {
|
||||
unsigned long bar0_base;
|
||||
unsigned long bar2_xlat;
|
||||
unsigned long bar2_limit;
|
||||
};
|
||||
|
||||
struct intel_b2b_addr {
|
||||
phys_addr_t bar0_addr;
|
||||
phys_addr_t bar2_addr64;
|
||||
phys_addr_t bar4_addr64;
|
||||
phys_addr_t bar4_addr32;
|
||||
phys_addr_t bar5_addr32;
|
||||
};
|
||||
|
||||
struct intel_ntb_vec {
|
||||
struct intel_ntb_dev *ndev;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct intel_ntb_dev {
|
||||
struct ntb_dev ntb;
|
||||
|
||||
/* offset of peer bar0 in b2b bar */
|
||||
unsigned long b2b_off;
|
||||
/* mw idx used to access peer bar0 */
|
||||
unsigned int b2b_idx;
|
||||
|
||||
/* BAR45 is split into BAR4 and BAR5 */
|
||||
bool bar4_split;
|
||||
|
||||
u32 ntb_ctl;
|
||||
u32 lnk_sta;
|
||||
|
||||
unsigned char mw_count;
|
||||
unsigned char spad_count;
|
||||
unsigned char db_count;
|
||||
unsigned char db_vec_count;
|
||||
unsigned char db_vec_shift;
|
||||
|
||||
u64 db_valid_mask;
|
||||
u64 db_link_mask;
|
||||
u64 db_mask;
|
||||
|
||||
/* synchronize rmw access of db_mask and hw reg */
|
||||
spinlock_t db_mask_lock;
|
||||
|
||||
struct msix_entry *msix;
|
||||
struct intel_ntb_vec *vec;
|
||||
|
||||
const struct intel_ntb_reg *reg;
|
||||
const struct intel_ntb_alt_reg *self_reg;
|
||||
const struct intel_ntb_alt_reg *peer_reg;
|
||||
const struct intel_ntb_xlat_reg *xlat_reg;
|
||||
void __iomem *self_mmio;
|
||||
void __iomem *peer_mmio;
|
||||
phys_addr_t peer_addr;
|
||||
|
||||
unsigned long last_ts;
|
||||
struct delayed_work hb_timer;
|
||||
|
||||
unsigned long hwerr_flags;
|
||||
unsigned long unsafe_flags;
|
||||
unsigned long unsafe_flags_ignore;
|
||||
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *debugfs_info;
|
||||
};
|
||||
|
||||
#define ndev_pdev(ndev) ((ndev)->ntb.pdev)
|
||||
#define ndev_name(ndev) pci_name(ndev_pdev(ndev))
|
||||
#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev)
|
||||
#define ntb_ndev(ntb) container_of(ntb, struct intel_ntb_dev, ntb)
|
||||
#define hb_ndev(work) container_of(work, struct intel_ntb_dev, hb_timer.work)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* PCIe NTB Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Allen Hubbe <Allen.Hubbe@emc.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/ntb.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define DRIVER_NAME "ntb"
|
||||
#define DRIVER_DESCRIPTION "PCIe NTB Driver Framework"
|
||||
|
||||
#define DRIVER_LICENSE "Dual BSD/GPL"
|
||||
#define DRIVER_VERSION "1.0"
|
||||
#define DRIVER_RELDATE "24 March 2015"
|
||||
#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
|
||||
|
||||
MODULE_LICENSE(DRIVER_LICENSE);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
|
||||
|
||||
static struct bus_type ntb_bus;
|
||||
static void ntb_dev_release(struct device *dev);
|
||||
|
||||
int __ntb_register_client(struct ntb_client *client, struct module *mod,
|
||||
const char *mod_name)
|
||||
{
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
if (!ntb_client_ops_is_valid(&client->ops))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&client->drv, 0, sizeof(client->drv));
|
||||
client->drv.bus = &ntb_bus;
|
||||
client->drv.name = mod_name;
|
||||
client->drv.owner = mod;
|
||||
|
||||
return driver_register(&client->drv);
|
||||
}
|
||||
EXPORT_SYMBOL(__ntb_register_client);
|
||||
|
||||
void ntb_unregister_client(struct ntb_client *client)
|
||||
{
|
||||
driver_unregister(&client->drv);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_unregister_client);
|
||||
|
||||
int ntb_register_device(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb)
|
||||
return -EINVAL;
|
||||
if (!ntb->pdev)
|
||||
return -EINVAL;
|
||||
if (!ntb->ops)
|
||||
return -EINVAL;
|
||||
if (!ntb_dev_ops_is_valid(ntb->ops))
|
||||
return -EINVAL;
|
||||
|
||||
init_completion(&ntb->released);
|
||||
|
||||
memset(&ntb->dev, 0, sizeof(ntb->dev));
|
||||
ntb->dev.bus = &ntb_bus;
|
||||
ntb->dev.parent = &ntb->pdev->dev;
|
||||
ntb->dev.release = ntb_dev_release;
|
||||
dev_set_name(&ntb->dev, pci_name(ntb->pdev));
|
||||
|
||||
ntb->ctx = NULL;
|
||||
ntb->ctx_ops = NULL;
|
||||
spin_lock_init(&ntb->ctx_lock);
|
||||
|
||||
return device_register(&ntb->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_register_device);
|
||||
|
||||
void ntb_unregister_device(struct ntb_dev *ntb)
|
||||
{
|
||||
device_unregister(&ntb->dev);
|
||||
wait_for_completion(&ntb->released);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_unregister_device);
|
||||
|
||||
int ntb_set_ctx(struct ntb_dev *ntb, void *ctx,
|
||||
const struct ntb_ctx_ops *ctx_ops)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
if (!ntb_ctx_ops_is_valid(ctx_ops))
|
||||
return -EINVAL;
|
||||
if (ntb->ctx_ops)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&ntb->ctx_lock, irqflags);
|
||||
{
|
||||
ntb->ctx = ctx;
|
||||
ntb->ctx_ops = ctx_ops;
|
||||
}
|
||||
spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_set_ctx);
|
||||
|
||||
void ntb_clear_ctx(struct ntb_dev *ntb)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&ntb->ctx_lock, irqflags);
|
||||
{
|
||||
ntb->ctx_ops = NULL;
|
||||
ntb->ctx = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_clear_ctx);
|
||||
|
||||
void ntb_link_event(struct ntb_dev *ntb)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&ntb->ctx_lock, irqflags);
|
||||
{
|
||||
if (ntb->ctx_ops && ntb->ctx_ops->link_event)
|
||||
ntb->ctx_ops->link_event(ntb->ctx);
|
||||
}
|
||||
spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_link_event);
|
||||
|
||||
void ntb_db_event(struct ntb_dev *ntb, int vector)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&ntb->ctx_lock, irqflags);
|
||||
{
|
||||
if (ntb->ctx_ops && ntb->ctx_ops->db_event)
|
||||
ntb->ctx_ops->db_event(ntb->ctx, vector);
|
||||
}
|
||||
spin_unlock_irqrestore(&ntb->ctx_lock, irqflags);
|
||||
}
|
||||
EXPORT_SYMBOL(ntb_db_event);
|
||||
|
||||
static int ntb_probe(struct device *dev)
|
||||
{
|
||||
struct ntb_dev *ntb;
|
||||
struct ntb_client *client;
|
||||
int rc;
|
||||
|
||||
get_device(dev);
|
||||
ntb = dev_ntb(dev);
|
||||
client = drv_ntb_client(dev->driver);
|
||||
|
||||
rc = client->ops.probe(client, ntb);
|
||||
if (rc)
|
||||
put_device(dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ntb_remove(struct device *dev)
|
||||
{
|
||||
struct ntb_dev *ntb;
|
||||
struct ntb_client *client;
|
||||
|
||||
if (dev->driver) {
|
||||
ntb = dev_ntb(dev);
|
||||
client = drv_ntb_client(dev->driver);
|
||||
|
||||
client->ops.remove(client, ntb);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ntb_dev_release(struct device *dev)
|
||||
{
|
||||
struct ntb_dev *ntb = dev_ntb(dev);
|
||||
|
||||
complete(&ntb->released);
|
||||
}
|
||||
|
||||
static struct bus_type ntb_bus = {
|
||||
.name = "ntb",
|
||||
.probe = ntb_probe,
|
||||
.remove = ntb_remove,
|
||||
};
|
||||
|
||||
static int __init ntb_driver_init(void)
|
||||
{
|
||||
return bus_register(&ntb_bus);
|
||||
}
|
||||
module_init(ntb_driver_init);
|
||||
|
||||
static void __exit ntb_driver_exit(void)
|
||||
{
|
||||
bus_unregister(&ntb_bus);
|
||||
}
|
||||
module_exit(ntb_driver_exit);
|
||||
|
1895
drivers/ntb/ntb_hw.c
1895
drivers/ntb/ntb_hw.c
File diff suppressed because it is too large
Load Diff
|
@ -1,256 +0,0 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Intel PCIe NTB Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
*/
|
||||
#include <linux/ntb.h>
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F
|
||||
#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E
|
||||
|
||||
#ifndef readq
|
||||
static inline u64 readq(void __iomem *addr)
|
||||
{
|
||||
return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef writeq
|
||||
static inline void writeq(u64 val, void __iomem *addr)
|
||||
{
|
||||
writel(val & 0xffffffff, addr);
|
||||
writel(val >> 32, addr + 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define NTB_BAR_MMIO 0
|
||||
#define NTB_BAR_23 2
|
||||
#define NTB_BAR_4 4
|
||||
#define NTB_BAR_5 5
|
||||
|
||||
#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
|
||||
(1 << NTB_BAR_4))
|
||||
#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
|
||||
(1 << NTB_BAR_4) | (1 << NTB_BAR_5))
|
||||
|
||||
#define NTB_HB_TIMEOUT msecs_to_jiffies(1000)
|
||||
|
||||
enum ntb_hw_event {
|
||||
NTB_EVENT_SW_EVENT0 = 0,
|
||||
NTB_EVENT_SW_EVENT1,
|
||||
NTB_EVENT_SW_EVENT2,
|
||||
NTB_EVENT_HW_ERROR,
|
||||
NTB_EVENT_HW_LINK_UP,
|
||||
NTB_EVENT_HW_LINK_DOWN,
|
||||
};
|
||||
|
||||
struct ntb_mw {
|
||||
dma_addr_t phys_addr;
|
||||
void __iomem *vbase;
|
||||
resource_size_t bar_sz;
|
||||
};
|
||||
|
||||
struct ntb_db_cb {
|
||||
int (*callback)(void *data, int db_num);
|
||||
unsigned int db_num;
|
||||
void *data;
|
||||
struct ntb_device *ndev;
|
||||
struct tasklet_struct irq_work;
|
||||
};
|
||||
|
||||
#define WA_SNB_ERR 0x00000001
|
||||
|
||||
struct ntb_device {
|
||||
struct pci_dev *pdev;
|
||||
struct msix_entry *msix_entries;
|
||||
void __iomem *reg_base;
|
||||
struct ntb_mw *mw;
|
||||
struct {
|
||||
unsigned char max_mw;
|
||||
unsigned char max_spads;
|
||||
unsigned char max_db_bits;
|
||||
unsigned char msix_cnt;
|
||||
} limits;
|
||||
struct {
|
||||
void __iomem *ldb;
|
||||
void __iomem *ldb_mask;
|
||||
void __iomem *rdb;
|
||||
void __iomem *bar2_xlat;
|
||||
void __iomem *bar4_xlat;
|
||||
void __iomem *bar5_xlat;
|
||||
void __iomem *spad_write;
|
||||
void __iomem *spad_read;
|
||||
void __iomem *lnk_cntl;
|
||||
void __iomem *lnk_stat;
|
||||
void __iomem *spci_cmd;
|
||||
} reg_ofs;
|
||||
struct ntb_transport *ntb_transport;
|
||||
void (*event_cb)(void *handle, enum ntb_hw_event event);
|
||||
|
||||
struct ntb_db_cb *db_cb;
|
||||
unsigned char hw_type;
|
||||
unsigned char conn_type;
|
||||
unsigned char dev_type;
|
||||
unsigned char num_msix;
|
||||
unsigned char bits_per_vector;
|
||||
unsigned char max_cbs;
|
||||
unsigned char link_width;
|
||||
unsigned char link_speed;
|
||||
unsigned char link_status;
|
||||
unsigned char split_bar;
|
||||
|
||||
struct delayed_work hb_timer;
|
||||
unsigned long last_ts;
|
||||
|
||||
struct delayed_work lr_timer;
|
||||
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *debugfs_info;
|
||||
|
||||
unsigned int wa_flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* ntb_max_cbs() - return the max callbacks
|
||||
* @ndev: pointer to ntb_device instance
|
||||
*
|
||||
* Given the ntb pointer, return the maximum number of callbacks
|
||||
*
|
||||
* RETURNS: the maximum number of callbacks
|
||||
*/
|
||||
static inline unsigned char ntb_max_cbs(struct ntb_device *ndev)
|
||||
{
|
||||
return ndev->max_cbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_max_mw() - return the max number of memory windows
|
||||
* @ndev: pointer to ntb_device instance
|
||||
*
|
||||
* Given the ntb pointer, return the maximum number of memory windows
|
||||
*
|
||||
* RETURNS: the maximum number of memory windows
|
||||
*/
|
||||
static inline unsigned char ntb_max_mw(struct ntb_device *ndev)
|
||||
{
|
||||
return ndev->limits.max_mw;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_hw_link_status() - return the hardware link status
|
||||
* @ndev: pointer to ntb_device instance
|
||||
*
|
||||
* Returns true if the hardware is connected to the remote system
|
||||
*
|
||||
* RETURNS: true or false based on the hardware link state
|
||||
*/
|
||||
static inline bool ntb_hw_link_status(struct ntb_device *ndev)
|
||||
{
|
||||
return ndev->link_status == NTB_LINK_UP;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_query_pdev() - return the pci_dev pointer
|
||||
* @ndev: pointer to ntb_device instance
|
||||
*
|
||||
* Given the ntb pointer, return the pci_dev pointer for the NTB hardware device
|
||||
*
|
||||
* RETURNS: a pointer to the ntb pci_dev
|
||||
*/
|
||||
static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
|
||||
{
|
||||
return ndev->pdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_query_debugfs() - return the debugfs pointer
|
||||
* @ndev: pointer to ntb_device instance
|
||||
*
|
||||
* Given the ntb pointer, return the debugfs directory pointer for the NTB
|
||||
* hardware device
|
||||
*
|
||||
* RETURNS: a pointer to the debugfs directory
|
||||
*/
|
||||
static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev)
|
||||
{
|
||||
return ndev->debugfs_dir;
|
||||
}
|
||||
|
||||
struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
|
||||
void *transport);
|
||||
void ntb_unregister_transport(struct ntb_device *ndev);
|
||||
void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr);
|
||||
int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
|
||||
void *data, int (*db_cb_func)(void *data,
|
||||
int db_num));
|
||||
void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx);
|
||||
int ntb_register_event_callback(struct ntb_device *ndev,
|
||||
void (*event_cb_func)(void *handle,
|
||||
enum ntb_hw_event event));
|
||||
void ntb_unregister_event_callback(struct ntb_device *ndev);
|
||||
int ntb_get_max_spads(struct ntb_device *ndev);
|
||||
int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
|
||||
int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
|
||||
int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
|
||||
int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
|
||||
resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw);
|
||||
void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
|
||||
u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
|
||||
void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx);
|
||||
void *ntb_find_transport(struct pci_dev *pdev);
|
||||
|
||||
int ntb_transport_init(struct pci_dev *pdev);
|
||||
void ntb_transport_free(void *transport);
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Intel PCIe NTB Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
*/
|
||||
|
||||
#define NTB_LINK_STATUS_ACTIVE 0x2000
|
||||
#define NTB_LINK_SPEED_MASK 0x000f
|
||||
#define NTB_LINK_WIDTH_MASK 0x03f0
|
||||
|
||||
#define SNB_MSIX_CNT 4
|
||||
#define SNB_MAX_B2B_SPADS 16
|
||||
#define SNB_MAX_COMPAT_SPADS 16
|
||||
/* Reserve the uppermost bit for link interrupt */
|
||||
#define SNB_MAX_DB_BITS 15
|
||||
#define SNB_LINK_DB 15
|
||||
#define SNB_DB_BITS_PER_VEC 5
|
||||
#define HSX_SPLITBAR_MAX_MW 3
|
||||
#define SNB_MAX_MW 2
|
||||
#define SNB_ERRATA_MAX_MW 1
|
||||
|
||||
#define SNB_DB_HW_LINK 0x8000
|
||||
|
||||
#define SNB_UNCERRSTS_OFFSET 0x014C
|
||||
#define SNB_CORERRSTS_OFFSET 0x0158
|
||||
#define SNB_LINK_STATUS_OFFSET 0x01A2
|
||||
#define SNB_PCICMD_OFFSET 0x0504
|
||||
#define SNB_DEVCTRL_OFFSET 0x0598
|
||||
#define SNB_DEVSTS_OFFSET 0x059A
|
||||
#define SNB_SLINK_STATUS_OFFSET 0x05A2
|
||||
|
||||
#define SNB_PBAR2LMT_OFFSET 0x0000
|
||||
#define SNB_PBAR4LMT_OFFSET 0x0008
|
||||
#define SNB_PBAR5LMT_OFFSET 0x000C
|
||||
#define SNB_PBAR2XLAT_OFFSET 0x0010
|
||||
#define SNB_PBAR4XLAT_OFFSET 0x0018
|
||||
#define SNB_PBAR5XLAT_OFFSET 0x001C
|
||||
#define SNB_SBAR2LMT_OFFSET 0x0020
|
||||
#define SNB_SBAR4LMT_OFFSET 0x0028
|
||||
#define SNB_SBAR5LMT_OFFSET 0x002C
|
||||
#define SNB_SBAR2XLAT_OFFSET 0x0030
|
||||
#define SNB_SBAR4XLAT_OFFSET 0x0038
|
||||
#define SNB_SBAR5XLAT_OFFSET 0x003C
|
||||
#define SNB_SBAR0BASE_OFFSET 0x0040
|
||||
#define SNB_SBAR2BASE_OFFSET 0x0048
|
||||
#define SNB_SBAR4BASE_OFFSET 0x0050
|
||||
#define SNB_SBAR5BASE_OFFSET 0x0054
|
||||
#define SNB_NTBCNTL_OFFSET 0x0058
|
||||
#define SNB_SBDF_OFFSET 0x005C
|
||||
#define SNB_PDOORBELL_OFFSET 0x0060
|
||||
#define SNB_PDBMSK_OFFSET 0x0062
|
||||
#define SNB_SDOORBELL_OFFSET 0x0064
|
||||
#define SNB_SDBMSK_OFFSET 0x0066
|
||||
#define SNB_USMEMMISS_OFFSET 0x0070
|
||||
#define SNB_SPAD_OFFSET 0x0080
|
||||
#define SNB_SPADSEMA4_OFFSET 0x00c0
|
||||
#define SNB_WCCNTRL_OFFSET 0x00e0
|
||||
#define SNB_B2B_SPAD_OFFSET 0x0100
|
||||
#define SNB_B2B_DOORBELL_OFFSET 0x0140
|
||||
#define SNB_B2B_XLAT_OFFSETL 0x0144
|
||||
#define SNB_B2B_XLAT_OFFSETU 0x0148
|
||||
|
||||
/*
|
||||
* The addresses are setup so the 32bit BARs can function. Thus
|
||||
* the addresses are all in 32bit space
|
||||
*/
|
||||
#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL
|
||||
#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL
|
||||
#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL
|
||||
#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL
|
||||
#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL
|
||||
#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL
|
||||
#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL
|
||||
#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL
|
||||
|
||||
#define BWD_MSIX_CNT 34
|
||||
#define BWD_MAX_SPADS 16
|
||||
#define BWD_MAX_DB_BITS 34
|
||||
#define BWD_DB_BITS_PER_VEC 1
|
||||
#define BWD_MAX_MW 2
|
||||
|
||||
#define BWD_PCICMD_OFFSET 0xb004
|
||||
#define BWD_MBAR23_OFFSET 0xb018
|
||||
#define BWD_MBAR45_OFFSET 0xb020
|
||||
#define BWD_DEVCTRL_OFFSET 0xb048
|
||||
#define BWD_LINK_STATUS_OFFSET 0xb052
|
||||
#define BWD_ERRCORSTS_OFFSET 0xb110
|
||||
|
||||
#define BWD_SBAR2XLAT_OFFSET 0x0008
|
||||
#define BWD_SBAR4XLAT_OFFSET 0x0010
|
||||
#define BWD_PDOORBELL_OFFSET 0x0020
|
||||
#define BWD_PDBMSK_OFFSET 0x0028
|
||||
#define BWD_NTBCNTL_OFFSET 0x0060
|
||||
#define BWD_EBDF_OFFSET 0x0064
|
||||
#define BWD_SPAD_OFFSET 0x0080
|
||||
#define BWD_SPADSEMA_OFFSET 0x00c0
|
||||
#define BWD_STKYSPAD_OFFSET 0x00c4
|
||||
#define BWD_PBAR2XLAT_OFFSET 0x8008
|
||||
#define BWD_PBAR4XLAT_OFFSET 0x8010
|
||||
#define BWD_B2B_DOORBELL_OFFSET 0x8020
|
||||
#define BWD_B2B_SPAD_OFFSET 0x8080
|
||||
#define BWD_B2B_SPADSEMA_OFFSET 0x80c0
|
||||
#define BWD_B2B_STKYSPAD_OFFSET 0x80c4
|
||||
|
||||
#define BWD_MODPHY_PCSREG4 0x1c004
|
||||
#define BWD_MODPHY_PCSREG6 0x1c006
|
||||
|
||||
#define BWD_IP_BASE 0xC000
|
||||
#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024)
|
||||
#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180)
|
||||
#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040)
|
||||
#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324)
|
||||
|
||||
#define BWD_DESKEWSTS_DBERR (1 << 15)
|
||||
#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20)
|
||||
#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2)
|
||||
#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF
|
||||
|
||||
#define NTB_CNTL_CFG_LOCK (1 << 0)
|
||||
#define NTB_CNTL_LINK_DISABLE (1 << 1)
|
||||
#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2)
|
||||
#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4)
|
||||
#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6)
|
||||
#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8)
|
||||
#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12)
|
||||
#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14)
|
||||
#define BWD_CNTL_LINK_DOWN (1 << 16)
|
||||
|
||||
#define NTB_PPD_OFFSET 0x00D4
|
||||
#define SNB_PPD_CONN_TYPE 0x0003
|
||||
#define SNB_PPD_DEV_TYPE 0x0010
|
||||
#define SNB_PPD_SPLIT_BAR (1 << 6)
|
||||
#define BWD_PPD_INIT_LINK 0x0008
|
||||
#define BWD_PPD_CONN_TYPE 0x0300
|
||||
#define BWD_PPD_DEV_TYPE 0x1000
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
config NTB_PINGPONG
|
||||
tristate "NTB Ping Pong Test Client"
|
||||
help
|
||||
This is a simple ping pong driver that exercises the scratchpads and
|
||||
doorbells of the ntb hardware. This driver may be used to test that
|
||||
your ntb hardware and drivers are functioning at a basic level.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NTB_TOOL
|
||||
tristate "NTB Debugging Tool Test Client"
|
||||
help
|
||||
This is a simple debugging driver that enables the doorbell and
|
||||
scratchpad registers to be read and written from the debugfs. This
|
||||
enables more complicated debugging to be scripted from user space.
|
||||
This driver may be used to test that your ntb hardware and drivers are
|
||||
functioning at a basic level.
|
||||
|
||||
If unsure, say N.
|
|
@ -0,0 +1,2 @@
|
|||
obj-$(CONFIG_NTB_PINGPONG) += ntb_pingpong.o
|
||||
obj-$(CONFIG_NTB_TOOL) += ntb_tool.o
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* PCIe NTB Pingpong Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Allen Hubbe <Allen.Hubbe@emc.com>
|
||||
*/
|
||||
|
||||
/* Note: load this module with option 'dyndbg=+p' */
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/ntb.h>
|
||||
|
||||
#define DRIVER_NAME "ntb_pingpong"
|
||||
#define DRIVER_DESCRIPTION "PCIe NTB Simple Pingpong Client"
|
||||
|
||||
#define DRIVER_LICENSE "Dual BSD/GPL"
|
||||
#define DRIVER_VERSION "1.0"
|
||||
#define DRIVER_RELDATE "24 March 2015"
|
||||
#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
|
||||
|
||||
MODULE_LICENSE(DRIVER_LICENSE);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
|
||||
|
||||
static unsigned int unsafe;
|
||||
module_param(unsafe, uint, 0644);
|
||||
MODULE_PARM_DESC(unsafe, "Run even though ntb operations may be unsafe");
|
||||
|
||||
static unsigned int delay_ms = 1000;
|
||||
module_param(delay_ms, uint, 0644);
|
||||
MODULE_PARM_DESC(delay_ms, "Milliseconds to delay the response to peer");
|
||||
|
||||
static unsigned long db_init = 0x7;
|
||||
module_param(db_init, ulong, 0644);
|
||||
MODULE_PARM_DESC(delay_ms, "Initial doorbell bits to ring on the peer");
|
||||
|
||||
struct pp_ctx {
|
||||
struct ntb_dev *ntb;
|
||||
u64 db_bits;
|
||||
/* synchronize access to db_bits by ping and pong */
|
||||
spinlock_t db_lock;
|
||||
struct timer_list db_timer;
|
||||
unsigned long db_delay;
|
||||
};
|
||||
|
||||
static void pp_ping(unsigned long ctx)
|
||||
{
|
||||
struct pp_ctx *pp = (void *)ctx;
|
||||
unsigned long irqflags;
|
||||
u64 db_bits, db_mask;
|
||||
u32 spad_rd, spad_wr;
|
||||
|
||||
spin_lock_irqsave(&pp->db_lock, irqflags);
|
||||
{
|
||||
db_mask = ntb_db_valid_mask(pp->ntb);
|
||||
db_bits = ntb_db_read(pp->ntb);
|
||||
|
||||
if (db_bits) {
|
||||
dev_dbg(&pp->ntb->dev,
|
||||
"Masked pongs %#llx\n",
|
||||
db_bits);
|
||||
ntb_db_clear(pp->ntb, db_bits);
|
||||
}
|
||||
|
||||
db_bits = ((pp->db_bits | db_bits) << 1) & db_mask;
|
||||
|
||||
if (!db_bits)
|
||||
db_bits = db_init;
|
||||
|
||||
spad_rd = ntb_spad_read(pp->ntb, 0);
|
||||
spad_wr = spad_rd + 1;
|
||||
|
||||
dev_dbg(&pp->ntb->dev,
|
||||
"Ping bits %#llx read %#x write %#x\n",
|
||||
db_bits, spad_rd, spad_wr);
|
||||
|
||||
ntb_peer_spad_write(pp->ntb, 0, spad_wr);
|
||||
ntb_peer_db_set(pp->ntb, db_bits);
|
||||
ntb_db_clear_mask(pp->ntb, db_mask);
|
||||
|
||||
pp->db_bits = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&pp->db_lock, irqflags);
|
||||
}
|
||||
|
||||
static void pp_link_event(void *ctx)
|
||||
{
|
||||
struct pp_ctx *pp = ctx;
|
||||
|
||||
if (ntb_link_is_up(pp->ntb, NULL, NULL) == 1) {
|
||||
dev_dbg(&pp->ntb->dev, "link is up\n");
|
||||
pp_ping((unsigned long)pp);
|
||||
} else {
|
||||
dev_dbg(&pp->ntb->dev, "link is down\n");
|
||||
del_timer(&pp->db_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void pp_db_event(void *ctx, int vec)
|
||||
{
|
||||
struct pp_ctx *pp = ctx;
|
||||
u64 db_bits, db_mask;
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&pp->db_lock, irqflags);
|
||||
{
|
||||
db_mask = ntb_db_vector_mask(pp->ntb, vec);
|
||||
db_bits = db_mask & ntb_db_read(pp->ntb);
|
||||
ntb_db_set_mask(pp->ntb, db_mask);
|
||||
ntb_db_clear(pp->ntb, db_bits);
|
||||
|
||||
pp->db_bits |= db_bits;
|
||||
|
||||
mod_timer(&pp->db_timer, jiffies + pp->db_delay);
|
||||
|
||||
dev_dbg(&pp->ntb->dev,
|
||||
"Pong vec %d bits %#llx\n",
|
||||
vec, db_bits);
|
||||
}
|
||||
spin_unlock_irqrestore(&pp->db_lock, irqflags);
|
||||
}
|
||||
|
||||
static const struct ntb_ctx_ops pp_ops = {
|
||||
.link_event = pp_link_event,
|
||||
.db_event = pp_db_event,
|
||||
};
|
||||
|
||||
static int pp_probe(struct ntb_client *client,
|
||||
struct ntb_dev *ntb)
|
||||
{
|
||||
struct pp_ctx *pp;
|
||||
int rc;
|
||||
|
||||
if (ntb_db_is_unsafe(ntb)) {
|
||||
dev_dbg(&ntb->dev, "doorbell is unsafe\n");
|
||||
if (!unsafe) {
|
||||
rc = -EINVAL;
|
||||
goto err_pp;
|
||||
}
|
||||
}
|
||||
|
||||
if (ntb_spad_is_unsafe(ntb)) {
|
||||
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
|
||||
if (!unsafe) {
|
||||
rc = -EINVAL;
|
||||
goto err_pp;
|
||||
}
|
||||
}
|
||||
|
||||
pp = kmalloc(sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp) {
|
||||
rc = -ENOMEM;
|
||||
goto err_pp;
|
||||
}
|
||||
|
||||
pp->ntb = ntb;
|
||||
pp->db_bits = 0;
|
||||
spin_lock_init(&pp->db_lock);
|
||||
setup_timer(&pp->db_timer, pp_ping, (unsigned long)pp);
|
||||
pp->db_delay = msecs_to_jiffies(delay_ms);
|
||||
|
||||
rc = ntb_set_ctx(ntb, pp, &pp_ops);
|
||||
if (rc)
|
||||
goto err_ctx;
|
||||
|
||||
ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
|
||||
ntb_link_event(ntb);
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx:
|
||||
kfree(pp);
|
||||
err_pp:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void pp_remove(struct ntb_client *client,
|
||||
struct ntb_dev *ntb)
|
||||
{
|
||||
struct pp_ctx *pp = ntb->ctx;
|
||||
|
||||
ntb_clear_ctx(ntb);
|
||||
del_timer_sync(&pp->db_timer);
|
||||
ntb_link_disable(ntb);
|
||||
|
||||
kfree(pp);
|
||||
}
|
||||
|
||||
static struct ntb_client pp_client = {
|
||||
.ops = {
|
||||
.probe = pp_probe,
|
||||
.remove = pp_remove,
|
||||
},
|
||||
};
|
||||
module_ntb_client(pp_client);
|
|
@ -0,0 +1,556 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* PCIe NTB Debugging Tool Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Allen Hubbe <Allen.Hubbe@emc.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* How to use this tool, by example.
|
||||
*
|
||||
* Assuming $DBG_DIR is something like:
|
||||
* '/sys/kernel/debug/ntb_tool/0000:00:03.0'
|
||||
*
|
||||
* Eg: check if clearing the doorbell mask generates an interrupt.
|
||||
*
|
||||
* # Set the doorbell mask
|
||||
* root@self# echo 's 1' > $DBG_DIR/mask
|
||||
*
|
||||
* # Ring the doorbell from the peer
|
||||
* root@peer# echo 's 1' > $DBG_DIR/peer_db
|
||||
*
|
||||
* # Clear the doorbell mask
|
||||
* root@self# echo 'c 1' > $DBG_DIR/mask
|
||||
*
|
||||
* Observe debugging output in dmesg or your console. You should see a
|
||||
* doorbell event triggered by clearing the mask. If not, this may indicate an
|
||||
* issue with the hardware that needs to be worked around in the driver.
|
||||
*
|
||||
* Eg: read and write scratchpad registers
|
||||
*
|
||||
* root@peer# echo '0 0x01010101 1 0x7f7f7f7f' > $DBG_DIR/peer_spad
|
||||
*
|
||||
* root@self# cat $DBG_DIR/spad
|
||||
*
|
||||
* Observe that spad 0 and 1 have the values set by the peer.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/ntb.h>
|
||||
|
||||
#define DRIVER_NAME "ntb_tool"
|
||||
#define DRIVER_DESCRIPTION "PCIe NTB Debugging Tool"
|
||||
|
||||
#define DRIVER_LICENSE "Dual BSD/GPL"
|
||||
#define DRIVER_VERSION "1.0"
|
||||
#define DRIVER_RELDATE "22 April 2015"
|
||||
#define DRIVER_AUTHOR "Allen Hubbe <Allen.Hubbe@emc.com>"
|
||||
|
||||
MODULE_LICENSE(DRIVER_LICENSE);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
|
||||
|
||||
static struct dentry *tool_dbgfs;
|
||||
|
||||
struct tool_ctx {
|
||||
struct ntb_dev *ntb;
|
||||
struct dentry *dbgfs;
|
||||
};
|
||||
|
||||
#define SPAD_FNAME_SIZE 0x10
|
||||
#define INT_PTR(x) ((void *)(unsigned long)x)
|
||||
#define PTR_INT(x) ((int)(unsigned long)x)
|
||||
|
||||
#define TOOL_FOPS_RDWR(__name, __read, __write) \
|
||||
const struct file_operations __name = { \
|
||||
.owner = THIS_MODULE, \
|
||||
.open = simple_open, \
|
||||
.read = __read, \
|
||||
.write = __write, \
|
||||
}
|
||||
|
||||
static void tool_link_event(void *ctx)
|
||||
{
|
||||
struct tool_ctx *tc = ctx;
|
||||
enum ntb_speed speed;
|
||||
enum ntb_width width;
|
||||
int up;
|
||||
|
||||
up = ntb_link_is_up(tc->ntb, &speed, &width);
|
||||
|
||||
dev_dbg(&tc->ntb->dev, "link is %s speed %d width %d\n",
|
||||
up ? "up" : "down", speed, width);
|
||||
}
|
||||
|
||||
static void tool_db_event(void *ctx, int vec)
|
||||
{
|
||||
struct tool_ctx *tc = ctx;
|
||||
u64 db_bits, db_mask;
|
||||
|
||||
db_mask = ntb_db_vector_mask(tc->ntb, vec);
|
||||
db_bits = ntb_db_read(tc->ntb);
|
||||
|
||||
dev_dbg(&tc->ntb->dev, "doorbell vec %d mask %#llx bits %#llx\n",
|
||||
vec, db_mask, db_bits);
|
||||
}
|
||||
|
||||
static const struct ntb_ctx_ops tool_ops = {
|
||||
.link_event = tool_link_event,
|
||||
.db_event = tool_db_event,
|
||||
};
|
||||
|
||||
static ssize_t tool_dbfn_read(struct tool_ctx *tc, char __user *ubuf,
|
||||
size_t size, loff_t *offp,
|
||||
u64 (*db_read_fn)(struct ntb_dev *))
|
||||
{
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
ssize_t pos, rc;
|
||||
|
||||
if (!db_read_fn)
|
||||
return -EINVAL;
|
||||
|
||||
buf_size = min_t(size_t, size, 0x20);
|
||||
|
||||
buf = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos = scnprintf(buf, buf_size, "%#llx\n",
|
||||
db_read_fn(tc->ntb));
|
||||
|
||||
rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t tool_dbfn_write(struct tool_ctx *tc,
|
||||
const char __user *ubuf,
|
||||
size_t size, loff_t *offp,
|
||||
int (*db_set_fn)(struct ntb_dev *, u64),
|
||||
int (*db_clear_fn)(struct ntb_dev *, u64))
|
||||
{
|
||||
u64 db_bits;
|
||||
char *buf, cmd;
|
||||
ssize_t rc;
|
||||
int n;
|
||||
|
||||
buf = kmalloc(size + 1, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
|
||||
if (rc < 0) {
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf[size] = 0;
|
||||
|
||||
n = sscanf(buf, "%c %lli", &cmd, &db_bits);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if (n != 2) {
|
||||
rc = -EINVAL;
|
||||
} else if (cmd == 's') {
|
||||
if (!db_set_fn)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = db_set_fn(tc->ntb, db_bits);
|
||||
} else if (cmd == 'c') {
|
||||
if (!db_clear_fn)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = db_clear_fn(tc->ntb, db_bits);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc ? : size;
|
||||
}
|
||||
|
||||
static ssize_t tool_spadfn_read(struct tool_ctx *tc, char __user *ubuf,
|
||||
size_t size, loff_t *offp,
|
||||
u32 (*spad_read_fn)(struct ntb_dev *, int))
|
||||
{
|
||||
size_t buf_size;
|
||||
char *buf;
|
||||
ssize_t pos, rc;
|
||||
int i, spad_count;
|
||||
|
||||
if (!spad_read_fn)
|
||||
return -EINVAL;
|
||||
|
||||
buf_size = min_t(size_t, size, 0x100);
|
||||
|
||||
buf = kmalloc(buf_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos = 0;
|
||||
|
||||
spad_count = ntb_spad_count(tc->ntb);
|
||||
for (i = 0; i < spad_count; ++i) {
|
||||
pos += scnprintf(buf + pos, buf_size - pos, "%d\t%#x\n",
|
||||
i, spad_read_fn(tc->ntb, i));
|
||||
}
|
||||
|
||||
rc = simple_read_from_buffer(ubuf, size, offp, buf, pos);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t tool_spadfn_write(struct tool_ctx *tc,
|
||||
const char __user *ubuf,
|
||||
size_t size, loff_t *offp,
|
||||
int (*spad_write_fn)(struct ntb_dev *,
|
||||
int, u32))
|
||||
{
|
||||
int spad_idx;
|
||||
u32 spad_val;
|
||||
char *buf;
|
||||
int pos, n;
|
||||
ssize_t rc;
|
||||
|
||||
if (!spad_write_fn) {
|
||||
dev_dbg(&tc->ntb->dev, "no spad write fn\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = kmalloc(size + 1, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(buf, size, offp, ubuf, size);
|
||||
if (rc < 0) {
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
buf[size] = 0;
|
||||
|
||||
n = sscanf(buf, "%d %i%n", &spad_idx, &spad_val, &pos);
|
||||
while (n == 2) {
|
||||
rc = spad_write_fn(tc->ntb, spad_idx, spad_val);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
n = sscanf(buf + pos, "%d %i%n", &spad_idx, &spad_val, &pos);
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
rc = n;
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return rc ? : size;
|
||||
}
|
||||
|
||||
static ssize_t tool_db_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->db_read);
|
||||
}
|
||||
|
||||
static ssize_t tool_db_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->db_set,
|
||||
tc->ntb->ops->db_clear);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_db_fops,
|
||||
tool_db_read,
|
||||
tool_db_write);
|
||||
|
||||
static ssize_t tool_mask_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->db_read_mask);
|
||||
}
|
||||
|
||||
static ssize_t tool_mask_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->db_set_mask,
|
||||
tc->ntb->ops->db_clear_mask);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_mask_fops,
|
||||
tool_mask_read,
|
||||
tool_mask_write);
|
||||
|
||||
static ssize_t tool_peer_db_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_db_read);
|
||||
}
|
||||
|
||||
static ssize_t tool_peer_db_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_db_set,
|
||||
tc->ntb->ops->peer_db_clear);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_peer_db_fops,
|
||||
tool_peer_db_read,
|
||||
tool_peer_db_write);
|
||||
|
||||
static ssize_t tool_peer_mask_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_db_read_mask);
|
||||
}
|
||||
|
||||
static ssize_t tool_peer_mask_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_dbfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_db_set_mask,
|
||||
tc->ntb->ops->peer_db_clear_mask);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_peer_mask_fops,
|
||||
tool_peer_mask_read,
|
||||
tool_peer_mask_write);
|
||||
|
||||
static ssize_t tool_spad_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_spadfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->spad_read);
|
||||
}
|
||||
|
||||
static ssize_t tool_spad_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_spadfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->spad_write);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_spad_fops,
|
||||
tool_spad_read,
|
||||
tool_spad_write);
|
||||
|
||||
static ssize_t tool_peer_spad_read(struct file *filep, char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_spadfn_read(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_spad_read);
|
||||
}
|
||||
|
||||
static ssize_t tool_peer_spad_write(struct file *filep, const char __user *ubuf,
|
||||
size_t size, loff_t *offp)
|
||||
{
|
||||
struct tool_ctx *tc = filep->private_data;
|
||||
|
||||
return tool_spadfn_write(tc, ubuf, size, offp,
|
||||
tc->ntb->ops->peer_spad_write);
|
||||
}
|
||||
|
||||
static TOOL_FOPS_RDWR(tool_peer_spad_fops,
|
||||
tool_peer_spad_read,
|
||||
tool_peer_spad_write);
|
||||
|
||||
static void tool_setup_dbgfs(struct tool_ctx *tc)
|
||||
{
|
||||
/* This modules is useless without dbgfs... */
|
||||
if (!tool_dbgfs) {
|
||||
tc->dbgfs = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
tc->dbgfs = debugfs_create_dir(dev_name(&tc->ntb->dev),
|
||||
tool_dbgfs);
|
||||
if (!tc->dbgfs)
|
||||
return;
|
||||
|
||||
debugfs_create_file("db", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_db_fops);
|
||||
|
||||
debugfs_create_file("mask", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_mask_fops);
|
||||
|
||||
debugfs_create_file("peer_db", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_peer_db_fops);
|
||||
|
||||
debugfs_create_file("peer_mask", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_peer_mask_fops);
|
||||
|
||||
debugfs_create_file("spad", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_spad_fops);
|
||||
|
||||
debugfs_create_file("peer_spad", S_IRUSR | S_IWUSR, tc->dbgfs,
|
||||
tc, &tool_peer_spad_fops);
|
||||
}
|
||||
|
||||
static int tool_probe(struct ntb_client *self, struct ntb_dev *ntb)
|
||||
{
|
||||
struct tool_ctx *tc;
|
||||
int rc;
|
||||
|
||||
if (ntb_db_is_unsafe(ntb))
|
||||
dev_dbg(&ntb->dev, "doorbell is unsafe\n");
|
||||
|
||||
if (ntb_spad_is_unsafe(ntb))
|
||||
dev_dbg(&ntb->dev, "scratchpad is unsafe\n");
|
||||
|
||||
tc = kmalloc(sizeof(*tc), GFP_KERNEL);
|
||||
if (!tc) {
|
||||
rc = -ENOMEM;
|
||||
goto err_tc;
|
||||
}
|
||||
|
||||
tc->ntb = ntb;
|
||||
|
||||
tool_setup_dbgfs(tc);
|
||||
|
||||
rc = ntb_set_ctx(ntb, tc, &tool_ops);
|
||||
if (rc)
|
||||
goto err_ctx;
|
||||
|
||||
ntb_link_enable(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
|
||||
ntb_link_event(ntb);
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx:
|
||||
debugfs_remove_recursive(tc->dbgfs);
|
||||
kfree(tc);
|
||||
err_tc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void tool_remove(struct ntb_client *self, struct ntb_dev *ntb)
|
||||
{
|
||||
struct tool_ctx *tc = ntb->ctx;
|
||||
|
||||
ntb_clear_ctx(ntb);
|
||||
ntb_link_disable(ntb);
|
||||
|
||||
debugfs_remove_recursive(tc->dbgfs);
|
||||
kfree(tc);
|
||||
}
|
||||
|
||||
static struct ntb_client tool_client = {
|
||||
.ops = {
|
||||
.probe = tool_probe,
|
||||
.remove = tool_remove,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init tool_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (debugfs_initialized())
|
||||
tool_dbgfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
||||
|
||||
rc = ntb_register_client(&tool_client);
|
||||
if (rc)
|
||||
goto err_client;
|
||||
|
||||
return 0;
|
||||
|
||||
err_client:
|
||||
debugfs_remove_recursive(tool_dbgfs);
|
||||
return rc;
|
||||
}
|
||||
module_init(tool_init);
|
||||
|
||||
static void __exit tool_exit(void)
|
||||
{
|
||||
ntb_unregister_client(&tool_client);
|
||||
debugfs_remove_recursive(tool_dbgfs);
|
||||
}
|
||||
module_exit(tool_exit);
|
|
@ -4,15 +4,20 @@
|
|||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -40,49 +45,940 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Intel PCIe NTB Linux driver
|
||||
* PCIe NTB Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
* Allen Hubbe <Allen.Hubbe@emc.com>
|
||||
*/
|
||||
|
||||
struct ntb_transport_qp;
|
||||
#ifndef _NTB_H_
|
||||
#define _NTB_H_
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct ntb_client;
|
||||
struct ntb_dev;
|
||||
struct pci_dev;
|
||||
|
||||
/**
|
||||
* enum ntb_topo - NTB connection topology
|
||||
* @NTB_TOPO_NONE: Topology is unknown or invalid.
|
||||
* @NTB_TOPO_PRI: On primary side of local ntb.
|
||||
* @NTB_TOPO_SEC: On secondary side of remote ntb.
|
||||
* @NTB_TOPO_B2B_USD: On primary side of local ntb upstream of remote ntb.
|
||||
* @NTB_TOPO_B2B_DSD: On primary side of local ntb downstream of remote ntb.
|
||||
*/
|
||||
enum ntb_topo {
|
||||
NTB_TOPO_NONE = -1,
|
||||
NTB_TOPO_PRI,
|
||||
NTB_TOPO_SEC,
|
||||
NTB_TOPO_B2B_USD,
|
||||
NTB_TOPO_B2B_DSD,
|
||||
};
|
||||
|
||||
static inline int ntb_topo_is_b2b(enum ntb_topo topo)
|
||||
{
|
||||
switch ((int)topo) {
|
||||
case NTB_TOPO_B2B_USD:
|
||||
case NTB_TOPO_B2B_DSD:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *ntb_topo_string(enum ntb_topo topo)
|
||||
{
|
||||
switch (topo) {
|
||||
case NTB_TOPO_NONE: return "NTB_TOPO_NONE";
|
||||
case NTB_TOPO_PRI: return "NTB_TOPO_PRI";
|
||||
case NTB_TOPO_SEC: return "NTB_TOPO_SEC";
|
||||
case NTB_TOPO_B2B_USD: return "NTB_TOPO_B2B_USD";
|
||||
case NTB_TOPO_B2B_DSD: return "NTB_TOPO_B2B_DSD";
|
||||
}
|
||||
return "NTB_TOPO_INVALID";
|
||||
}
|
||||
|
||||
/**
|
||||
* enum ntb_speed - NTB link training speed
|
||||
* @NTB_SPEED_AUTO: Request the max supported speed.
|
||||
* @NTB_SPEED_NONE: Link is not trained to any speed.
|
||||
* @NTB_SPEED_GEN1: Link is trained to gen1 speed.
|
||||
* @NTB_SPEED_GEN2: Link is trained to gen2 speed.
|
||||
* @NTB_SPEED_GEN3: Link is trained to gen3 speed.
|
||||
*/
|
||||
enum ntb_speed {
|
||||
NTB_SPEED_AUTO = -1,
|
||||
NTB_SPEED_NONE = 0,
|
||||
NTB_SPEED_GEN1 = 1,
|
||||
NTB_SPEED_GEN2 = 2,
|
||||
NTB_SPEED_GEN3 = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ntb_width - NTB link training width
|
||||
* @NTB_WIDTH_AUTO: Request the max supported width.
|
||||
* @NTB_WIDTH_NONE: Link is not trained to any width.
|
||||
* @NTB_WIDTH_1: Link is trained to 1 lane width.
|
||||
* @NTB_WIDTH_2: Link is trained to 2 lane width.
|
||||
* @NTB_WIDTH_4: Link is trained to 4 lane width.
|
||||
* @NTB_WIDTH_8: Link is trained to 8 lane width.
|
||||
* @NTB_WIDTH_12: Link is trained to 12 lane width.
|
||||
* @NTB_WIDTH_16: Link is trained to 16 lane width.
|
||||
* @NTB_WIDTH_32: Link is trained to 32 lane width.
|
||||
*/
|
||||
enum ntb_width {
|
||||
NTB_WIDTH_AUTO = -1,
|
||||
NTB_WIDTH_NONE = 0,
|
||||
NTB_WIDTH_1 = 1,
|
||||
NTB_WIDTH_2 = 2,
|
||||
NTB_WIDTH_4 = 4,
|
||||
NTB_WIDTH_8 = 8,
|
||||
NTB_WIDTH_12 = 12,
|
||||
NTB_WIDTH_16 = 16,
|
||||
NTB_WIDTH_32 = 32,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ntb_client_ops - ntb client operations
|
||||
* @probe: Notify client of a new device.
|
||||
* @remove: Notify client to remove a device.
|
||||
*/
|
||||
struct ntb_client_ops {
|
||||
int (*probe)(struct ntb_client *client, struct ntb_dev *ntb);
|
||||
void (*remove)(struct ntb_client *client, struct ntb_dev *ntb);
|
||||
};
|
||||
|
||||
static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops)
|
||||
{
|
||||
/* commented callbacks are not required: */
|
||||
return
|
||||
ops->probe &&
|
||||
ops->remove &&
|
||||
1;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ntb_ctx_ops - ntb driver context operations
|
||||
* @link_event: See ntb_link_event().
|
||||
* @db_event: See ntb_db_event().
|
||||
*/
|
||||
struct ntb_ctx_ops {
|
||||
void (*link_event)(void *ctx);
|
||||
void (*db_event)(void *ctx, int db_vector);
|
||||
};
|
||||
|
||||
static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops)
|
||||
{
|
||||
/* commented callbacks are not required: */
|
||||
return
|
||||
/* ops->link_event && */
|
||||
/* ops->db_event && */
|
||||
1;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ntb_ctx_ops - ntb device operations
|
||||
* @mw_count: See ntb_mw_count().
|
||||
* @mw_get_range: See ntb_mw_get_range().
|
||||
* @mw_set_trans: See ntb_mw_set_trans().
|
||||
* @mw_clear_trans: See ntb_mw_clear_trans().
|
||||
* @link_is_up: See ntb_link_is_up().
|
||||
* @link_enable: See ntb_link_enable().
|
||||
* @link_disable: See ntb_link_disable().
|
||||
* @db_is_unsafe: See ntb_db_is_unsafe().
|
||||
* @db_valid_mask: See ntb_db_valid_mask().
|
||||
* @db_vector_count: See ntb_db_vector_count().
|
||||
* @db_vector_mask: See ntb_db_vector_mask().
|
||||
* @db_read: See ntb_db_read().
|
||||
* @db_set: See ntb_db_set().
|
||||
* @db_clear: See ntb_db_clear().
|
||||
* @db_read_mask: See ntb_db_read_mask().
|
||||
* @db_set_mask: See ntb_db_set_mask().
|
||||
* @db_clear_mask: See ntb_db_clear_mask().
|
||||
* @peer_db_addr: See ntb_peer_db_addr().
|
||||
* @peer_db_read: See ntb_peer_db_read().
|
||||
* @peer_db_set: See ntb_peer_db_set().
|
||||
* @peer_db_clear: See ntb_peer_db_clear().
|
||||
* @peer_db_read_mask: See ntb_peer_db_read_mask().
|
||||
* @peer_db_set_mask: See ntb_peer_db_set_mask().
|
||||
* @peer_db_clear_mask: See ntb_peer_db_clear_mask().
|
||||
* @spad_is_unsafe: See ntb_spad_is_unsafe().
|
||||
* @spad_count: See ntb_spad_count().
|
||||
* @spad_read: See ntb_spad_read().
|
||||
* @spad_write: See ntb_spad_write().
|
||||
* @peer_spad_addr: See ntb_peer_spad_addr().
|
||||
* @peer_spad_read: See ntb_peer_spad_read().
|
||||
* @peer_spad_write: See ntb_peer_spad_write().
|
||||
*/
|
||||
struct ntb_dev_ops {
|
||||
int (*mw_count)(struct ntb_dev *ntb);
|
||||
int (*mw_get_range)(struct ntb_dev *ntb, int idx,
|
||||
phys_addr_t *base, resource_size_t *size,
|
||||
resource_size_t *align, resource_size_t *align_size);
|
||||
int (*mw_set_trans)(struct ntb_dev *ntb, int idx,
|
||||
dma_addr_t addr, resource_size_t size);
|
||||
int (*mw_clear_trans)(struct ntb_dev *ntb, int idx);
|
||||
|
||||
int (*link_is_up)(struct ntb_dev *ntb,
|
||||
enum ntb_speed *speed, enum ntb_width *width);
|
||||
int (*link_enable)(struct ntb_dev *ntb,
|
||||
enum ntb_speed max_speed, enum ntb_width max_width);
|
||||
int (*link_disable)(struct ntb_dev *ntb);
|
||||
|
||||
int (*db_is_unsafe)(struct ntb_dev *ntb);
|
||||
u64 (*db_valid_mask)(struct ntb_dev *ntb);
|
||||
int (*db_vector_count)(struct ntb_dev *ntb);
|
||||
u64 (*db_vector_mask)(struct ntb_dev *ntb, int db_vector);
|
||||
|
||||
u64 (*db_read)(struct ntb_dev *ntb);
|
||||
int (*db_set)(struct ntb_dev *ntb, u64 db_bits);
|
||||
int (*db_clear)(struct ntb_dev *ntb, u64 db_bits);
|
||||
|
||||
u64 (*db_read_mask)(struct ntb_dev *ntb);
|
||||
int (*db_set_mask)(struct ntb_dev *ntb, u64 db_bits);
|
||||
int (*db_clear_mask)(struct ntb_dev *ntb, u64 db_bits);
|
||||
|
||||
int (*peer_db_addr)(struct ntb_dev *ntb,
|
||||
phys_addr_t *db_addr, resource_size_t *db_size);
|
||||
u64 (*peer_db_read)(struct ntb_dev *ntb);
|
||||
int (*peer_db_set)(struct ntb_dev *ntb, u64 db_bits);
|
||||
int (*peer_db_clear)(struct ntb_dev *ntb, u64 db_bits);
|
||||
|
||||
u64 (*peer_db_read_mask)(struct ntb_dev *ntb);
|
||||
int (*peer_db_set_mask)(struct ntb_dev *ntb, u64 db_bits);
|
||||
int (*peer_db_clear_mask)(struct ntb_dev *ntb, u64 db_bits);
|
||||
|
||||
int (*spad_is_unsafe)(struct ntb_dev *ntb);
|
||||
int (*spad_count)(struct ntb_dev *ntb);
|
||||
|
||||
u32 (*spad_read)(struct ntb_dev *ntb, int idx);
|
||||
int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val);
|
||||
|
||||
int (*peer_spad_addr)(struct ntb_dev *ntb, int idx,
|
||||
phys_addr_t *spad_addr);
|
||||
u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx);
|
||||
int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val);
|
||||
};
|
||||
|
||||
static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops)
|
||||
{
|
||||
/* commented callbacks are not required: */
|
||||
return
|
||||
ops->mw_count &&
|
||||
ops->mw_get_range &&
|
||||
ops->mw_set_trans &&
|
||||
/* ops->mw_clear_trans && */
|
||||
ops->link_is_up &&
|
||||
ops->link_enable &&
|
||||
ops->link_disable &&
|
||||
/* ops->db_is_unsafe && */
|
||||
ops->db_valid_mask &&
|
||||
|
||||
/* both set, or both unset */
|
||||
(!ops->db_vector_count == !ops->db_vector_mask) &&
|
||||
|
||||
ops->db_read &&
|
||||
/* ops->db_set && */
|
||||
ops->db_clear &&
|
||||
/* ops->db_read_mask && */
|
||||
ops->db_set_mask &&
|
||||
ops->db_clear_mask &&
|
||||
ops->peer_db_addr &&
|
||||
/* ops->peer_db_read && */
|
||||
ops->peer_db_set &&
|
||||
/* ops->peer_db_clear && */
|
||||
/* ops->peer_db_read_mask && */
|
||||
/* ops->peer_db_set_mask && */
|
||||
/* ops->peer_db_clear_mask && */
|
||||
/* ops->spad_is_unsafe && */
|
||||
ops->spad_count &&
|
||||
ops->spad_read &&
|
||||
ops->spad_write &&
|
||||
ops->peer_spad_addr &&
|
||||
/* ops->peer_spad_read && */
|
||||
ops->peer_spad_write &&
|
||||
1;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ntb_client - client interested in ntb devices
|
||||
* @drv: Linux driver object.
|
||||
* @ops: See &ntb_client_ops.
|
||||
*/
|
||||
struct ntb_client {
|
||||
struct device_driver driver;
|
||||
int (*probe)(struct pci_dev *pdev);
|
||||
void (*remove)(struct pci_dev *pdev);
|
||||
struct device_driver drv;
|
||||
const struct ntb_client_ops ops;
|
||||
};
|
||||
|
||||
enum {
|
||||
NTB_LINK_DOWN = 0,
|
||||
NTB_LINK_UP,
|
||||
#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv)
|
||||
|
||||
/**
|
||||
* struct ntb_device - ntb device
|
||||
* @dev: Linux device object.
|
||||
* @pdev: Pci device entry of the ntb.
|
||||
* @topo: Detected topology of the ntb.
|
||||
* @ops: See &ntb_dev_ops.
|
||||
* @ctx: See &ntb_ctx_ops.
|
||||
* @ctx_ops: See &ntb_ctx_ops.
|
||||
*/
|
||||
struct ntb_dev {
|
||||
struct device dev;
|
||||
struct pci_dev *pdev;
|
||||
enum ntb_topo topo;
|
||||
const struct ntb_dev_ops *ops;
|
||||
void *ctx;
|
||||
const struct ntb_ctx_ops *ctx_ops;
|
||||
|
||||
/* private: */
|
||||
|
||||
/* synchronize setting, clearing, and calling ctx_ops */
|
||||
spinlock_t ctx_lock;
|
||||
/* block unregister until device is fully released */
|
||||
struct completion released;
|
||||
};
|
||||
|
||||
int ntb_register_client(struct ntb_client *drvr);
|
||||
void ntb_unregister_client(struct ntb_client *drvr);
|
||||
int ntb_register_client_dev(char *device_name);
|
||||
void ntb_unregister_client_dev(char *device_name);
|
||||
#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev)
|
||||
|
||||
struct ntb_queue_handlers {
|
||||
void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
|
||||
void *data, int len);
|
||||
void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
|
||||
void *data, int len);
|
||||
void (*event_handler)(void *data, int status);
|
||||
};
|
||||
/**
|
||||
* ntb_register_client() - register a client for interest in ntb devices
|
||||
* @client: Client context.
|
||||
*
|
||||
* The client will be added to the list of clients interested in ntb devices.
|
||||
* The client will be notified of any ntb devices that are not already
|
||||
* associated with a client, or if ntb devices are registered later.
|
||||
*
|
||||
* Return: Zero if the client is registered, otherwise an error number.
|
||||
*/
|
||||
#define ntb_register_client(client) \
|
||||
__ntb_register_client((client), THIS_MODULE, KBUILD_MODNAME)
|
||||
|
||||
unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp);
|
||||
unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
|
||||
struct ntb_transport_qp *
|
||||
ntb_transport_create_queue(void *data, struct pci_dev *pdev,
|
||||
const struct ntb_queue_handlers *handlers);
|
||||
void ntb_transport_free_queue(struct ntb_transport_qp *qp);
|
||||
int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
|
||||
unsigned int len);
|
||||
int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
|
||||
unsigned int len);
|
||||
void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len);
|
||||
void ntb_transport_link_up(struct ntb_transport_qp *qp);
|
||||
void ntb_transport_link_down(struct ntb_transport_qp *qp);
|
||||
bool ntb_transport_link_query(struct ntb_transport_qp *qp);
|
||||
int __ntb_register_client(struct ntb_client *client, struct module *mod,
|
||||
const char *mod_name);
|
||||
|
||||
/**
|
||||
* ntb_unregister_client() - unregister a client for interest in ntb devices
|
||||
* @client: Client context.
|
||||
*
|
||||
* The client will be removed from the list of clients interested in ntb
|
||||
* devices. If any ntb devices are associated with the client, the client will
|
||||
* be notified to remove those devices.
|
||||
*/
|
||||
void ntb_unregister_client(struct ntb_client *client);
|
||||
|
||||
#define module_ntb_client(__ntb_client) \
|
||||
module_driver(__ntb_client, ntb_register_client, \
|
||||
ntb_unregister_client)
|
||||
|
||||
/**
|
||||
* ntb_register_device() - register a ntb device
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* The device will be added to the list of ntb devices. If any clients are
|
||||
* interested in ntb devices, each client will be notified of the ntb device,
|
||||
* until at most one client accepts the device.
|
||||
*
|
||||
* Return: Zero if the device is registered, otherwise an error number.
|
||||
*/
|
||||
int ntb_register_device(struct ntb_dev *ntb);
|
||||
|
||||
/**
|
||||
* ntb_register_device() - unregister a ntb device
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* The device will be removed from the list of ntb devices. If the ntb device
|
||||
* is associated with a client, the client will be notified to remove the
|
||||
* device.
|
||||
*/
|
||||
void ntb_unregister_device(struct ntb_dev *ntb);
|
||||
|
||||
/**
|
||||
* ntb_set_ctx() - associate a driver context with an ntb device
|
||||
* @ntb: NTB device context.
|
||||
* @ctx: Driver context.
|
||||
* @ctx_ops: Driver context operations.
|
||||
*
|
||||
* Associate a driver context and operations with a ntb device. The context is
|
||||
* provided by the client driver, and the driver may associate a different
|
||||
* context with each ntb device.
|
||||
*
|
||||
* Return: Zero if the context is associated, otherwise an error number.
|
||||
*/
|
||||
int ntb_set_ctx(struct ntb_dev *ntb, void *ctx,
|
||||
const struct ntb_ctx_ops *ctx_ops);
|
||||
|
||||
/**
|
||||
* ntb_clear_ctx() - disassociate any driver context from an ntb device
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Clear any association that may exist between a driver context and the ntb
|
||||
* device.
|
||||
*/
|
||||
void ntb_clear_ctx(struct ntb_dev *ntb);
|
||||
|
||||
/**
|
||||
* ntb_link_event() - notify driver context of a change in link status
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Notify the driver context that the link status may have changed. The driver
|
||||
* should call ntb_link_is_up() to get the current status.
|
||||
*/
|
||||
void ntb_link_event(struct ntb_dev *ntb);
|
||||
|
||||
/**
|
||||
* ntb_db_event() - notify driver context of a doorbell event
|
||||
* @ntb: NTB device context.
|
||||
* @vector: Interrupt vector number.
|
||||
*
|
||||
* Notify the driver context of a doorbell event. If hardware supports
|
||||
* multiple interrupt vectors for doorbells, the vector number indicates which
|
||||
* vector received the interrupt. The vector number is relative to the first
|
||||
* vector used for doorbells, starting at zero, and must be less than
|
||||
** ntb_db_vector_count(). The driver may call ntb_db_read() to check which
|
||||
* doorbell bits need service, and ntb_db_vector_mask() to determine which of
|
||||
* those bits are associated with the vector number.
|
||||
*/
|
||||
void ntb_db_event(struct ntb_dev *ntb, int vector);
|
||||
|
||||
/**
|
||||
* ntb_mw_count() - get the number of memory windows
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Hardware and topology may support a different number of memory windows.
|
||||
*
|
||||
* Return: the number of memory windows.
|
||||
*/
|
||||
static inline int ntb_mw_count(struct ntb_dev *ntb)
|
||||
{
|
||||
return ntb->ops->mw_count(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_mw_get_range() - get the range of a memory window
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Memory window number.
|
||||
* @base: OUT - the base address for mapping the memory window
|
||||
* @size: OUT - the size for mapping the memory window
|
||||
* @align: OUT - the base alignment for translating the memory window
|
||||
* @align_size: OUT - the size alignment for translating the memory window
|
||||
*
|
||||
* Get the range of a memory window. 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. The alignment and
|
||||
* size may be used for translating the memory window, for the peer to access
|
||||
* memory on the local system.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx,
|
||||
phys_addr_t *base, resource_size_t *size,
|
||||
resource_size_t *align, resource_size_t *align_size)
|
||||
{
|
||||
return ntb->ops->mw_get_range(ntb, idx, base, size,
|
||||
align, align_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_mw_set_trans() - set the translation of a memory window
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Memory window number.
|
||||
* @addr: The dma address 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
|
||||
* 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
|
||||
* must be aligned to the size alignment specified by ntb_mw_get_range().
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx,
|
||||
dma_addr_t addr, resource_size_t size)
|
||||
{
|
||||
return ntb->ops->mw_set_trans(ntb, idx, addr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_mw_clear_trans() - clear the translation of a memory window
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Memory window number.
|
||||
*
|
||||
* Clear the translation of a memory window. The peer may no longer access
|
||||
* local memory through the window.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx)
|
||||
{
|
||||
if (!ntb->ops->mw_clear_trans)
|
||||
return ntb->ops->mw_set_trans(ntb, idx, 0, 0);
|
||||
|
||||
return ntb->ops->mw_clear_trans(ntb, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_link_is_up() - get the current ntb link state
|
||||
* @ntb: NTB device context.
|
||||
* @speed: OUT - The link speed expressed as PCIe generation number.
|
||||
* @width: OUT - The link width expressed as the number of PCIe lanes.
|
||||
*
|
||||
* 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
|
||||
* must be aligned to the alignment specified by ntb_mw_get_range(). The size
|
||||
* must be aligned to the size alignment specified by ntb_mw_get_range().
|
||||
*
|
||||
* Return: One if the link is up, zero if the link is down, otherwise a
|
||||
* negative value indicating the error number.
|
||||
*/
|
||||
static inline int ntb_link_is_up(struct ntb_dev *ntb,
|
||||
enum ntb_speed *speed, enum ntb_width *width)
|
||||
{
|
||||
return ntb->ops->link_is_up(ntb, speed, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_link_enable() - enable the link on the secondary side of the ntb
|
||||
* @ntb: NTB device context.
|
||||
* @max_speed: The maximum link speed expressed as PCIe generation number.
|
||||
* @max_width: The maximum link width expressed as the number of PCIe lanes.
|
||||
*
|
||||
* Enable the link on the secondary side of the ntb. This can only be done
|
||||
* from the primary side of the ntb in primary or b2b topology. The ntb device
|
||||
* should train the link to its maximum speed and width, or the requested speed
|
||||
* and width, whichever is smaller, if supported.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_link_enable(struct ntb_dev *ntb,
|
||||
enum ntb_speed max_speed,
|
||||
enum ntb_width max_width)
|
||||
{
|
||||
return ntb->ops->link_enable(ntb, max_speed, max_width);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_link_disable() - disable the link on the secondary side of the ntb
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Disable the link on the secondary side of the ntb. This can only be
|
||||
* done from the primary side of the ntb in primary or b2b topology. The ntb
|
||||
* device should disable the link. Returning from this call must indicate that
|
||||
* a barrier has passed, though with no more writes may pass in either
|
||||
* direction across the link, except if this call returns an error number.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_link_disable(struct ntb_dev *ntb)
|
||||
{
|
||||
return ntb->ops->link_disable(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_is_unsafe() - check if it is safe to use hardware doorbell
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* It is possible for some ntb hardware to be affected by errata. Hardware
|
||||
* drivers can advise clients to avoid using doorbells. Clients may ignore
|
||||
* this advice, though caution is recommended.
|
||||
*
|
||||
* Return: Zero if it is safe to use doorbells, or One if it is not safe.
|
||||
*/
|
||||
static inline int ntb_db_is_unsafe(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->db_is_unsafe)
|
||||
return 0;
|
||||
|
||||
return ntb->ops->db_is_unsafe(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Hardware may support different number or arrangement of doorbell bits.
|
||||
*
|
||||
* Return: A mask of doorbell bits supported by the ntb.
|
||||
*/
|
||||
static inline u64 ntb_db_valid_mask(struct ntb_dev *ntb)
|
||||
{
|
||||
return ntb->ops->db_valid_mask(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_vector_count() - get the number of doorbell interrupt vectors
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Hardware may support different number of interrupt vectors.
|
||||
*
|
||||
* Return: The number of doorbell interrupt vectors.
|
||||
*/
|
||||
static inline int ntb_db_vector_count(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->db_vector_count)
|
||||
return 1;
|
||||
|
||||
return ntb->ops->db_vector_count(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_vector_mask() - get a mask of doorbell bits serviced by a vector
|
||||
* @ntb: NTB device context.
|
||||
* @vector: Doorbell vector number.
|
||||
*
|
||||
* Each interrupt vector may have a different number or arrangement of bits.
|
||||
*
|
||||
* Return: A mask of doorbell bits serviced by a vector.
|
||||
*/
|
||||
static inline u64 ntb_db_vector_mask(struct ntb_dev *ntb, int vector)
|
||||
{
|
||||
if (!ntb->ops->db_vector_mask)
|
||||
return ntb_db_valid_mask(ntb);
|
||||
|
||||
return ntb->ops->db_vector_mask(ntb, vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_read() - read the local doorbell register
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Read the local doorbell register, and return the bits that are set.
|
||||
*
|
||||
* Return: The bits currently set in the local doorbell register.
|
||||
*/
|
||||
static inline u64 ntb_db_read(struct ntb_dev *ntb)
|
||||
{
|
||||
return ntb->ops->db_read(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_set() - set bits in the local doorbell register
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to set.
|
||||
*
|
||||
* Set bits in the local doorbell register, which may generate a local doorbell
|
||||
* interrupt. Bits that were already set must remain set.
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_db_set(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
if (!ntb->ops->db_set)
|
||||
return -EINVAL;
|
||||
|
||||
return ntb->ops->db_set(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_clear() - clear bits in the local doorbell register
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to clear.
|
||||
*
|
||||
* Clear bits in the local doorbell register, arming the bits for the next
|
||||
* doorbell.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_db_clear(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
return ntb->ops->db_clear(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_read_mask() - read the local doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Read the local doorbell mask register, and return the bits that are set.
|
||||
*
|
||||
* This is unusual, though hardware is likely to support it.
|
||||
*
|
||||
* Return: The bits currently set in the local doorbell mask register.
|
||||
*/
|
||||
static inline u64 ntb_db_read_mask(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->db_read_mask)
|
||||
return 0;
|
||||
|
||||
return ntb->ops->db_read_mask(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_set_mask() - set bits in the local doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell mask bits to set.
|
||||
*
|
||||
* Set bits in the local doorbell mask register, preventing doorbell interrupts
|
||||
* from being generated for those doorbell bits. Bits that were already set
|
||||
* must remain set.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
return ntb->ops->db_set_mask(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_db_clear_mask() - clear bits in the local doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to clear.
|
||||
*
|
||||
* Clear bits in the local doorbell mask register, allowing doorbell interrupts
|
||||
* from being generated for those doorbell bits. If a doorbell bit is already
|
||||
* set at the time the mask is cleared, and the corresponding mask bit is
|
||||
* changed from set to clear, then the ntb driver must ensure that
|
||||
* ntb_db_event() is called. If the hardware does not generate the interrupt
|
||||
* on clearing the mask bit, then the driver must call ntb_db_event() anyway.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
return ntb->ops->db_clear_mask(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_addr() - address and size of the peer doorbell register
|
||||
* @ntb: NTB device context.
|
||||
* @db_addr: OUT - The address of the peer doorbell register.
|
||||
* @db_size: OUT - The number of bytes to write the peer doorbell register.
|
||||
*
|
||||
* Return the address of the peer doorbell register. This may be used, for
|
||||
* example, by drivers that offload memory copy operations to a dma engine.
|
||||
* The drivers may wish to ring the peer doorbell at the completion of memory
|
||||
* copy operations. For efficiency, and to simplify ordering of operations
|
||||
* between the dma memory copies and the ringing doorbell, the driver may
|
||||
* append one additional dma memory copy with the doorbell register as the
|
||||
* destination, after the memory copy operations.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_db_addr(struct ntb_dev *ntb,
|
||||
phys_addr_t *db_addr,
|
||||
resource_size_t *db_size)
|
||||
{
|
||||
return ntb->ops->peer_db_addr(ntb, db_addr, db_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_read() - read the peer doorbell register
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Read the peer doorbell register, and return the bits that are set.
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: The bits currently set in the peer doorbell register.
|
||||
*/
|
||||
static inline u64 ntb_peer_db_read(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->peer_db_read)
|
||||
return 0;
|
||||
|
||||
return ntb->ops->peer_db_read(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_set() - set bits in the peer doorbell register
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to set.
|
||||
*
|
||||
* Set bits in the peer doorbell register, which may generate a peer doorbell
|
||||
* interrupt. Bits that were already set must remain set.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
return ntb->ops->peer_db_set(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_clear() - clear bits in the local doorbell register
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to clear.
|
||||
*
|
||||
* Clear bits in the peer doorbell register, arming the bits for the next
|
||||
* doorbell.
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_db_clear(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
if (!ntb->ops->db_clear)
|
||||
return -EINVAL;
|
||||
|
||||
return ntb->ops->peer_db_clear(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_read_mask() - read the peer doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Read the peer doorbell mask register, and return the bits that are set.
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: The bits currently set in the peer doorbell mask register.
|
||||
*/
|
||||
static inline u64 ntb_peer_db_read_mask(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->db_read_mask)
|
||||
return 0;
|
||||
|
||||
return ntb->ops->peer_db_read_mask(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_set_mask() - set bits in the peer doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell mask bits to set.
|
||||
*
|
||||
* Set bits in the peer doorbell mask register, preventing doorbell interrupts
|
||||
* from being generated for those doorbell bits. Bits that were already set
|
||||
* must remain set.
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_db_set_mask(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
if (!ntb->ops->db_set_mask)
|
||||
return -EINVAL;
|
||||
|
||||
return ntb->ops->peer_db_set_mask(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_db_clear_mask() - clear bits in the peer doorbell mask
|
||||
* @ntb: NTB device context.
|
||||
* @db_bits: Doorbell bits to clear.
|
||||
*
|
||||
* Clear bits in the peer doorbell mask register, allowing doorbell interrupts
|
||||
* from being generated for those doorbell bits. If the hardware does not
|
||||
* generate the interrupt on clearing the mask bit, then the driver should not
|
||||
* implement this function!
|
||||
*
|
||||
* This is unusual, and hardware may not support it.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_db_clear_mask(struct ntb_dev *ntb, u64 db_bits)
|
||||
{
|
||||
if (!ntb->ops->db_clear_mask)
|
||||
return -EINVAL;
|
||||
|
||||
return ntb->ops->peer_db_clear_mask(ntb, db_bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_spad_is_unsafe() - check if it is safe to use the hardware scratchpads
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* It is possible for some ntb hardware to be affected by errata. Hardware
|
||||
* drivers can advise clients to avoid using scratchpads. Clients may ignore
|
||||
* this advice, though caution is recommended.
|
||||
*
|
||||
* Return: Zero if it is safe to use scratchpads, or One if it is not safe.
|
||||
*/
|
||||
static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb)
|
||||
{
|
||||
if (!ntb->ops->spad_is_unsafe)
|
||||
return 0;
|
||||
|
||||
return ntb->ops->spad_is_unsafe(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_mw_count() - get the number of scratchpads
|
||||
* @ntb: NTB device context.
|
||||
*
|
||||
* Hardware and topology may support a different number of scratchpads.
|
||||
*
|
||||
* Return: the number of scratchpads.
|
||||
*/
|
||||
static inline int ntb_spad_count(struct ntb_dev *ntb)
|
||||
{
|
||||
return ntb->ops->spad_count(ntb);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_spad_read() - read the local scratchpad register
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Scratchpad index.
|
||||
*
|
||||
* Read the local scratchpad register, and return the value.
|
||||
*
|
||||
* Return: The value of the local scratchpad register.
|
||||
*/
|
||||
static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx)
|
||||
{
|
||||
return ntb->ops->spad_read(ntb, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_spad_write() - write the local scratchpad register
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Scratchpad index.
|
||||
* @val: Scratchpad value.
|
||||
*
|
||||
* Write the value to the local scratchpad register.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val)
|
||||
{
|
||||
return ntb->ops->spad_write(ntb, idx, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_spad_addr() - address of the peer scratchpad register
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Scratchpad index.
|
||||
* @spad_addr: OUT - The address of the peer scratchpad register.
|
||||
*
|
||||
* Return the address of the peer doorbell register. This may be used, for
|
||||
* example, by drivers that offload memory copy operations to a dma engine.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx,
|
||||
phys_addr_t *spad_addr)
|
||||
{
|
||||
return ntb->ops->peer_spad_addr(ntb, idx, spad_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_spad_read() - read the peer scratchpad register
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Scratchpad index.
|
||||
*
|
||||
* Read the peer scratchpad register, and return the value.
|
||||
*
|
||||
* Return: The value of the local scratchpad register.
|
||||
*/
|
||||
static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx)
|
||||
{
|
||||
return ntb->ops->peer_spad_read(ntb, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntb_peer_spad_write() - write the peer scratchpad register
|
||||
* @ntb: NTB device context.
|
||||
* @idx: Scratchpad index.
|
||||
* @val: Scratchpad value.
|
||||
*
|
||||
* Write the value to the peer scratchpad register.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error number.
|
||||
*/
|
||||
static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val)
|
||||
{
|
||||
return ntb->ops->peer_spad_write(ntb, idx, val);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (C) 2015 EMC Corporation. All Rights Reserved.
|
||||
*
|
||||
* 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 copy
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* PCIe NTB Transport Linux driver
|
||||
*
|
||||
* Contact Information:
|
||||
* Jon Mason <jon.mason@intel.com>
|
||||
*/
|
||||
|
||||
struct ntb_transport_qp;
|
||||
|
||||
struct ntb_transport_client {
|
||||
struct device_driver driver;
|
||||
int (*probe)(struct device *client_dev);
|
||||
void (*remove)(struct device *client_dev);
|
||||
};
|
||||
|
||||
int ntb_transport_register_client(struct ntb_transport_client *drvr);
|
||||
void ntb_transport_unregister_client(struct ntb_transport_client *drvr);
|
||||
int ntb_transport_register_client_dev(char *device_name);
|
||||
void ntb_transport_unregister_client_dev(char *device_name);
|
||||
|
||||
struct ntb_queue_handlers {
|
||||
void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data,
|
||||
void *data, int len);
|
||||
void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data,
|
||||
void *data, int len);
|
||||
void (*event_handler)(void *data, int status);
|
||||
};
|
||||
|
||||
unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp);
|
||||
unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp);
|
||||
struct ntb_transport_qp *
|
||||
ntb_transport_create_queue(void *data, struct device *client_dev,
|
||||
const struct ntb_queue_handlers *handlers);
|
||||
void ntb_transport_free_queue(struct ntb_transport_qp *qp);
|
||||
int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
|
||||
unsigned int len);
|
||||
int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
|
||||
unsigned int len);
|
||||
void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len);
|
||||
void ntb_transport_link_up(struct ntb_transport_qp *qp);
|
||||
void ntb_transport_link_down(struct ntb_transport_qp *qp);
|
||||
bool ntb_transport_link_query(struct ntb_transport_qp *qp);
|
Loading…
Reference in New Issue