Introduce a backend abstraction layer so ntb_transport can support multiple data-plane implementations without too much code duplication.
Add backend registration APIs, store the selected backend in the transport context, and route key operations through backend hooks. Also add per-entry/per-QP private pointers and move backend-specific debugfs stats behind the backend ops callback. Register the existing implementation as the default backend. Signed-off-by: Koichiro Den <[email protected]> --- drivers/ntb/ntb_transport_core.c | 329 ++++++++++++++++++++++----- drivers/ntb/ntb_transport_internal.h | 80 +++++++ 2 files changed, 347 insertions(+), 62 deletions(-) diff --git a/drivers/ntb/ntb_transport_core.c b/drivers/ntb/ntb_transport_core.c index 86181fe1eadd..2129fa7a22d8 100644 --- a/drivers/ntb/ntb_transport_core.c +++ b/drivers/ntb/ntb_transport_core.c @@ -77,6 +77,8 @@ MODULE_VERSION(NTB_TRANSPORT_VER); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); +static LIST_HEAD(ntb_transport_backends); +static DEFINE_MUTEX(ntb_transport_backend_lock); static struct dentry *nt_debugfs_dir; @@ -300,15 +302,51 @@ void ntb_transport_unregister_client(struct ntb_transport_client *drv) } EXPORT_SYMBOL_GPL(ntb_transport_unregister_client); -static int ntb_qp_debugfs_stats_show(struct seq_file *s, void *v) +int ntb_transport_backend_register(struct ntb_transport_backend *b) { - struct ntb_transport_qp *qp = s->private; + struct ntb_transport_backend *tmp; - if (!qp || !qp->link_is_up) - return 0; + if (!b || !b->name || !b->ops) + return -EINVAL; - seq_puts(s, "\nNTB QP stats:\n\n"); + mutex_lock(&ntb_transport_backend_lock); + list_for_each_entry(tmp, &ntb_transport_backends, node) { + if (!strcmp(tmp->name, b->name)) { + mutex_unlock(&ntb_transport_backend_lock); + return -EEXIST; + } + } + list_add_tail(&b->node, &ntb_transport_backends); + mutex_unlock(&ntb_transport_backend_lock); + return 0; +} +EXPORT_SYMBOL_GPL(ntb_transport_backend_register); + +void ntb_transport_backend_unregister(struct ntb_transport_backend *b) +{ + if (!b) + return; + mutex_lock(&ntb_transport_backend_lock); + list_del_init(&b->node); + mutex_unlock(&ntb_transport_backend_lock); +} +EXPORT_SYMBOL_GPL(ntb_transport_backend_unregister); + +static struct ntb_transport_backend *ntb_transport_backend_find(const char *name) +{ + struct ntb_transport_backend *b; + + list_for_each_entry(b, &ntb_transport_backends, node) { + if (!strcmp(b->name, name)) + return b; + } + + return NULL; +} +static void ntb_transport_default_debugfs_stats_show(struct seq_file *s, + struct ntb_transport_qp *qp) +{ seq_printf(s, "rx_bytes - \t%llu\n", qp->rx_bytes); seq_printf(s, "rx_pkts - \t%llu\n", qp->rx_pkts); seq_printf(s, "rx_memcpy - \t%llu\n", qp->rx_memcpy); @@ -338,6 +376,17 @@ static int ntb_qp_debugfs_stats_show(struct seq_file *s, void *v) seq_printf(s, "Using TX DMA - \t%s\n", qp->tx_dma_chan ? "Yes" : "No"); seq_printf(s, "Using RX DMA - \t%s\n", qp->rx_dma_chan ? "Yes" : "No"); seq_printf(s, "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down"); +} + +static int ntb_qp_debugfs_stats_show(struct seq_file *s, void *v) +{ + struct ntb_transport_qp *qp = s->private; + + if (!qp || !qp->link_is_up) + return 0; + + seq_puts(s, "\nNTB QP stats:\n\n"); + qp->transport->backend->ops->debugfs_stats_show(s, qp); seq_putc(s, '\n'); return 0; @@ -395,8 +444,37 @@ struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock, struct list_head *list, } EXPORT_SYMBOL_GPL(ntb_list_mv); -static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, - unsigned int qp_num) +struct ntb_queue_entry * +ntb_queue_entry_alloc(struct ntb_transport_ctx *nt, struct ntb_transport_qp *qp, int node) +{ + static struct ntb_queue_entry *entry; + + entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); + if (!entry) + return NULL; + + if (nt->backend->ops->entry_priv_alloc) { + entry->priv = nt->backend->ops->entry_priv_alloc(); + if (!entry->priv) { + kfree(entry); + return NULL; + } + } + return entry; +} +EXPORT_SYMBOL_GPL(ntb_queue_entry_alloc); + +static void +ntb_queue_entry_free(struct ntb_transport_ctx *nt, struct ntb_queue_entry *entry) +{ + if (nt->backend->ops->entry_priv_free) + nt->backend->ops->entry_priv_free(entry->priv); + + kfree(entry); +} + +static int ntb_transport_default_setup_qp_mw(struct ntb_transport_ctx *nt, + unsigned int qp_num) { struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; struct ntb_transport_mw *mw; @@ -467,7 +545,7 @@ static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, */ node = dev_to_node(&ndev->dev); for (i = qp->rx_alloc_entry; i < qp->rx_max_entry; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); + entry = ntb_queue_entry_alloc(nt, qp, node); if (!entry) return -ENOMEM; @@ -805,6 +883,9 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt) u64 qp_bitmap_alloc; unsigned int i, count; + if (nt->backend->ops->link_down) + nt->backend->ops->link_down(nt); + qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; /* Pass along the info to any clients */ @@ -866,6 +947,12 @@ static void ntb_transport_link_work(struct work_struct *work) /* send the local info, in the opposite order of the way we read it */ + if (nt->backend->ops->link_up_pre) { + rc = nt->backend->ops->link_up_pre(nt); + if (rc) + return; + } + if (nt->use_msi) { rc = ntb_msi_setup_mws(ndev); if (rc) { @@ -952,10 +1039,16 @@ static void ntb_transport_link_work(struct work_struct *work) nt->link_is_up = true; + if (nt->backend->ops->link_up_post) { + rc = nt->backend->ops->link_up_post(nt); + if (rc) + return; + } + for (i = 0; i < nt->qp_count; i++) { struct ntb_transport_qp *qp = &nt->qp_vec[i]; - ntb_transport_setup_qp_mw(nt, i); + nt->backend->ops->setup_qp_mw(nt, i); ntb_transport_setup_qp_peer_msi(nt, i); if (qp->client_ready) @@ -1012,8 +1105,7 @@ static void ntb_qp_link_work(struct work_struct *work) msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } -static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, - unsigned int qp_num) +int ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num) { struct ntb_transport_qp *qp; @@ -1057,6 +1149,69 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, return 0; } +static unsigned int ntb_transport_default_tx_free_entry(struct ntb_transport_qp *qp) +{ + unsigned int head = qp->tx_index; + unsigned int tail = qp->remote_rx_info->entry; + + return tail >= head ? tail - head : qp->tx_max_entry + tail - head; +} + +static int ntb_transport_default_rx_enqueue(struct ntb_transport_qp *qp, + struct ntb_queue_entry *entry) +{ + ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q); + + if (qp->active) + tasklet_schedule(&qp->rxc_db_work); + + return 0; +} + +static void ntb_transport_default_rx_poll(struct ntb_transport_qp *qp); +static int ntb_transport_default_tx_enqueue(struct ntb_transport_qp *qp, + struct ntb_queue_entry *entry, + void *cb, void *data, unsigned int len, + unsigned int flags); + +static const struct ntb_transport_backend_ops default_backend_ops = { + .setup_qp_mw = ntb_transport_default_setup_qp_mw, + .tx_free_entry = ntb_transport_default_tx_free_entry, + .tx_enqueue = ntb_transport_default_tx_enqueue, + .rx_enqueue = ntb_transport_default_rx_enqueue, + .rx_poll = ntb_transport_default_rx_poll, + .debugfs_stats_show = ntb_transport_default_debugfs_stats_show, +}; + +static struct ntb_transport_backend default_transport_backend = { + .name = "default", + .ops = &default_backend_ops, + .owner = THIS_MODULE, +}; + +static struct ntb_transport_backend * +ntb_transport_backend_get(const char *name) +{ + struct ntb_transport_backend *b; + + if (!name || !name[0]) + name = "default"; + + mutex_lock(&ntb_transport_backend_lock); + b = ntb_transport_backend_find(name); + if (b && !try_module_get(b->owner)) + b = NULL; + mutex_unlock(&ntb_transport_backend_lock); + + return b; +} + +static void +ntb_transport_backend_put(struct ntb_transport_backend *b) +{ + module_put(b->owner); +} + int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, bool use_msi, unsigned long max_mw_size, unsigned int transport_mtu, @@ -1064,6 +1219,7 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, unsigned int copy_bytes, bool use_dma, unsigned int num_rx_entries) { + struct ntb_transport_backend *b; struct ntb_transport_ctx *nt; struct ntb_transport_mw *mw; unsigned int mw_count, qp_count, spad_count, max_mw_count_for_spads; @@ -1101,6 +1257,20 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, nt->use_dma = use_dma; nt->num_rx_entries = num_rx_entries; + b = ntb_transport_backend_get(backend_name); + if (!b) { + rc = -EPROBE_DEFER; + goto err_free_ctx; + } + + nt->backend = b; + + if (b->ops->enable) { + rc = b->ops->enable(nt, &mw_count); + if (rc) + goto err_put_backend; + } + /* * If we are using MSI, and have at least one extra memory window, * we will reserve the last MW for the MSI window. @@ -1120,7 +1290,7 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, if (spad_count < NTB_TRANSPORT_MIN_SPADS) { nt->mw_count = 0; rc = -EINVAL; - goto err; + goto err_disable_backend; } max_mw_count_for_spads = (spad_count - MW0_SZ_HIGH) / 2; @@ -1132,7 +1302,7 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, GFP_KERNEL, node); if (!nt->mw_vec) { rc = -ENOMEM; - goto err; + goto err_disable_backend; } for (i = 0; i < mw_count; i++) { @@ -1141,12 +1311,12 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, rc = ntb_peer_mw_get_addr(ndev, i, &mw->phys_addr, &mw->phys_size); if (rc) - goto err1; + goto err_free_mw_vec; mw->vbase = ioremap_wc(mw->phys_addr, mw->phys_size); if (!mw->vbase) { rc = -ENOMEM; - goto err1; + goto err_free_mw_vec; } mw->buff_size = 0; @@ -1177,7 +1347,7 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, GFP_KERNEL, node); if (!nt->qp_vec) { rc = -ENOMEM; - goto err1; + goto err_free_mw_vec; } if (nt_debugfs_dir) { @@ -1189,7 +1359,13 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, for (i = 0; i < qp_count; i++) { rc = ntb_transport_init_queue(nt, i); if (rc) - goto err2; + goto err_free_qp_vec; + + if (b->ops->qp_init) { + rc = b->ops->qp_init(nt, i); + if (rc) + goto err_free_qp_vec; + } } INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work); @@ -1197,12 +1373,12 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops); if (rc) - goto err2; + goto err_free_qp_vec; INIT_LIST_HEAD(&nt->client_devs); rc = ntb_bus_init(nt); if (rc) - goto err3; + goto err_clear_ctx; nt->link_is_up = false; ntb_link_enable(ndev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); @@ -1210,17 +1386,22 @@ int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, return 0; -err3: +err_clear_ctx: ntb_clear_ctx(ndev); -err2: +err_free_qp_vec: kfree(nt->qp_vec); -err1: +err_free_mw_vec: while (i--) { mw = &nt->mw_vec[i]; iounmap(mw->vbase); } kfree(nt->mw_vec); -err: +err_disable_backend: + if (b->ops->disable) + b->ops->disable(nt); +err_put_backend: + module_put(nt->backend->owner); +err_free_ctx: kfree(nt); return rc; } @@ -1229,10 +1410,13 @@ EXPORT_SYMBOL_GPL(ntb_transport_attach); void ntb_transport_detach(struct ntb_dev *ndev) { struct ntb_transport_ctx *nt = ndev->ctx; + struct ntb_transport_backend *b; struct ntb_transport_qp *qp; u64 qp_bitmap_alloc; int i; + WARN_ON_ONCE(!nt); + ntb_transport_link_cleanup(nt); cancel_work_sync(&nt->link_cleanup); cancel_delayed_work_sync(&nt->link_work); @@ -1258,6 +1442,11 @@ void ntb_transport_detach(struct ntb_dev *ndev) iounmap(nt->mw_vec[i].vbase); } + b = nt->backend; + if (b && b->ops->disable) + b->ops->disable(nt); + ntb_transport_backend_put(b); + kfree(nt->qp_vec); kfree(nt->mw_vec); kfree(nt); @@ -1513,14 +1702,10 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) return 0; } -static void ntb_transport_rxc_db(unsigned long data) +static void ntb_transport_default_rx_poll(struct ntb_transport_qp *qp) { - struct ntb_transport_qp *qp = (void *)data; int rc, i; - dev_dbg(&qp->ndev->pdev->dev, "%s: doorbell %d received\n", - __func__, qp->qp_num); - /* Limit the number of packets processed in a single interrupt to * provide fairness to others */ @@ -1552,6 +1737,17 @@ static void ntb_transport_rxc_db(unsigned long data) } } +static void ntb_transport_rxc_db(unsigned long data) +{ + struct ntb_transport_qp *qp = (void *)data; + struct ntb_transport_ctx *nt = qp->transport; + + dev_dbg(&qp->ndev->pdev->dev, "%s: doorbell %d received\n", + __func__, qp->qp_num); + + nt->backend->ops->rx_poll(qp); +} + static void ntb_tx_copy_callback(void *data, const struct dmaengine_result *res) { @@ -1721,9 +1917,18 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, qp->tx_memcpy++; } -static int ntb_process_tx(struct ntb_transport_qp *qp, - struct ntb_queue_entry *entry) +static int ntb_transport_default_tx_enqueue(struct ntb_transport_qp *qp, + struct ntb_queue_entry *entry, + void *cb, void *data, unsigned int len, + unsigned int flags) { + entry->cb_data = cb; + entry->buf = data; + entry->len = len; + entry->flags = flags; + entry->errors = 0; + entry->tx_index = 0; + if (!ntb_transport_tx_free_entry(qp)) { qp->tx_ring_full++; return -EAGAIN; @@ -1750,6 +1955,7 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, static void ntb_send_link_down(struct ntb_transport_qp *qp) { + struct ntb_transport_ctx *nt = qp->transport; struct pci_dev *pdev = qp->ndev->pdev; struct ntb_queue_entry *entry; int i, rc; @@ -1769,12 +1975,7 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) if (!entry) return; - entry->cb_data = NULL; - entry->buf = NULL; - entry->len = 0; - entry->flags = LINK_DOWN_FLAG; - - rc = ntb_process_tx(qp, entry); + rc = nt->backend->ops->tx_enqueue(qp, entry, NULL, NULL, 0, LINK_DOWN_FLAG); if (rc) dev_err(&pdev->dev, "ntb: QP%d unable to send linkdown msg\n", qp->qp_num); @@ -1834,6 +2035,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, nt->qp_bitmap_free &= ~qp_bit; + qp->qp_bit = qp_bit; qp->cb_data = data; qp->rx_handler = handlers->rx_handler; qp->tx_handler = handlers->tx_handler; @@ -1879,7 +2081,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->rx_dma_chan ? "DMA" : "CPU"); for (i = 0; i < nt->num_rx_entries; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); + entry = ntb_queue_entry_alloc(nt, qp, node); if (!entry) goto err1; @@ -1890,7 +2092,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, qp->rx_alloc_entry = nt->num_rx_entries; for (i = 0; i < qp->tx_max_entry; i++) { - entry = kzalloc_node(sizeof(*entry), GFP_KERNEL, node); + entry = ntb_queue_entry_alloc(nt, qp, node); if (!entry) goto err2; @@ -1908,11 +2110,11 @@ ntb_transport_create_queue(void *data, struct device *client_dev, err2: while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) - kfree(entry); + ntb_queue_entry_free(nt, entry); err1: qp->rx_alloc_entry = 0; while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) - kfree(entry); + ntb_queue_entry_free(nt, entry); if (qp->tx_mw_dma_addr) dma_unmap_resource(qp->tx_dma_chan->device->dev, qp->tx_mw_dma_addr, qp->tx_mw_size, @@ -1935,6 +2137,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue); */ void ntb_transport_free_queue(struct ntb_transport_qp *qp) { + struct ntb_transport_ctx *nt; struct pci_dev *pdev; struct ntb_queue_entry *entry; u64 qp_bit; @@ -1942,6 +2145,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) if (!qp) return; + nt = qp->transport; pdev = qp->ndev->pdev; qp->active = false; @@ -1988,26 +2192,29 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) cancel_delayed_work_sync(&qp->link_work); + if (nt->backend->ops->qp_free) + nt->backend->ops->qp_free(qp); + qp->cb_data = NULL; qp->rx_handler = NULL; qp->tx_handler = NULL; qp->event_handler = NULL; while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) - kfree(entry); + ntb_queue_entry_free(nt, entry); while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_pend_q))) { dev_warn(&pdev->dev, "Freeing item from non-empty rx_pend_q\n"); - kfree(entry); + ntb_queue_entry_free(nt, entry); } while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_post_q))) { dev_warn(&pdev->dev, "Freeing item from non-empty rx_post_q\n"); - kfree(entry); + ntb_queue_entry_free(nt, entry); } while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) - kfree(entry); + ntb_queue_entry_free(nt, entry); qp->transport->qp_bitmap_free |= qp_bit; @@ -2061,11 +2268,13 @@ EXPORT_SYMBOL_GPL(ntb_transport_rx_remove); int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, unsigned int len) { + struct ntb_transport_ctx *nt; struct ntb_queue_entry *entry; if (!qp) return -EINVAL; + nt = qp->transport; entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q); if (!entry) return -ENOMEM; @@ -2078,12 +2287,7 @@ int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, entry->errors = 0; entry->rx_index = 0; - ntb_list_add(&qp->ntb_rx_q_lock, &entry->entry, &qp->rx_pend_q); - - if (qp->active) - tasklet_schedule(&qp->rxc_db_work); - - return 0; + return nt->backend->ops->rx_enqueue(qp, entry); } EXPORT_SYMBOL_GPL(ntb_transport_rx_enqueue); @@ -2103,6 +2307,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_rx_enqueue); int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, unsigned int len) { + struct ntb_transport_ctx *nt = qp->transport; struct ntb_queue_entry *entry; int rc; @@ -2119,15 +2324,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, return -EBUSY; } - entry->cb_data = cb; - entry->buf = data; - entry->len = len; - entry->flags = 0; - entry->errors = 0; - entry->retries = 0; - entry->tx_index = 0; - - rc = ntb_process_tx(qp, entry); + rc = nt->backend->ops->tx_enqueue(qp, entry, cb, data, len, 0); if (rc) ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q); @@ -2249,10 +2446,9 @@ EXPORT_SYMBOL_GPL(ntb_transport_max_size); unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp) { - unsigned int head = qp->tx_index; - unsigned int tail = qp->remote_rx_info->entry; + struct ntb_transport_ctx *nt = qp->transport; - return tail >= head ? tail - head : qp->tx_max_entry + tail - head; + return nt->backend->ops->tx_free_entry(qp); } EXPORT_SYMBOL_GPL(ntb_transport_tx_free_entry); @@ -2293,6 +2489,13 @@ static int __init ntb_transport_init(void) pr_info("%s, version %s\n", NTB_TRANSPORT_DESC, NTB_TRANSPORT_VER); + rc = ntb_transport_backend_register(&default_transport_backend); + if (rc) { + pr_err("%s: failed to register default transport backend\n", + NTB_TRANSPORT_NAME); + return rc; + } + if (debugfs_initialized()) nt_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); @@ -2300,6 +2503,7 @@ static int __init ntb_transport_init(void) if (rc) { bus_unregister(&ntb_transport_bus); debugfs_remove_recursive(nt_debugfs_dir); + ntb_transport_backend_unregister(&default_transport_backend); } return rc; } @@ -2309,5 +2513,6 @@ static void __exit ntb_transport_exit(void) { bus_unregister(&ntb_transport_bus); debugfs_remove_recursive(nt_debugfs_dir); + ntb_transport_backend_unregister(&default_transport_backend); } module_exit(ntb_transport_exit); diff --git a/drivers/ntb/ntb_transport_internal.h b/drivers/ntb/ntb_transport_internal.h index 406033dbddb7..a7cc44c466ee 100644 --- a/drivers/ntb/ntb_transport_internal.h +++ b/drivers/ntb/ntb_transport_internal.h @@ -33,6 +33,9 @@ struct ntb_queue_entry { struct ntb_payload_header __iomem *tx_hdr; struct ntb_payload_header *rx_hdr; }; + + /* Backend-specific */ + void *priv; }; struct ntb_rx_info { @@ -110,6 +113,9 @@ struct ntb_transport_qp { int msi_irq; struct ntb_msi_desc msi_desc; struct ntb_msi_desc peer_msi_desc; + + /* Backend-specific */ + void *priv; }; struct ntb_transport_mw { @@ -124,12 +130,74 @@ struct ntb_transport_mw { dma_addr_t dma_addr; }; +/** + * struct ntb_transport_backend_ops - ntb_transport backend operations + * @enable: Optional. Initialize backend-specific state for the + * passed @nt context on ntb_transport_attach(). + * @disable: Optional. Tear down backend-specific state initialized + * by @enable. Called from ntb_transport_detach() and + * attach error paths. + * @qp_init: Optional. Initialize per-QP backend-specific state for + * @qp_num. + * @qp_free: Optional. Tear down per-QP backend-specific state + * initialized by @qp_init. + * @link_up_pre: Optional. Called before the link-up handshake. + * @link_up_post: Optional. Called after the link-up handshake. + * @link_down: Optional. Called when tearing down an established link. + * @setup_qp_mw: Required. Program MW layout and initialize QP mappings + * for @qp_num. + * @entry_priv_alloc: Optional. Allocate backend-private per-entry data. + * The returned pointer is stored in entry->priv. + * @entry_priv_free: Optional. Free per-entry private data allocated by + * @entry_priv_alloc. + * @tx_free_entry: Required. Return the number of free TX entries available + * for enqueue on @qp. + * @tx_enqueue: Required. Backend-specific implementation of + * ntb_transport_tx_enqueue(). + * @rx_enqueue: Required. Backend-specific implementation of + * ntb_transport_rx_enqueue(). + * @rx_poll: Required. Poll RX completions and/or push newly posted + * RX buffers. + * @debugfs_stats_show: Required. Emit backend-specific per-QP stats into @s. + */ +struct ntb_transport_backend_ops { + int (*enable)(struct ntb_transport_ctx *nt, unsigned int *mw_count); + void (*disable)(struct ntb_transport_ctx *nt); + int (*qp_init)(struct ntb_transport_ctx *nt, unsigned int qp_num); + void (*qp_free)(struct ntb_transport_qp *qp); + int (*link_up_pre)(struct ntb_transport_ctx *nt); + int (*link_up_post)(struct ntb_transport_ctx *nt); + void (*link_down)(struct ntb_transport_ctx *nt); + int (*setup_qp_mw)(struct ntb_transport_ctx *nt, unsigned int qp_num); + void *(*entry_priv_alloc)(void); + void (*entry_priv_free)(void *priv); + unsigned int (*tx_free_entry)(struct ntb_transport_qp *qp); + int (*tx_enqueue)(struct ntb_transport_qp *qp, + struct ntb_queue_entry *entry, + void *cb, void *data, unsigned int len, + unsigned int flags); + int (*rx_enqueue)(struct ntb_transport_qp *qp, + struct ntb_queue_entry *entry); + void (*rx_poll)(struct ntb_transport_qp *qp); + void (*debugfs_stats_show)(struct seq_file *s, + struct ntb_transport_qp *qp); +}; + +struct ntb_transport_backend { + const char *name; + const struct ntb_transport_backend_ops *ops; + struct module *owner; + struct list_head node; +}; + struct ntb_transport_ctx { struct list_head entry; struct list_head client_devs; struct ntb_dev *ndev; + struct ntb_transport_backend *backend; + struct ntb_transport_mw *mw_vec; struct ntb_transport_qp *qp_vec; unsigned int mw_count; @@ -157,6 +225,9 @@ struct ntb_transport_ctx { /* Make sure workq of link event be executed serially */ struct mutex link_event_lock; + + /* Backend-specific context */ + void *priv; }; enum { @@ -169,7 +240,16 @@ void ntb_list_add(spinlock_t *lock, struct list_head *entry, struct ntb_queue_entry *ntb_list_rm(spinlock_t *lock, struct list_head *list); struct ntb_queue_entry *ntb_list_mv(spinlock_t *lock, struct list_head *list, struct list_head *to_list); +struct ntb_queue_entry *ntb_queue_entry_alloc(struct ntb_transport_ctx *nt, + struct ntb_transport_qp *qp, + int node); void ntb_qp_link_down(struct ntb_transport_qp *qp); +int ntb_transport_init_queue(struct ntb_transport_ctx *nt, + unsigned int qp_num); + +int ntb_transport_backend_register(struct ntb_transport_backend *b); +void ntb_transport_backend_unregister(struct ntb_transport_backend *b); + int ntb_transport_attach(struct ntb_dev *ndev, const char *backend_name, bool use_msi, unsigned long max_mw_size, unsigned int transport_mtu, -- 2.51.0
