Once more refactor KPI between NTB hardware and consumers.

New design allows hardware resources to be split between several consumers.
For example, one BAR can be dedicated for remote memory access, while other
resources can be used for packet transport for virtual Ethernet interface.
And even without resource split, this code allows to specify which consumer
driver should attach the hardware.

From some points this makes the code even closer to Linux one, even though
Linux does not provide the described flexibility.
This commit is contained in:
Alexander Motin 2016-07-28 10:48:20 +00:00
parent b4a395a41b
commit 4490696b3e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=303429
6 changed files with 1168 additions and 751 deletions

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 10, 2016
.Dd July 28, 2016
.Dt NTB_HW 4
.Os
.Sh NAME
@ -51,6 +51,20 @@ The following tunables are settable from the
.It Va hw.ntb.debug_level
Driver debug level.
The default value is 0, higher means more verbose.
.It Va hint.ntb_hw. Ns Ar X Ns Va .config
Configures NTB resources split between several consumer devices.
Configuration of multiple consumer devices separated by commas.
Each device can be configured as: "<name>[:<mw>[:<spad>[:<db>]]]", where:
.Va name
is a name of the driver which should attach the device (empty means any),
.Va mw
is a number of memory windows to allocate (empty means all available),
.Va spad
is a number of scratchpad registers to allocate (empty means all available),
.Va db
is a number of doorbells to allocate (empty means all available).
The default configuration is empty string, which means single device
with all available resources allowing any driver attachment.
.El
.Sh DESCRIPTION
The NTB allows you to connect two computer systems using a PCIe link if they
@ -69,7 +83,7 @@ The hardware provides 2-3 memory windows to the other system's memory,
On Xeon processors one of memory windows is typically consumed by the driver
to workaround multiple hardware erratas.
.Sh CONFIGURATION
Tne NTB configuration should be set by BIOS.
The NTB configuration should be set by BIOS.
It includes enabling NTB, choosing between NTB-to-NTB or NTB-to-Root Port mode,
enabling split BAR mode (one of two 64-bit BARs can be split into two 32-bit
ones) and configuring BAR sizes in bits (from 12 to 29/39) for both NTB sides.

View File

@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/rmlock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/sysctl.h>
@ -39,4 +41,422 @@ __FBSDID("$FreeBSD$");
devclass_t ntb_hw_devclass;
SYSCTL_NODE(_hw, OID_AUTO, ntb, CTLFLAG_RW, 0, "NTB sysctls");
struct ntb_child {
device_t dev;
int enabled;
int mwoff;
int mwcnt;
int spadoff;
int spadcnt;
int dboff;
int dbmask;
void *ctx;
const struct ntb_ctx_ops *ctx_ops;
struct rmlock ctx_lock;
struct ntb_child *next;
};
int
ntb_register_device(device_t dev)
{
struct ntb_child **cpp = device_get_softc(dev);
struct ntb_child *nc;
int i, mw, mwu, mwt, spad, spadu, spadt, db, dbu, dbt;
char cfg[128] = "";
char buf[32];
char *n, *np, *c, *p, *name;
mwu = 0;
mwt = NTB_MW_COUNT(dev);
spadu = 0;
spadt = NTB_SPAD_COUNT(dev);
dbu = 0;
dbt = flsll(NTB_DB_VALID_MASK(dev));
device_printf(dev, "%d memory windows, %d scratchpads, "
"%d doorbells\n", mwt, spadt, dbt);
snprintf(buf, sizeof(buf), "hint.%s.%d.config", device_get_name(dev),
device_get_unit(dev));
TUNABLE_STR_FETCH(buf, cfg, sizeof(cfg));
n = cfg;
i = 0;
while ((c = strsep(&n, ",")) != NULL) {
np = c;
name = strsep(&np, ":");
if (name != NULL && name[0] == 0)
name = NULL;
p = strsep(&np, ":");
mw = (p && p[0] != 0) ? strtol(p, NULL, 10) : mwt - mwu;
p = strsep(&np, ":");
spad = (p && p[0] != 0) ? strtol(p, NULL, 10) : spadt - spadu;
db = (np && np[0] != 0) ? strtol(np, NULL, 10) : dbt - dbu;
if (mw > mwt - mwu || spad > spadt - spadu || db > dbt - dbu) {
device_printf(dev, "Not enough resources for config\n");
break;
}
nc = malloc(sizeof(*nc), M_DEVBUF, M_WAITOK | M_ZERO);
nc->mwoff = mwu;
nc->mwcnt = mw;
nc->spadoff = spadu;
nc->spadcnt = spad;
nc->dboff = dbu;
nc->dbmask = (db == 0) ? 0 : (0xffffffffffffffff >> (64 - db));
rm_init(&nc->ctx_lock, "ntb ctx");
nc->dev = device_add_child(dev, name, -1);
if (nc->dev == NULL) {
ntb_unregister_device(dev);
return (ENOMEM);
}
device_set_ivars(nc->dev, nc);
*cpp = nc;
cpp = &nc->next;
if (bootverbose) {
device_printf(dev, "%d \"%s\":", i, name);
if (mw > 0) {
printf(" memory windows %d", mwu);
if (mw > 1)
printf("-%d", mwu + mw - 1);
}
if (spad > 0) {
printf(" scratchpads %d", spadu);
if (spad > 1)
printf("-%d", spadu + spad - 1);
}
if (db > 0) {
printf(" doorbells %d", dbu);
if (db > 1)
printf("-%d", dbu + db - 1);
}
printf("\n");
}
mwu += mw;
spadu += spad;
dbu += db;
i++;
}
bus_generic_attach(dev);
return (0);
}
int
ntb_unregister_device(device_t dev)
{
struct ntb_child **cpp = device_get_softc(dev);
struct ntb_child *nc;
int error = 0;
while ((nc = *cpp) != NULL) {
*cpp = (*cpp)->next;
error = device_delete_child(dev, nc->dev);
if (error)
break;
rm_destroy(&nc->ctx_lock);
free(nc, M_DEVBUF);
}
return (error);
}
void
ntb_link_event(device_t dev)
{
struct ntb_child **cpp = device_get_softc(dev);
struct ntb_child *nc;
struct rm_priotracker ctx_tracker;
for (nc = *cpp; nc != NULL; nc = nc->next) {
rm_rlock(&nc->ctx_lock, &ctx_tracker);
if (nc->ctx_ops != NULL && nc->ctx_ops->link_event != NULL)
nc->ctx_ops->link_event(nc->ctx);
rm_runlock(&nc->ctx_lock, &ctx_tracker);
}
}
void
ntb_db_event(device_t dev, uint32_t vec)
{
struct ntb_child **cpp = device_get_softc(dev);
struct ntb_child *nc;
struct rm_priotracker ctx_tracker;
for (nc = *cpp; nc != NULL; nc = nc->next) {
rm_rlock(&nc->ctx_lock, &ctx_tracker);
if (nc->ctx_ops != NULL && nc->ctx_ops->db_event != NULL)
nc->ctx_ops->db_event(nc->ctx, vec);
rm_runlock(&nc->ctx_lock, &ctx_tracker);
}
}
bool
ntb_link_is_up(device_t ntb, enum ntb_speed *speed, enum ntb_width *width)
{
return (NTB_LINK_IS_UP(device_get_parent(ntb), speed, width));
}
int
ntb_link_enable(device_t ntb, enum ntb_speed speed, enum ntb_width width)
{
struct ntb_child *nc = device_get_ivars(ntb);
struct ntb_child **cpp = device_get_softc(device_get_parent(nc->dev));
struct ntb_child *nc1;
for (nc1 = *cpp; nc1 != NULL; nc1 = nc->next) {
if (nc1->enabled) {
nc->enabled = 1;
return (0);
}
}
nc->enabled = 1;
return (NTB_LINK_ENABLE(device_get_parent(ntb), speed, width));
}
int
ntb_link_disable(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
struct ntb_child **cpp = device_get_softc(device_get_parent(nc->dev));
struct ntb_child *nc1;
if (!nc->enabled)
return (0);
nc->enabled = 0;
for (nc1 = *cpp; nc1 != NULL; nc1 = nc->next) {
if (nc1->enabled)
return (0);
}
return (NTB_LINK_DISABLE(device_get_parent(ntb)));
}
bool
ntb_link_enabled(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (nc->enabled && NTB_LINK_ENABLED(device_get_parent(ntb)));
}
int
ntb_set_ctx(device_t ntb, void *ctx, const struct ntb_ctx_ops *ctx_ops)
{
struct ntb_child *nc = device_get_ivars(ntb);
if (ctx == NULL || ctx_ops == NULL)
return (EINVAL);
rm_wlock(&nc->ctx_lock);
if (nc->ctx_ops != NULL) {
rm_wunlock(&nc->ctx_lock);
return (EINVAL);
}
nc->ctx = ctx;
nc->ctx_ops = ctx_ops;
rm_wunlock(&nc->ctx_lock);
return (0);
}
void *
ntb_get_ctx(device_t ntb, const struct ntb_ctx_ops **ctx_ops)
{
struct ntb_child *nc = device_get_ivars(ntb);
KASSERT(nc->ntb_ctx != NULL && nc->ctx_ops != NULL, ("bogus"));
if (ctx_ops != NULL)
*ctx_ops = nc->ctx_ops;
return (nc->ctx);
}
void
ntb_clear_ctx(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
rm_wlock(&nc->ctx_lock);
nc->ctx = NULL;
nc->ctx_ops = NULL;
rm_wunlock(&nc->ctx_lock);
}
uint8_t
ntb_mw_count(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (nc->mwcnt);
}
int
ntb_mw_get_range(device_t ntb, unsigned mw_idx, vm_paddr_t *base,
caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
bus_addr_t *plimit)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_MW_GET_RANGE(device_get_parent(ntb), mw_idx + nc->mwoff,
base, vbase, size, align, align_size, plimit));
}
int
ntb_mw_set_trans(device_t ntb, unsigned mw_idx, bus_addr_t addr, size_t size)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_MW_SET_TRANS(device_get_parent(ntb), mw_idx + nc->mwoff,
addr, size));
}
int
ntb_mw_clear_trans(device_t ntb, unsigned mw_idx)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_MW_CLEAR_TRANS(device_get_parent(ntb), mw_idx + nc->mwoff));
}
int
ntb_mw_get_wc(device_t ntb, unsigned mw_idx, vm_memattr_t *mode)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_MW_GET_WC(device_get_parent(ntb), mw_idx + nc->mwoff, mode));
}
int
ntb_mw_set_wc(device_t ntb, unsigned mw_idx, vm_memattr_t mode)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_MW_SET_WC(device_get_parent(ntb), mw_idx + nc->mwoff, mode));
}
uint8_t
ntb_spad_count(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (nc->spadcnt);
}
void
ntb_spad_clear(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
unsigned i;
for (i = 0; i < nc->spadcnt; i++)
NTB_SPAD_WRITE(device_get_parent(ntb), i + nc->spadoff, 0);
}
int
ntb_spad_write(device_t ntb, unsigned int idx, uint32_t val)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_SPAD_WRITE(device_get_parent(ntb), idx + nc->spadoff, val));
}
int
ntb_spad_read(device_t ntb, unsigned int idx, uint32_t *val)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_SPAD_READ(device_get_parent(ntb), idx + nc->spadoff, val));
}
int
ntb_peer_spad_write(device_t ntb, unsigned int idx, uint32_t val)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_PEER_SPAD_WRITE(device_get_parent(ntb), idx + nc->spadoff,
val));
}
int
ntb_peer_spad_read(device_t ntb, unsigned int idx, uint32_t *val)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_PEER_SPAD_READ(device_get_parent(ntb), idx + nc->spadoff,
val));
}
uint64_t
ntb_db_valid_mask(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (nc->dbmask);
}
int
ntb_db_vector_count(device_t ntb)
{
return (NTB_DB_VECTOR_COUNT(device_get_parent(ntb)));
}
uint64_t
ntb_db_vector_mask(device_t ntb, uint32_t vector)
{
struct ntb_child *nc = device_get_ivars(ntb);
return ((NTB_DB_VECTOR_MASK(device_get_parent(ntb), vector)
>> nc->dboff) & nc->dbmask);
}
int
ntb_peer_db_addr(device_t ntb, bus_addr_t *db_addr, vm_size_t *db_size)
{
return (NTB_PEER_DB_ADDR(device_get_parent(ntb), db_addr, db_size));
}
void
ntb_db_clear(device_t ntb, uint64_t bits)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_DB_CLEAR(device_get_parent(ntb), bits << nc->dboff));
}
void
ntb_db_clear_mask(device_t ntb, uint64_t bits)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_DB_CLEAR_MASK(device_get_parent(ntb), bits << nc->dboff));
}
uint64_t
ntb_db_read(device_t ntb)
{
struct ntb_child *nc = device_get_ivars(ntb);
return ((NTB_DB_READ(device_get_parent(ntb)) >> nc->dboff)
& nc->dbmask);
}
void
ntb_db_set_mask(device_t ntb, uint64_t bits)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_DB_SET_MASK(device_get_parent(ntb), bits << nc->dboff));
}
void
ntb_peer_db_set(device_t ntb, uint64_t bits)
{
struct ntb_child *nc = device_get_ivars(ntb);
return (NTB_PEER_DB_SET(device_get_parent(ntb), bits << nc->dboff));
}
MODULE_VERSION(ntb, 1);

View File

@ -34,4 +34,376 @@
extern devclass_t ntb_hw_devclass;
SYSCTL_DECL(_hw_ntb);
int ntb_register_device(device_t ntb);
int ntb_unregister_device(device_t 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 intb_link_is_up() to get the current status.
*/
void ntb_link_event(device_t 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(device_t ntb, uint32_t vec);
/*
* 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
*
* RETURNS: true or false based on the hardware link state
*/
bool ntb_link_is_up(device_t ntb, enum ntb_speed *speed, enum ntb_width *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[0]
* @max_width: The maximum link width expressed as the number of PCIe lanes[0]
*
* 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.
*
* [0]: Only NTB_SPEED_AUTO and NTB_WIDTH_AUTO are valid inputs; other speed
* and width input will be ignored.
*/
int ntb_link_enable(device_t ntb, enum ntb_speed speed, enum ntb_width 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.
*/
int ntb_link_disable(device_t ntb);
/*
* get enable status of the link on the secondary side of the ntb
*/
bool ntb_link_enabled(device_t 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(device_t ntb, void *ctx, const struct ntb_ctx_ops *ctx_ops);
/*
* ntb_set_ctx() - get a driver context associated with an ntb device
* @ntb: NTB device context
* @ctx_ops: Driver context operations
*
* Get a driver context and operations associated with a ntb device.
*/
void * ntb_get_ctx(device_t ntb, 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(device_t ntb);
/*
* ntb_mw_count() - Get the number of memory windows available for KPI
* consumers.
*
* (Excludes any MW wholly reserved for register access.)
*/
uint8_t ntb_mw_count(device_t 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.
*/
int ntb_mw_get_range(device_t ntb, unsigned mw_idx, vm_paddr_t *base,
caddr_t *vbase, size_t *size, size_t *align, size_t *align_size,
bus_addr_t *plimit);
/*
* 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(). The
* address must be below the plimit specified by ntb_mw_get_range() (i.e. for
* 32-bit BARs).
*
* Return: Zero on success, otherwise an error number.
*/
int ntb_mw_set_trans(device_t ntb, unsigned mw_idx, bus_addr_t addr,
size_t 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.
*/
int ntb_mw_clear_trans(device_t ntb, unsigned mw_idx);
/*
* ntb_mw_get_wc - Get the write-combine status of a memory window
*
* Returns: Zero on success, setting *wc; otherwise an error number (e.g. if
* idx is an invalid memory window).
*
* Mode is a VM_MEMATTR_* type.
*/
int ntb_mw_get_wc(device_t ntb, unsigned mw_idx, vm_memattr_t *mode);
/*
* ntb_mw_set_wc - Set the write-combine status of a memory window
*
* If 'mode' matches the current status, this does nothing and succeeds. Mode
* is a VM_MEMATTR_* type.
*
* Returns: Zero on success, setting the caching attribute on the virtual
* mapping of the BAR; otherwise an error number (e.g. if idx is an invalid
* memory window, or if changing the caching attribute fails).
*/
int ntb_mw_set_wc(device_t ntb, unsigned mw_idx, vm_memattr_t mode);
/*
* ntb_spad_count() - get the total scratch regs usable
* @ntb: pointer to ntb_softc instance
*
* This function returns the max 32bit scratchpad registers usable by the
* upper layer.
*
* RETURNS: total number of scratch pad registers available
*/
uint8_t ntb_spad_count(device_t ntb);
/*
* ntb_get_max_spads() - zero local scratch registers
* @ntb: pointer to ntb_softc instance
*
* This functions overwrites all local scratchpad registers with zeroes.
*/
void ntb_spad_clear(device_t ntb);
/*
* ntb_spad_write() - write to the secondary scratchpad register
* @ntb: pointer to ntb_softc instance
* @idx: index to the scratchpad register, 0 based
* @val: the data value to put into the register
*
* This function allows writing of a 32bit value to the indexed scratchpad
* register. The register resides on the secondary (external) side.
*
* RETURNS: An appropriate ERRNO error value on error, or zero for success.
*/
int ntb_spad_write(device_t ntb, unsigned int idx, uint32_t val);
/*
* ntb_spad_read() - read from the primary scratchpad register
* @ntb: pointer to ntb_softc instance
* @idx: index to scratchpad register, 0 based
* @val: pointer to 32bit integer for storing the register value
*
* This function allows reading of the 32bit scratchpad register on
* the primary (internal) side.
*
* RETURNS: An appropriate ERRNO error value on error, or zero for success.
*/
int ntb_spad_read(device_t ntb, unsigned int idx, uint32_t *val);
/*
* ntb_peer_spad_write() - write to the secondary scratchpad register
* @ntb: pointer to ntb_softc instance
* @idx: index to the scratchpad register, 0 based
* @val: the data value to put into the register
*
* This function allows writing of a 32bit value to the indexed scratchpad
* register. The register resides on the secondary (external) side.
*
* RETURNS: An appropriate ERRNO error value on error, or zero for success.
*/
int ntb_peer_spad_write(device_t ntb, unsigned int idx, uint32_t val);
/*
* ntb_peer_spad_read() - read from the primary scratchpad register
* @ntb: pointer to ntb_softc instance
* @idx: index to scratchpad register, 0 based
* @val: pointer to 32bit integer for storing the register value
*
* This function allows reading of the 32bit scratchpad register on
* the primary (internal) side.
*
* RETURNS: An appropriate ERRNO error value on error, or zero for success.
*/
int ntb_peer_spad_read(device_t ntb, unsigned int idx, uint32_t *val);
/*
* 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.
*/
uint64_t ntb_db_valid_mask(device_t 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.
*/
int ntb_db_vector_count(device_t 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.
*/
uint64_t ntb_db_vector_mask(device_t ntb, uint32_t vector);
/*
* 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.
*
* Note that writing the peer doorbell via a memory window will *not* generate
* an interrupt on the remote host; that must be done separately.
*/
int ntb_peer_db_addr(device_t ntb, bus_addr_t *db_addr, vm_size_t *db_size);
/*
* 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.
*/
void ntb_db_clear(device_t ntb, uint64_t 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.
*/
void ntb_db_clear_mask(device_t ntb, uint64_t bits);
/*
* 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.
*/
uint64_t ntb_db_read(device_t 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.
*/
void ntb_db_set_mask(device_t ntb, uint64_t bits);
/*
* ntb_peer_db_set() - Set the doorbell on the secondary/external side
* @ntb: pointer to ntb_softc instance
* @bit: doorbell bits to ring
*
* This function allows triggering of a doorbell on the secondary/external
* side that will initiate an interrupt on the remote host
*/
void ntb_peer_db_set(device_t ntb, uint64_t bits);
#endif /* _NTB_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -60,133 +60,45 @@ HEADER {
};
};
#
# 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
#
# RETURNS: true or false based on the hardware link state
#
METHOD bool link_is_up {
device_t ntb;
enum ntb_speed *speed;
enum ntb_width *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[0]
# @max_width: The maximum link width expressed as the number of PCIe lanes[0]
#
# 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.
#
# [0]: Only NTB_SPEED_AUTO and NTB_WIDTH_AUTO are valid inputs; other speed
# and width input will be ignored.
#/
METHOD int link_enable {
device_t ntb;
enum ntb_speed speed;
enum ntb_width 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.
#
METHOD int link_disable {
device_t ntb;
};
#
# get enable status of the link on the secondary side of the ntb
#
METHOD bool link_enabled {
device_t 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.
#
METHOD int set_ctx {
device_t ntb;
void *ctx;
const struct ntb_ctx_ops *ctx_ops;
};
#
# ntb_set_ctx() - get a driver context associated with an ntb device
# @ntb: NTB device context
# @ctx_ops: Driver context operations
#
# Get a driver context and operations associated with a ntb device.
#
METHOD void * get_ctx {
device_t ntb;
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.
#
METHOD void clear_ctx {
device_t ntb;
};
#
# ntb_mw_count() - Get the number of memory windows available for KPI
# consumers.
#
# (Excludes any MW wholly reserved for register access.)
#
METHOD uint8_t mw_count {
device_t 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.
#
METHOD int mw_get_range {
device_t ntb;
unsigned mw_idx;
@ -198,22 +110,6 @@ METHOD int mw_get_range {
bus_addr_t *plimit;
};
#
# 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(). The
# address must be below the plimit specified by ntb_mw_get_range() (i.e. for
# 32-bit BARs).
#
# Return: Zero on success, otherwise an error number.
#
METHOD int mw_set_trans {
device_t ntb;
unsigned mw_idx;
@ -221,277 +117,94 @@ METHOD int mw_set_trans {
size_t 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.
#
METHOD int mw_clear_trans {
device_t ntb;
unsigned mw_idx;
};
#
# ntb_mw_get_wc - Get the write-combine status of a memory window
#
# Returns: Zero on success, setting *wc; otherwise an error number (e.g. if
# idx is an invalid memory window).
#
# Mode is a VM_MEMATTR_* type.
#
METHOD int mw_get_wc {
device_t ntb;
unsigned mw_idx;
vm_memattr_t *mode;
};
#
# ntb_mw_set_wc - Set the write-combine status of a memory window
#
# If 'mode' matches the current status, this does nothing and succeeds. Mode
# is a VM_MEMATTR_* type.
#
# Returns: Zero on success, setting the caching attribute on the virtual
# mapping of the BAR; otherwise an error number (e.g. if idx is an invalid
# memory window, or if changing the caching attribute fails).
#
METHOD int mw_set_wc {
device_t ntb;
unsigned mw_idx;
vm_memattr_t mode;
};
#
# ntb_spad_count() - get the total scratch regs usable
# @ntb: pointer to ntb_softc instance
#
# This function returns the max 32bit scratchpad registers usable by the
# upper layer.
#
# RETURNS: total number of scratch pad registers available
#
METHOD uint8_t spad_count {
device_t ntb;
};
#
# ntb_get_max_spads() - zero local scratch registers
# @ntb: pointer to ntb_softc instance
#
# This functions overwrites all local scratchpad registers with zeroes.
#
METHOD void spad_clear {
device_t ntb;
};
#
# ntb_spad_write() - write to the secondary scratchpad register
# @ntb: pointer to ntb_softc instance
# @idx: index to the scratchpad register, 0 based
# @val: the data value to put into the register
#
# This function allows writing of a 32bit value to the indexed scratchpad
# register. The register resides on the secondary (external) side.
#
# RETURNS: An appropriate ERRNO error value on error, or zero for success.
#
METHOD int spad_write {
device_t ntb;
unsigned int idx;
uint32_t val;
};
#
# ntb_spad_read() - read from the primary scratchpad register
# @ntb: pointer to ntb_softc instance
# @idx: index to scratchpad register, 0 based
# @val: pointer to 32bit integer for storing the register value
#
# This function allows reading of the 32bit scratchpad register on
# the primary (internal) side.
#
# RETURNS: An appropriate ERRNO error value on error, or zero for success.
#
METHOD int spad_read {
device_t ntb;
unsigned int idx;
uint32_t *val;
};
#
# ntb_peer_spad_write() - write to the secondary scratchpad register
# @ntb: pointer to ntb_softc instance
# @idx: index to the scratchpad register, 0 based
# @val: the data value to put into the register
#
# This function allows writing of a 32bit value to the indexed scratchpad
# register. The register resides on the secondary (external) side.
#
# RETURNS: An appropriate ERRNO error value on error, or zero for success.
#
METHOD int peer_spad_write {
device_t ntb;
unsigned int idx;
uint32_t val;
};
#
# ntb_peer_spad_read() - read from the primary scratchpad register
# @ntb: pointer to ntb_softc instance
# @idx: index to scratchpad register, 0 based
# @val: pointer to 32bit integer for storing the register value
#
# This function allows reading of the 32bit scratchpad register on
# the primary (internal) side.
#
# RETURNS: An appropriate ERRNO error value on error, or zero for success.
#
METHOD int peer_spad_read {
device_t ntb;
unsigned int idx;
uint32_t *val;
};
#
# 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.
#
METHOD uint64_t db_valid_mask {
device_t 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.
#
METHOD int db_vector_count {
device_t 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.
#
METHOD uint64_t db_vector_mask {
device_t ntb;
uint32_t vector;
};
#
# 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.
#
# Note that writing the peer doorbell via a memory window will *not* generate
# an interrupt on the remote host; that must be done separately.
#
METHOD int peer_db_addr {
device_t ntb;
bus_addr_t *db_addr;
vm_size_t *db_size;
};
#
# 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.
#
METHOD void db_clear {
device_t ntb;
uint64_t 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.
#
METHOD void db_clear_mask {
device_t ntb;
uint64_t bits;
};
#
# 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.
#
METHOD uint64_t db_read {
device_t 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.
#
METHOD void db_set_mask {
device_t ntb;
uint64_t bits;
};
#
# ntb_peer_db_set() - Set the doorbell on the secondary/external side
# @ntb: pointer to ntb_softc instance
# @bit: doorbell bits to ring
#
# This function allows triggering of a doorbell on the secondary/external
# side that will initiate an interrupt on the remote host
#
METHOD void peer_db_set {
device_t ntb;
uint64_t bits;
};

View File

@ -130,7 +130,7 @@ struct ntb_rx_info {
struct ntb_transport_qp {
struct ntb_transport_ctx *transport;
device_t ntb;
device_t dev;
void *cb_data;
@ -202,7 +202,6 @@ struct ntb_transport_mw {
struct ntb_transport_ctx {
device_t dev;
device_t ntb;
struct ntb_transport_mw *mw_vec;
struct ntb_transport_qp *qp_vec;
struct _qpset qp_bitmap;
@ -317,7 +316,7 @@ xeon_link_watchdog_hb(void *arg)
struct ntb_transport_ctx *nt;
nt = arg;
NTB_SPAD_WRITE(nt->ntb, NTBT_WATCHDOG_SPAD, 0);
ntb_spad_write(nt->dev, NTBT_WATCHDOG_SPAD, 0);
callout_reset(&nt->link_watchdog, 1 * hz, xeon_link_watchdog_hb, nt);
}
@ -333,21 +332,19 @@ static int
ntb_transport_attach(device_t dev)
{
struct ntb_transport_ctx *nt = device_get_softc(dev);
device_t ntb = device_get_parent(dev);
struct ntb_transport_mw *mw;
uint64_t qp_bitmap;
int rc;
unsigned i;
nt->dev = dev;
nt->ntb = ntb;
nt->mw_count = NTB_MW_COUNT(ntb);
nt->mw_count = ntb_mw_count(dev);
nt->mw_vec = malloc(nt->mw_count * sizeof(*nt->mw_vec), M_NTB_T,
M_WAITOK | M_ZERO);
for (i = 0; i < nt->mw_count; i++) {
mw = &nt->mw_vec[i];
rc = NTB_MW_GET_RANGE(ntb, i, &mw->phys_addr, &mw->vbase,
rc = ntb_mw_get_range(dev, i, &mw->phys_addr, &mw->vbase,
&mw->phys_size, &mw->xlat_align, &mw->xlat_align_size,
&mw->addr_limit);
if (rc != 0)
@ -358,12 +355,12 @@ ntb_transport_attach(device_t dev)
mw->virt_addr = NULL;
mw->dma_addr = 0;
rc = NTB_MW_SET_WC(nt->ntb, i, VM_MEMATTR_WRITE_COMBINING);
rc = ntb_mw_set_wc(dev, i, VM_MEMATTR_WRITE_COMBINING);
if (rc)
ntb_printf(0, "Unable to set mw%d caching\n", i);
}
qp_bitmap = NTB_DB_VALID_MASK(ntb);
qp_bitmap = ntb_db_valid_mask(dev);
nt->qp_count = flsll(qp_bitmap);
KASSERT(nt->qp_count != 0, ("bogus db bitmap"));
nt->qp_count -= 1;
@ -387,12 +384,12 @@ ntb_transport_attach(device_t dev)
callout_init(&nt->link_watchdog, 0);
TASK_INIT(&nt->link_cleanup, 0, ntb_transport_link_cleanup_work, nt);
rc = NTB_SET_CTX(ntb, nt, &ntb_transport_ops);
rc = ntb_set_ctx(dev, nt, &ntb_transport_ops);
if (rc != 0)
goto err;
nt->link_is_up = false;
NTB_LINK_ENABLE(ntb, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
ntb_link_enable(dev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO);
if (enable_xeon_watchdog != 0)
callout_reset(&nt->link_watchdog, 0, xeon_link_watchdog_hb, nt);
@ -413,7 +410,6 @@ static int
ntb_transport_detach(device_t dev)
{
struct ntb_transport_ctx *nt = device_get_softc(dev);
device_t ntb = nt->ntb;
struct _qpset qp_bitmap_alloc;
uint8_t i;
@ -433,8 +429,8 @@ ntb_transport_detach(device_t dev)
if (test_bit(i, &qp_bitmap_alloc))
ntb_transport_free_queue(&nt->qp_vec[i]);
NTB_LINK_DISABLE(ntb);
NTB_CLEAR_CTX(ntb);
ntb_link_disable(dev);
ntb_clear_ctx(dev);
for (i = 0; i < nt->mw_count; i++)
ntb_free_mw(nt, i);
@ -461,7 +457,7 @@ ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num)
qp = &nt->qp_vec[qp_num];
qp->qp_num = qp_num;
qp->transport = nt;
qp->ntb = nt->ntb;
qp->dev = nt->dev;
qp->client_ready = false;
qp->event_handler = NULL;
ntb_qp_link_down_reset(qp);
@ -518,7 +514,7 @@ ntb_transport_free_queue(struct ntb_transport_qp *qp)
callout_drain(&qp->link_work);
NTB_DB_SET_MASK(qp->ntb, 1ull << qp->qp_num);
ntb_db_set_mask(qp->dev, 1ull << qp->qp_num);
taskqueue_drain_all(qp->rxc_tq);
taskqueue_free(qp->rxc_tq);
@ -558,7 +554,6 @@ ntb_transport_create_queue(void *data, device_t dev,
const struct ntb_queue_handlers *handlers)
{
struct ntb_transport_ctx *nt = device_get_softc(dev);
device_t ntb = device_get_parent(dev);
struct ntb_queue_entry *entry;
struct ntb_transport_qp *qp;
unsigned int free_queue;
@ -593,7 +588,7 @@ ntb_transport_create_queue(void *data, device_t dev,
ntb_list_add(&qp->ntb_tx_free_q_lock, entry, &qp->tx_free_q);
}
NTB_DB_CLEAR(ntb, 1ull << qp->qp_num);
ntb_db_clear(dev, 1ull << qp->qp_num);
return (qp);
}
@ -680,7 +675,7 @@ ntb_tx_copy_callback(void *data)
iowrite32(entry->flags | NTBT_DESC_DONE_FLAG, &hdr->flags);
CTR1(KTR_NTB, "TX: hdr %p set DESC_DONE", hdr);
NTB_PEER_DB_SET(qp->ntb, 1ull << qp->qp_num);
ntb_peer_db_set(qp->dev, 1ull << qp->qp_num);
/*
* The entry length can only be zero if the packet is intended to be a
@ -790,9 +785,9 @@ ntb_transport_rxc_db(void *arg, int pending __unused)
;
CTR1(KTR_NTB, "RX: process_rxc returned %d", rc);
if ((NTB_DB_READ(qp->ntb) & (1ull << qp->qp_num)) != 0) {
if ((ntb_db_read(qp->dev) & (1ull << qp->qp_num)) != 0) {
/* If db is set, clear it and check queue once more. */
NTB_DB_CLEAR(qp->ntb, 1ull << qp->qp_num);
ntb_db_clear(qp->dev, 1ull << qp->qp_num);
goto again;
}
}
@ -956,9 +951,9 @@ ntb_transport_doorbell_callback(void *data, uint32_t vector)
BIT_COPY(QP_SETSIZE, &nt->qp_bitmap, &db_bits);
BIT_NAND(QP_SETSIZE, &db_bits, &nt->qp_bitmap_free);
vec_mask = NTB_DB_VECTOR_MASK(nt->ntb, vector);
vec_mask = ntb_db_vector_mask(nt->dev, vector);
if ((vec_mask & (vec_mask - 1)) != 0)
vec_mask &= NTB_DB_READ(nt->ntb);
vec_mask &= ntb_db_read(nt->dev);
while (vec_mask != 0) {
qp_num = ffsll(vec_mask) - 1;
@ -978,7 +973,7 @@ ntb_transport_event_callback(void *data)
{
struct ntb_transport_ctx *nt = data;
if (NTB_LINK_IS_UP(nt->ntb, NULL, NULL)) {
if (ntb_link_is_up(nt->dev, NULL, NULL)) {
ntb_printf(1, "HW link up\n");
callout_reset(&nt->link_work, 0, ntb_transport_link_work, nt);
} else {
@ -992,7 +987,7 @@ static void
ntb_transport_link_work(void *arg)
{
struct ntb_transport_ctx *nt = arg;
device_t ntb = nt->ntb;
device_t dev = nt->dev;
struct ntb_transport_qp *qp;
uint64_t val64, size;
uint32_t val;
@ -1006,36 +1001,36 @@ ntb_transport_link_work(void *arg)
if (max_mw_size != 0 && size > max_mw_size)
size = max_mw_size;
NTB_PEER_SPAD_WRITE(ntb, NTBT_MW0_SZ_HIGH + (i * 2),
ntb_peer_spad_write(dev, NTBT_MW0_SZ_HIGH + (i * 2),
size >> 32);
NTB_PEER_SPAD_WRITE(ntb, NTBT_MW0_SZ_LOW + (i * 2), size);
ntb_peer_spad_write(dev, NTBT_MW0_SZ_LOW + (i * 2), size);
}
NTB_PEER_SPAD_WRITE(ntb, NTBT_NUM_MWS, nt->mw_count);
ntb_peer_spad_write(dev, NTBT_NUM_MWS, nt->mw_count);
NTB_PEER_SPAD_WRITE(ntb, NTBT_NUM_QPS, nt->qp_count);
ntb_peer_spad_write(dev, NTBT_NUM_QPS, nt->qp_count);
NTB_PEER_SPAD_WRITE(ntb, NTBT_VERSION, NTB_TRANSPORT_VERSION);
ntb_peer_spad_write(dev, NTBT_VERSION, NTB_TRANSPORT_VERSION);
/* Query the remote side for its info */
val = 0;
NTB_SPAD_READ(ntb, NTBT_VERSION, &val);
ntb_spad_read(dev, NTBT_VERSION, &val);
if (val != NTB_TRANSPORT_VERSION)
goto out;
NTB_SPAD_READ(ntb, NTBT_NUM_QPS, &val);
ntb_spad_read(dev, NTBT_NUM_QPS, &val);
if (val != nt->qp_count)
goto out;
NTB_SPAD_READ(ntb, NTBT_NUM_MWS, &val);
ntb_spad_read(dev, NTBT_NUM_MWS, &val);
if (val != nt->mw_count)
goto out;
for (i = 0; i < nt->mw_count; i++) {
NTB_SPAD_READ(ntb, NTBT_MW0_SZ_HIGH + (i * 2), &val);
ntb_spad_read(dev, NTBT_MW0_SZ_HIGH + (i * 2), &val);
val64 = (uint64_t)val << 32;
NTB_SPAD_READ(ntb, NTBT_MW0_SZ_LOW + (i * 2), &val);
ntb_spad_read(dev, NTBT_MW0_SZ_LOW + (i * 2), &val);
val64 |= val;
rc = ntb_set_mw(nt, i, val64);
@ -1061,7 +1056,7 @@ ntb_transport_link_work(void *arg)
for (i = 0; i < nt->mw_count; i++)
ntb_free_mw(nt, i);
out:
if (NTB_LINK_IS_UP(ntb, NULL, NULL))
if (ntb_link_is_up(dev, NULL, NULL))
callout_reset(&nt->link_work,
NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_transport_link_work, nt);
}
@ -1116,7 +1111,7 @@ ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, size_t size)
}
/* Notify HW the memory location of the receive buffer */
rc = NTB_MW_SET_TRANS(nt->ntb, num_mw, mw->dma_addr, mw->xlat_size);
rc = ntb_mw_set_trans(nt->dev, num_mw, mw->dma_addr, mw->xlat_size);
if (rc) {
ntb_printf(0, "Unable to set mw%d translation\n", num_mw);
ntb_free_mw(nt, num_mw);
@ -1134,7 +1129,7 @@ ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
if (mw->virt_addr == NULL)
return;
NTB_MW_CLEAR_TRANS(nt->ntb, num_mw);
ntb_mw_clear_trans(nt->dev, num_mw);
contigfree(mw->virt_addr, mw->xlat_size, M_NTB_T);
mw->xlat_size = 0;
mw->buff_size = 0;
@ -1194,16 +1189,16 @@ static void
ntb_qp_link_work(void *arg)
{
struct ntb_transport_qp *qp = arg;
device_t ntb = qp->ntb;
device_t dev = qp->dev;
struct ntb_transport_ctx *nt = qp->transport;
uint32_t val, dummy;
NTB_SPAD_READ(ntb, NTBT_QP_LINKS, &val);
ntb_spad_read(dev, NTBT_QP_LINKS, &val);
NTB_PEER_SPAD_WRITE(ntb, NTBT_QP_LINKS, val | (1ull << qp->qp_num));
ntb_peer_spad_write(dev, NTBT_QP_LINKS, val | (1ull << qp->qp_num));
/* query remote spad for qp ready bits */
NTB_PEER_SPAD_READ(ntb, NTBT_QP_LINKS, &dummy);
ntb_peer_spad_read(dev, NTBT_QP_LINKS, &dummy);
/* See if the remote side is up */
if ((val & (1ull << qp->qp_num)) != 0) {
@ -1213,7 +1208,7 @@ ntb_qp_link_work(void *arg)
if (qp->event_handler != NULL)
qp->event_handler(qp->cb_data, NTB_LINK_UP);
NTB_DB_CLEAR_MASK(ntb, 1ull << qp->qp_num);
ntb_db_clear_mask(dev, 1ull << qp->qp_num);
} else if (nt->link_is_up)
callout_reset(&qp->link_work,
NTB_LINK_DOWN_TIMEOUT * hz / 1000, ntb_qp_link_work, qp);
@ -1247,7 +1242,7 @@ ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
* time they are accessed
*/
for (i = 0; i < NTBT_MAX_SPAD; i++)
NTB_SPAD_WRITE(nt->ntb, i, 0);
ntb_spad_write(nt->dev, i, 0);
}
static void
@ -1269,7 +1264,7 @@ ntb_qp_link_down_reset(struct ntb_transport_qp *qp)
{
qp->link_is_up = false;
NTB_DB_SET_MASK(qp->ntb, 1ull << qp->qp_num);
ntb_db_set_mask(qp->dev, 1ull << qp->qp_num);
qp->tx_index = qp->rx_index = 0;
qp->tx_bytes = qp->rx_bytes = 0;
@ -1312,9 +1307,9 @@ ntb_transport_link_down(struct ntb_transport_qp *qp)
qp->client_ready = false;
NTB_SPAD_READ(qp->ntb, NTBT_QP_LINKS, &val);
ntb_spad_read(qp->dev, NTBT_QP_LINKS, &val);
NTB_PEER_SPAD_WRITE(qp->ntb, NTBT_QP_LINKS,
ntb_peer_spad_write(qp->dev, NTBT_QP_LINKS,
val & ~(1 << qp->qp_num));
if (qp->link_is_up)