aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ntb/ntb_transport.c
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2016-07-29 17:15:41 +0000
committerAlexander Motin <mav@FreeBSD.org>2016-07-29 17:15:41 +0000
commit6bd57d14ed207b6b5aa94f81b8bef29bc52b8518 (patch)
tree8b1d100670cef43198ab3b7b43e8c7363a1a0f8e /sys/dev/ntb/ntb_transport.c
parent793172ea8846d38e8425883ab942328ddef363e0 (diff)
downloadsrc-6bd57d14ed207b6b5aa94f81b8bef29bc52b8518.tar.gz
src-6bd57d14ed207b6b5aa94f81b8bef29bc52b8518.zip
Once more refactor KPI between ntb_transport(4) and if_ntb(4)..
New design allows to attach multiple consumers to ntb_transport(4) instance. Previous design obtained from Linux theoretically allowed that, but was not practically usable (Linux also has only one consumer driver now).
Notes
Notes: svn path=/head/; revision=303494
Diffstat (limited to 'sys/dev/ntb/ntb_transport.c')
-rw-r--r--sys/dev/ntb/ntb_transport.c208
1 files changed, 129 insertions, 79 deletions
diff --git a/sys/dev/ntb/ntb_transport.c b/sys/dev/ntb/ntb_transport.c
index d3ea6df1591d..c4b8fd0dc916 100644
--- a/sys/dev/ntb/ntb_transport.c
+++ b/sys/dev/ntb/ntb_transport.c
@@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
-#include <sys/bitset.h>
#include <sys/bus.h>
#include <sys/ktr.h>
#include <sys/limits.h>
@@ -64,13 +63,6 @@ __FBSDID("$FreeBSD$");
#include "ntb.h"
#include "ntb_transport.h"
-#define QP_SETSIZE 64
-BITSET_DEFINE(_qpset, QP_SETSIZE);
-#define test_bit(pos, addr) BIT_ISSET(QP_SETSIZE, (pos), (addr))
-#define set_bit(pos, addr) BIT_SET(QP_SETSIZE, (pos), (addr))
-#define clear_bit(pos, addr) BIT_CLR(QP_SETSIZE, (pos), (addr))
-#define ffs_bit(addr) BIT_FFS(QP_SETSIZE, (addr))
-
#define KTR_NTB KTR_SPARE3
#define NTB_TRANSPORT_VERSION 4
@@ -94,12 +86,6 @@ SYSCTL_UQUAD(_hw_ntb_transport, OID_AUTO, max_mw_size, CTLFLAG_RDTUN, &max_mw_si
"If enabled (non-zero), limit the size of large memory windows. "
"Both sides of the NTB MUST set the same value here.");
-static unsigned max_num_clients;
-SYSCTL_UINT(_hw_ntb_transport, OID_AUTO, max_num_clients, CTLFLAG_RDTUN,
- &max_num_clients, 0, "Maximum number of NTB transport clients. "
- "0 (default) - use all available NTB memory windows; "
- "positive integer N - Limit to N memory windows.");
-
static unsigned enable_xeon_watchdog;
SYSCTL_UINT(_hw_ntb_transport, OID_AUTO, enable_xeon_watchdog, CTLFLAG_RDTUN,
&enable_xeon_watchdog, 0, "If non-zero, write a register every second to "
@@ -200,14 +186,21 @@ struct ntb_transport_mw {
bus_addr_t dma_addr;
};
+struct ntb_transport_child {
+ device_t dev;
+ int qpoff;
+ int qpcnt;
+ struct ntb_transport_child *next;
+};
+
struct ntb_transport_ctx {
device_t dev;
+ struct ntb_transport_child *child;
struct ntb_transport_mw *mw_vec;
struct ntb_transport_qp *qp_vec;
- struct _qpset qp_bitmap;
- struct _qpset qp_bitmap_free;
unsigned mw_count;
unsigned qp_count;
+ uint64_t qp_bitmap;
volatile bool link_is_up;
struct callout link_work;
struct callout link_watchdog;
@@ -242,7 +235,6 @@ enum {
NTBT_MW0_SZ_LOW,
NTBT_MW1_SZ_HIGH,
NTBT_MW1_SZ_LOW,
- NTBT_MAX_SPAD,
/*
* Some NTB-using hardware have a watchdog to work around NTB hangs; if
@@ -332,13 +324,44 @@ static int
ntb_transport_attach(device_t dev)
{
struct ntb_transport_ctx *nt = device_get_softc(dev);
+ struct ntb_transport_child **cpp = &nt->child;
+ struct ntb_transport_child *nc;
struct ntb_transport_mw *mw;
- uint64_t qp_bitmap;
- int rc;
- unsigned i;
+ uint64_t db_bitmap;
+ int rc, i, db_count, spad_count, qp, qpu, qpo, qpt;
+ char cfg[128] = "";
+ char buf[32];
+ char *n, *np, *c, *name;
nt->dev = dev;
nt->mw_count = ntb_mw_count(dev);
+ spad_count = ntb_spad_count(dev);
+ db_bitmap = ntb_db_valid_mask(dev);
+ db_count = flsll(db_bitmap);
+ KASSERT(db_bitmap == (1 << db_count) - 1,
+ ("Doorbells are not sequential (%jx).\n", db_bitmap));
+
+ device_printf(dev, "%d memory windows, %d scratchpads, "
+ "%d doorbells\n", nt->mw_count, spad_count, db_count);
+
+ if (nt->mw_count == 0) {
+ device_printf(dev, "At least 1 memory window required.\n");
+ return (ENXIO);
+ }
+ if (spad_count < 6) {
+ device_printf(dev, "At least 6 scratchpads required.\n");
+ return (ENXIO);
+ }
+ if (spad_count < 4 + 2 * nt->mw_count) {
+ nt->mw_count = (spad_count - 4) / 2;
+ device_printf(dev, "Scratchpads enough only for %d "
+ "memory windows.\n", nt->mw_count);
+ }
+ if (db_bitmap == 0) {
+ device_printf(dev, "At least one doorbell required.\n");
+ return (ENXIO);
+ }
+
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++) {
@@ -360,25 +383,59 @@ ntb_transport_attach(device_t dev)
ntb_printf(0, "Unable to set mw%d caching\n", i);
}
- 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;
+ qpu = 0;
+ qpo = imin(db_count, nt->mw_count);
+ qpt = db_count;
+
+ 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;
+ qp = (np && np[0] != 0) ? strtol(np, NULL, 10) : qpo - qpu;
+ if (qp <= 0)
+ qp = 1;
+
+ if (qp > qpt - qpu) {
+ device_printf(dev, "Not enough resources for config\n");
+ break;
+ }
- if (max_num_clients != 0 && max_num_clients < nt->qp_count)
- nt->qp_count = max_num_clients;
- else if (nt->mw_count < nt->qp_count)
- nt->qp_count = nt->mw_count;
- KASSERT(nt->qp_count <= QP_SETSIZE, ("invalid qp_count"));
+ nc = malloc(sizeof(*nc), M_DEVBUF, M_WAITOK | M_ZERO);
+ nc->qpoff = qpu;
+ nc->qpcnt = qp;
+ nc->dev = device_add_child(dev, name, -1);
+ if (nc->dev == NULL) {
+ device_printf(dev, "Can not add child.\n");
+ break;
+ }
+ device_set_ivars(nc->dev, nc);
+ *cpp = nc;
+ cpp = &nc->next;
+
+ if (bootverbose) {
+ device_printf(dev, "%d \"%s\": queues %d",
+ i, name, qpu);
+ if (qp > 1)
+ printf("-%d", qpu + qp - 1);
+ printf("\n");
+ }
+
+ qpu += qp;
+ i++;
+ }
+ nt->qp_count = qpu;
nt->qp_vec = malloc(nt->qp_count * sizeof(*nt->qp_vec), M_NTB_T,
M_WAITOK | M_ZERO);
- for (i = 0; i < nt->qp_count; i++) {
- set_bit(i, &nt->qp_bitmap);
- set_bit(i, &nt->qp_bitmap_free);
+ for (i = 0; i < nt->qp_count; i++)
ntb_transport_init_queue(nt, i);
- }
callout_init(&nt->link_work, 0);
callout_init(&nt->link_watchdog, 0);
@@ -394,10 +451,7 @@ ntb_transport_attach(device_t dev)
if (enable_xeon_watchdog != 0)
callout_reset(&nt->link_watchdog, 0, xeon_link_watchdog_hb, nt);
- /* Attach children to this transport */
- device_add_child(dev, NULL, -1);
bus_generic_attach(dev);
-
return (0);
err:
@@ -410,25 +464,25 @@ static int
ntb_transport_detach(device_t dev)
{
struct ntb_transport_ctx *nt = device_get_softc(dev);
- struct _qpset qp_bitmap_alloc;
- uint8_t i;
-
- /* Detach & delete all children */
- device_delete_children(dev);
+ struct ntb_transport_child **cpp = &nt->child;
+ struct ntb_transport_child *nc;
+ int error = 0, i;
+
+ while ((nc = *cpp) != NULL) {
+ *cpp = (*cpp)->next;
+ error = device_delete_child(dev, nc->dev);
+ if (error)
+ break;
+ free(nc, M_DEVBUF);
+ }
+ KASSERT(nt->qp_bitmap == 0,
+ ("Some queues not freed on detach (%jx)", nt->qp_bitmap));
ntb_transport_link_cleanup(nt);
taskqueue_drain(taskqueue_swi, &nt->link_cleanup);
callout_drain(&nt->link_work);
callout_drain(&nt->link_watchdog);
- BIT_COPY(QP_SETSIZE, &nt->qp_bitmap, &qp_bitmap_alloc);
- BIT_NAND(QP_SETSIZE, &qp_bitmap_alloc, &nt->qp_bitmap_free);
-
- /* Verify that all the QPs are freed */
- for (i = 0; i < nt->qp_count; i++)
- if (test_bit(i, &qp_bitmap_alloc))
- ntb_transport_free_queue(&nt->qp_vec[i]);
-
ntb_link_disable(dev);
ntb_clear_ctx(dev);
@@ -440,6 +494,14 @@ ntb_transport_detach(device_t dev)
return (0);
}
+int
+ntb_transport_queue_count(device_t dev)
+{
+ struct ntb_transport_child *nc = device_get_ivars(dev);
+
+ return (nc->qpcnt);
+}
+
static void
ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num)
{
@@ -507,6 +569,7 @@ ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num)
void
ntb_transport_free_queue(struct ntb_transport_qp *qp)
{
+ struct ntb_transport_ctx *nt = qp->transport;
struct ntb_queue_entry *entry;
if (qp == NULL)
@@ -532,7 +595,7 @@ ntb_transport_free_queue(struct ntb_transport_qp *qp)
while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q)))
free(entry, M_NTB_T);
- set_bit(qp->qp_num, &qp->transport->qp_bitmap_free);
+ nt->qp_bitmap &= ~(1 << qp->qp_num);
}
/**
@@ -550,24 +613,20 @@ ntb_transport_free_queue(struct ntb_transport_qp *qp)
* RETURNS: pointer to newly created ntb_queue, NULL on error.
*/
struct ntb_transport_qp *
-ntb_transport_create_queue(void *data, device_t dev,
- const struct ntb_queue_handlers *handlers)
+ntb_transport_create_queue(device_t dev, int q,
+ const struct ntb_queue_handlers *handlers, void *data)
{
- struct ntb_transport_ctx *nt = device_get_softc(dev);
+ struct ntb_transport_child *nc = device_get_ivars(dev);
+ struct ntb_transport_ctx *nt = device_get_softc(device_get_parent(dev));
struct ntb_queue_entry *entry;
struct ntb_transport_qp *qp;
- unsigned int free_queue;
int i;
- free_queue = ffs_bit(&nt->qp_bitmap_free);
- if (free_queue == 0)
+ if (q < 0 || q >= nc->qpcnt)
return (NULL);
- /* decrement free_queue to make it zero based */
- free_queue--;
-
- qp = &nt->qp_vec[free_queue];
- clear_bit(qp->qp_num, &nt->qp_bitmap_free);
+ qp = &nt->qp_vec[nc->qpoff + q];
+ nt->qp_bitmap |= (1 << qp->qp_num);
qp->cb_data = data;
qp->rx_handler = handlers->rx_handler;
qp->tx_handler = handlers->tx_handler;
@@ -944,24 +1003,19 @@ ntb_transport_doorbell_callback(void *data, uint32_t vector)
{
struct ntb_transport_ctx *nt = data;
struct ntb_transport_qp *qp;
- struct _qpset db_bits;
uint64_t vec_mask;
unsigned qp_num;
- 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->dev, vector);
+ vec_mask &= nt->qp_bitmap;
if ((vec_mask & (vec_mask - 1)) != 0)
vec_mask &= ntb_db_read(nt->dev);
while (vec_mask != 0) {
qp_num = ffsll(vec_mask) - 1;
- if (test_bit(qp_num, &db_bits)) {
- qp = &nt->qp_vec[qp_num];
- if (qp->link_is_up)
- taskqueue_enqueue(qp->rxc_tq, &qp->rxc_db_work);
- }
+ qp = &nt->qp_vec[qp_num];
+ if (qp->link_is_up)
+ taskqueue_enqueue(qp->rxc_tq, &qp->rxc_db_work);
vec_mask &= ~(1ull << qp_num);
}
@@ -1219,19 +1273,16 @@ static void
ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
{
struct ntb_transport_qp *qp;
- struct _qpset qp_bitmap_alloc;
- unsigned i;
-
- BIT_COPY(QP_SETSIZE, &nt->qp_bitmap, &qp_bitmap_alloc);
- BIT_NAND(QP_SETSIZE, &qp_bitmap_alloc, &nt->qp_bitmap_free);
+ int i;
/* Pass along the info to any clients */
- for (i = 0; i < nt->qp_count; i++)
- if (test_bit(i, &qp_bitmap_alloc)) {
+ for (i = 0; i < nt->qp_count; i++) {
+ if ((nt->qp_bitmap & (1 << i)) != 0) {
qp = &nt->qp_vec[i];
ntb_qp_link_cleanup(qp);
callout_drain(&qp->link_work);
}
+ }
if (!nt->link_is_up)
callout_drain(&nt->link_work);
@@ -1241,8 +1292,7 @@ ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
* goes down, blast them now to give them a sane value the next
* time they are accessed
*/
- for (i = 0; i < NTBT_MAX_SPAD; i++)
- ntb_spad_write(nt->dev, i, 0);
+ ntb_spad_clear(nt->dev);
}
static void