|
@@ -119,7 +119,8 @@ struct ntb_transport_qp {
|
|
|
struct ntb_transport_ctx *transport;
|
|
|
struct ntb_dev *ndev;
|
|
|
void *cb_data;
|
|
|
- struct dma_chan *dma_chan;
|
|
|
+ struct dma_chan *tx_dma_chan;
|
|
|
+ struct dma_chan *rx_dma_chan;
|
|
|
|
|
|
bool client_ready;
|
|
|
bool link_is_up;
|
|
@@ -297,7 +298,7 @@ static LIST_HEAD(ntb_transport_list);
|
|
|
|
|
|
static int ntb_bus_init(struct ntb_transport_ctx *nt)
|
|
|
{
|
|
|
- list_add(&nt->entry, &ntb_transport_list);
|
|
|
+ list_add_tail(&nt->entry, &ntb_transport_list);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -452,7 +453,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
|
|
|
|
|
|
out_offset = 0;
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "NTB QP stats\n");
|
|
|
+ "\nNTB QP stats:\n\n");
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"rx_bytes - \t%llu\n", qp->rx_bytes);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
@@ -470,11 +471,11 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"rx_err_ver - \t%llu\n", qp->rx_err_ver);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "rx_buff - \t%p\n", qp->rx_buff);
|
|
|
+ "rx_buff - \t0x%p\n", qp->rx_buff);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"rx_index - \t%u\n", qp->rx_index);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "rx_max_entry - \t%u\n", qp->rx_max_entry);
|
|
|
+ "rx_max_entry - \t%u\n\n", qp->rx_max_entry);
|
|
|
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"tx_bytes - \t%llu\n", qp->tx_bytes);
|
|
@@ -489,15 +490,32 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"tx_err_no_buf - %llu\n", qp->tx_err_no_buf);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "tx_mw - \t%p\n", qp->tx_mw);
|
|
|
+ "tx_mw - \t0x%p\n", qp->tx_mw);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "tx_index - \t%u\n", qp->tx_index);
|
|
|
+ "tx_index (H) - \t%u\n", qp->tx_index);
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "RRI (T) - \t%u\n",
|
|
|
+ qp->remote_rx_info->entry);
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
"tx_max_entry - \t%u\n", qp->tx_max_entry);
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "free tx - \t%u\n",
|
|
|
+ ntb_transport_tx_free_entry(qp));
|
|
|
|
|
|
out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
- "\nQP Link %s\n",
|
|
|
+ "\n");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "Using TX DMA - \t%s\n",
|
|
|
+ qp->tx_dma_chan ? "Yes" : "No");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "Using RX DMA - \t%s\n",
|
|
|
+ qp->rx_dma_chan ? "Yes" : "No");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "QP Link - \t%s\n",
|
|
|
qp->link_is_up ? "Up" : "Down");
|
|
|
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
|
|
|
+ "\n");
|
|
|
+
|
|
|
if (out_offset > out_count)
|
|
|
out_offset = out_count;
|
|
|
|
|
@@ -535,6 +553,7 @@ static struct ntb_queue_entry *ntb_list_rm(spinlock_t *lock,
|
|
|
}
|
|
|
entry = list_first_entry(list, struct ntb_queue_entry, entry);
|
|
|
list_del(&entry->entry);
|
|
|
+
|
|
|
out:
|
|
|
spin_unlock_irqrestore(lock, flags);
|
|
|
|
|
@@ -1206,7 +1225,7 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
|
|
|
{
|
|
|
struct dma_async_tx_descriptor *txd;
|
|
|
struct ntb_transport_qp *qp = entry->qp;
|
|
|
- struct dma_chan *chan = qp->dma_chan;
|
|
|
+ struct dma_chan *chan = qp->rx_dma_chan;
|
|
|
struct dma_device *device;
|
|
|
size_t pay_off, buff_off, len;
|
|
|
struct dmaengine_unmap_data *unmap;
|
|
@@ -1219,18 +1238,18 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset)
|
|
|
goto err;
|
|
|
|
|
|
if (len < copy_bytes)
|
|
|
- goto err_wait;
|
|
|
+ goto err;
|
|
|
|
|
|
device = chan->device;
|
|
|
pay_off = (size_t)offset & ~PAGE_MASK;
|
|
|
buff_off = (size_t)buf & ~PAGE_MASK;
|
|
|
|
|
|
if (!is_dma_copy_aligned(device, pay_off, buff_off, len))
|
|
|
- goto err_wait;
|
|
|
+ goto err;
|
|
|
|
|
|
unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOWAIT);
|
|
|
if (!unmap)
|
|
|
- goto err_wait;
|
|
|
+ goto err;
|
|
|
|
|
|
unmap->len = len;
|
|
|
unmap->addr[0] = dma_map_page(device->dev, virt_to_page(offset),
|
|
@@ -1273,12 +1292,6 @@ err_set_unmap:
|
|
|
dmaengine_unmap_put(unmap);
|
|
|
err_get_unmap:
|
|
|
dmaengine_unmap_put(unmap);
|
|
|
-err_wait:
|
|
|
- /* If the callbacks come out of order, the writing of the index to the
|
|
|
- * last completed will be out of order. This may result in the
|
|
|
- * receive stalling forever.
|
|
|
- */
|
|
|
- dma_sync_wait(chan, qp->last_cookie);
|
|
|
err:
|
|
|
ntb_memcpy_rx(entry, offset);
|
|
|
qp->rx_memcpy++;
|
|
@@ -1373,8 +1386,8 @@ static void ntb_transport_rxc_db(unsigned long data)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (i && qp->dma_chan)
|
|
|
- dma_async_issue_pending(qp->dma_chan);
|
|
|
+ if (i && qp->rx_dma_chan)
|
|
|
+ dma_async_issue_pending(qp->rx_dma_chan);
|
|
|
|
|
|
if (i == qp->rx_max_entry) {
|
|
|
/* there is more work to do */
|
|
@@ -1441,7 +1454,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp,
|
|
|
{
|
|
|
struct ntb_payload_header __iomem *hdr;
|
|
|
struct dma_async_tx_descriptor *txd;
|
|
|
- struct dma_chan *chan = qp->dma_chan;
|
|
|
+ struct dma_chan *chan = qp->tx_dma_chan;
|
|
|
struct dma_device *device;
|
|
|
size_t dest_off, buff_off;
|
|
|
struct dmaengine_unmap_data *unmap;
|
|
@@ -1634,14 +1647,27 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
|
|
|
dma_cap_set(DMA_MEMCPY, dma_mask);
|
|
|
|
|
|
if (use_dma) {
|
|
|
- qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn,
|
|
|
- (void *)(unsigned long)node);
|
|
|
- if (!qp->dma_chan)
|
|
|
- dev_info(&pdev->dev, "Unable to allocate DMA channel\n");
|
|
|
+ qp->tx_dma_chan =
|
|
|
+ dma_request_channel(dma_mask, ntb_dma_filter_fn,
|
|
|
+ (void *)(unsigned long)node);
|
|
|
+ if (!qp->tx_dma_chan)
|
|
|
+ dev_info(&pdev->dev, "Unable to allocate TX DMA channel\n");
|
|
|
+
|
|
|
+ qp->rx_dma_chan =
|
|
|
+ dma_request_channel(dma_mask, ntb_dma_filter_fn,
|
|
|
+ (void *)(unsigned long)node);
|
|
|
+ if (!qp->rx_dma_chan)
|
|
|
+ dev_info(&pdev->dev, "Unable to allocate RX DMA channel\n");
|
|
|
} else {
|
|
|
- qp->dma_chan = NULL;
|
|
|
+ qp->tx_dma_chan = NULL;
|
|
|
+ qp->rx_dma_chan = NULL;
|
|
|
}
|
|
|
- dev_dbg(&pdev->dev, "Using %s memcpy\n", qp->dma_chan ? "DMA" : "CPU");
|
|
|
+
|
|
|
+ dev_dbg(&pdev->dev, "Using %s memcpy for TX\n",
|
|
|
+ qp->tx_dma_chan ? "DMA" : "CPU");
|
|
|
+
|
|
|
+ dev_dbg(&pdev->dev, "Using %s memcpy for RX\n",
|
|
|
+ qp->rx_dma_chan ? "DMA" : "CPU");
|
|
|
|
|
|
for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
|
|
|
entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node);
|
|
@@ -1676,8 +1702,10 @@ err2:
|
|
|
err1:
|
|
|
while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q)))
|
|
|
kfree(entry);
|
|
|
- if (qp->dma_chan)
|
|
|
- dma_release_channel(qp->dma_chan);
|
|
|
+ if (qp->tx_dma_chan)
|
|
|
+ dma_release_channel(qp->tx_dma_chan);
|
|
|
+ if (qp->rx_dma_chan)
|
|
|
+ dma_release_channel(qp->rx_dma_chan);
|
|
|
nt->qp_bitmap_free |= qp_bit;
|
|
|
err:
|
|
|
return NULL;
|
|
@@ -1701,12 +1729,27 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
|
|
|
|
|
|
pdev = qp->ndev->pdev;
|
|
|
|
|
|
- if (qp->dma_chan) {
|
|
|
- struct dma_chan *chan = qp->dma_chan;
|
|
|
+ if (qp->tx_dma_chan) {
|
|
|
+ struct dma_chan *chan = qp->tx_dma_chan;
|
|
|
+ /* Putting the dma_chan to NULL will force any new traffic to be
|
|
|
+ * processed by the CPU instead of the DAM engine
|
|
|
+ */
|
|
|
+ qp->tx_dma_chan = NULL;
|
|
|
+
|
|
|
+ /* Try to be nice and wait for any queued DMA engine
|
|
|
+ * transactions to process before smashing it with a rock
|
|
|
+ */
|
|
|
+ dma_sync_wait(chan, qp->last_cookie);
|
|
|
+ dmaengine_terminate_all(chan);
|
|
|
+ dma_release_channel(chan);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (qp->rx_dma_chan) {
|
|
|
+ struct dma_chan *chan = qp->rx_dma_chan;
|
|
|
/* Putting the dma_chan to NULL will force any new traffic to be
|
|
|
* processed by the CPU instead of the DAM engine
|
|
|
*/
|
|
|
- qp->dma_chan = NULL;
|
|
|
+ qp->rx_dma_chan = NULL;
|
|
|
|
|
|
/* Try to be nice and wait for any queued DMA engine
|
|
|
* transactions to process before smashing it with a rock
|
|
@@ -1843,7 +1886,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
|
|
|
entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
|
|
|
if (!entry) {
|
|
|
qp->tx_err_no_buf++;
|
|
|
- return -ENOMEM;
|
|
|
+ return -EBUSY;
|
|
|
}
|
|
|
|
|
|
entry->cb_data = cb;
|
|
@@ -1954,21 +1997,34 @@ EXPORT_SYMBOL_GPL(ntb_transport_qp_num);
|
|
|
unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
|
|
|
{
|
|
|
unsigned int max;
|
|
|
+ unsigned int copy_align;
|
|
|
|
|
|
if (!qp)
|
|
|
return 0;
|
|
|
|
|
|
- if (!qp->dma_chan)
|
|
|
+ if (!qp->tx_dma_chan && !qp->rx_dma_chan)
|
|
|
return qp->tx_max_frame - sizeof(struct ntb_payload_header);
|
|
|
|
|
|
+ copy_align = max(qp->tx_dma_chan->device->copy_align,
|
|
|
+ qp->rx_dma_chan->device->copy_align);
|
|
|
+
|
|
|
/* If DMA engine usage is possible, try to find the max size for that */
|
|
|
max = qp->tx_max_frame - sizeof(struct ntb_payload_header);
|
|
|
- max -= max % (1 << qp->dma_chan->device->copy_align);
|
|
|
+ max -= max % (1 << copy_align);
|
|
|
|
|
|
return max;
|
|
|
}
|
|
|
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;
|
|
|
+
|
|
|
+ return tail > head ? tail - head : qp->tx_max_entry + tail - head;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(ntb_transport_tx_free_entry);
|
|
|
+
|
|
|
static void ntb_transport_doorbell_callback(void *data, int vector)
|
|
|
{
|
|
|
struct ntb_transport_ctx *nt = data;
|