Skip to content

Commit e74bfee

Browse files
davejiangjonmason
authored andcommitted
NTB: Add flow control to the ntb_netdev
Right now if we push the NTB really hard, we start dropping packets due to not able to process the packets fast enough. We need to st:qop the upper layer from flooding us when that happens. A timer is necessary in order to restart the queue once the resource has been processed on the receive side. Due to the way NTB is setup, the resources on the tx side are tied to the processing of the rx side and there's no async way to know when the rx side has released those resources. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Jon Mason <jdmason@kudzu.us>
1 parent 5e9fd73 commit e74bfee

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

drivers/net/ntb_netdev.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,21 @@ MODULE_VERSION(NTB_NETDEV_VER);
6161
MODULE_LICENSE("Dual BSD/GPL");
6262
MODULE_AUTHOR("Intel Corporation");
6363

64+
/* Time in usecs for tx resource reaper */
65+
static unsigned int tx_time = 1;
66+
67+
/* Number of descriptors to free before resuming tx */
68+
static unsigned int tx_start = 10;
69+
70+
/* Number of descriptors still available before stop upper layer tx */
71+
static unsigned int tx_stop = 5;
72+
6473
struct ntb_netdev {
6574
struct list_head list;
6675
struct pci_dev *pdev;
6776
struct net_device *ndev;
6877
struct ntb_transport_qp *qp;
78+
struct timer_list tx_timer;
6979
};
7080

7181
#define NTB_TX_TIMEOUT_MS 1000
@@ -136,11 +146,42 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
136146
}
137147
}
138148

149+
static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,
150+
struct ntb_transport_qp *qp, int size)
151+
{
152+
struct ntb_netdev *dev = netdev_priv(netdev);
153+
154+
netif_stop_queue(netdev);
155+
/* Make sure to see the latest value of ntb_transport_tx_free_entry()
156+
* since the queue was last started.
157+
*/
158+
smp_mb();
159+
160+
if (likely(ntb_transport_tx_free_entry(qp) < size)) {
161+
mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
162+
return -EBUSY;
163+
}
164+
165+
netif_start_queue(netdev);
166+
return 0;
167+
}
168+
169+
static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,
170+
struct ntb_transport_qp *qp, int size)
171+
{
172+
if (netif_queue_stopped(ndev) ||
173+
(ntb_transport_tx_free_entry(qp) >= size))
174+
return 0;
175+
176+
return __ntb_netdev_maybe_stop_tx(ndev, qp, size);
177+
}
178+
139179
static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
140180
void *data, int len)
141181
{
142182
struct net_device *ndev = qp_data;
143183
struct sk_buff *skb;
184+
struct ntb_netdev *dev = netdev_priv(ndev);
144185

145186
skb = data;
146187
if (!skb || !ndev)
@@ -155,6 +196,15 @@ static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
155196
}
156197

157198
dev_kfree_skb(skb);
199+
200+
if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {
201+
/* Make sure anybody stopping the queue after this sees the new
202+
* value of ntb_transport_tx_free_entry()
203+
*/
204+
smp_mb();
205+
if (netif_queue_stopped(ndev))
206+
netif_wake_queue(ndev);
207+
}
158208
}
159209

160210
static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
@@ -163,10 +213,15 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
163213
struct ntb_netdev *dev = netdev_priv(ndev);
164214
int rc;
165215

216+
ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
217+
166218
rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
167219
if (rc)
168220
goto err;
169221

222+
/* check for next submit */
223+
ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
224+
170225
return NETDEV_TX_OK;
171226

172227
err:
@@ -175,6 +230,23 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
175230
return NETDEV_TX_BUSY;
176231
}
177232

233+
static void ntb_netdev_tx_timer(unsigned long data)
234+
{
235+
struct net_device *ndev = (struct net_device *)data;
236+
struct ntb_netdev *dev = netdev_priv(ndev);
237+
238+
if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
239+
mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time));
240+
} else {
241+
/* Make sure anybody stopping the queue after this sees the new
242+
* value of ntb_transport_tx_free_entry()
243+
*/
244+
smp_mb();
245+
if (netif_queue_stopped(ndev))
246+
netif_wake_queue(ndev);
247+
}
248+
}
249+
178250
static int ntb_netdev_open(struct net_device *ndev)
179251
{
180252
struct ntb_netdev *dev = netdev_priv(ndev);
@@ -197,8 +269,11 @@ static int ntb_netdev_open(struct net_device *ndev)
197269
}
198270
}
199271

272+
setup_timer(&dev->tx_timer, ntb_netdev_tx_timer, (unsigned long)ndev);
273+
200274
netif_carrier_off(ndev);
201275
ntb_transport_link_up(dev->qp);
276+
netif_start_queue(ndev);
202277

203278
return 0;
204279

@@ -219,6 +294,8 @@ static int ntb_netdev_close(struct net_device *ndev)
219294
while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
220295
dev_kfree_skb(skb);
221296

297+
del_timer_sync(&dev->tx_timer);
298+
222299
return 0;
223300
}
224301

drivers/ntb/ntb_transport.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,12 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
494494
"tx_index - \t%u\n", qp->tx_index);
495495
out_offset += snprintf(buf + out_offset, out_count - out_offset,
496496
"tx_max_entry - \t%u\n", qp->tx_max_entry);
497+
out_offset += snprintf(buf + out_offset, out_count - out_offset,
498+
"qp->remote_rx_info->entry - \t%u\n",
499+
qp->remote_rx_info->entry);
500+
out_offset += snprintf(buf + out_offset, out_count - out_offset,
501+
"free tx - \t%u\n",
502+
ntb_transport_tx_free_entry(qp));
497503

498504
out_offset += snprintf(buf + out_offset, out_count - out_offset,
499505
"\nQP Link %s\n",
@@ -535,6 +541,7 @@ static struct ntb_queue_entry *ntb_list_rm(spinlock_t *lock,
535541
}
536542
entry = list_first_entry(list, struct ntb_queue_entry, entry);
537543
list_del(&entry->entry);
544+
538545
out:
539546
spin_unlock_irqrestore(lock, flags);
540547

@@ -1843,7 +1850,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
18431850
entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
18441851
if (!entry) {
18451852
qp->tx_err_no_buf++;
1846-
return -ENOMEM;
1853+
return -EBUSY;
18471854
}
18481855

18491856
entry->cb_data = cb;
@@ -1969,6 +1976,15 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
19691976
}
19701977
EXPORT_SYMBOL_GPL(ntb_transport_max_size);
19711978

1979+
unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp)
1980+
{
1981+
unsigned int head = qp->tx_index;
1982+
unsigned int tail = qp->remote_rx_info->entry;
1983+
1984+
return tail > head ? tail - head : qp->tx_max_entry + tail - head;
1985+
}
1986+
EXPORT_SYMBOL_GPL(ntb_transport_tx_free_entry);
1987+
19721988
static void ntb_transport_doorbell_callback(void *data, int vector)
19731989
{
19741990
struct ntb_transport_ctx *nt = data;

include/linux/ntb_transport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,4 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len);
8383
void ntb_transport_link_up(struct ntb_transport_qp *qp);
8484
void ntb_transport_link_down(struct ntb_transport_qp *qp);
8585
bool ntb_transport_link_query(struct ntb_transport_qp *qp);
86+
unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp);

0 commit comments

Comments
 (0)