Skip to content

Commit d101564

Browse files
sowminivdavem330
authored andcommitted
sunvnet: Avoid sending superfluous LDC messages.
When sending out a burst of packets across multiple descriptors, it is sufficient to send one LDC "start" trigger for the first descriptor, so do not send an LDC "start" for every pass through vnet_start_xmit. Similarly, it is sufficient to send one "DRING_STOPPED" trigger for the last dring (and if that fails, hold off and send the trigger later). Optimizations to the number of LDC messages helps avoid filling up the LDC channel with superfluous LDC messages that risk triggering flow-control on the channel, and also boosts performance. Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Acked-by: Raghuram Kothakota <raghuram.kothakota@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent c706471 commit d101564

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

drivers/net/ethernet/sun/sunvnet.c

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ MODULE_VERSION(DRV_MODULE_VERSION);
3737
*/
3838
#define VNET_MAX_RETRIES 10
3939

40+
static int __vnet_tx_trigger(struct vnet_port *port, u32 start);
41+
4042
/* Ordered from largest major to lowest */
4143
static struct vio_version vnet_versions[] = {
4244
{ .major = 1, .minor = 0 },
@@ -283,10 +285,18 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
283285
port->raddr[0], port->raddr[1],
284286
port->raddr[2], port->raddr[3],
285287
port->raddr[4], port->raddr[5]);
286-
err = -ECONNRESET;
288+
break;
287289
}
288290
} while (err == -EAGAIN);
289291

292+
if (err <= 0 && vio_dring_state == VIO_DRING_STOPPED) {
293+
port->stop_rx_idx = end;
294+
port->stop_rx = true;
295+
} else {
296+
port->stop_rx_idx = 0;
297+
port->stop_rx = false;
298+
}
299+
290300
return err;
291301
}
292302

@@ -448,15 +458,32 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf)
448458
struct net_device *dev;
449459
struct vnet *vp;
450460
u32 end;
451-
461+
struct vio_net_desc *desc;
452462
if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
453463
return 0;
454464

455465
end = pkt->end_idx;
456466
if (unlikely(!idx_is_pending(dr, end)))
457467
return 0;
458468

469+
/* sync for race conditions with vnet_start_xmit() and tell xmit it
470+
* is time to send a trigger.
471+
*/
459472
dr->cons = next_idx(end, dr);
473+
desc = vio_dring_entry(dr, dr->cons);
474+
if (desc->hdr.state == VIO_DESC_READY && port->start_cons) {
475+
/* vnet_start_xmit() just populated this dring but missed
476+
* sending the "start" LDC message to the consumer.
477+
* Send a "start" trigger on its behalf.
478+
*/
479+
if (__vnet_tx_trigger(port, dr->cons) > 0)
480+
port->start_cons = false;
481+
else
482+
port->start_cons = true;
483+
} else {
484+
port->start_cons = true;
485+
}
486+
460487

461488
vp = port->vp;
462489
dev = vp->dev;
@@ -597,7 +624,7 @@ static void vnet_event(void *arg, int event)
597624
local_irq_restore(flags);
598625
}
599626

600-
static int __vnet_tx_trigger(struct vnet_port *port)
627+
static int __vnet_tx_trigger(struct vnet_port *port, u32 start)
601628
{
602629
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
603630
struct vio_dring_data hdr = {
@@ -608,12 +635,21 @@ static int __vnet_tx_trigger(struct vnet_port *port)
608635
.sid = vio_send_sid(&port->vio),
609636
},
610637
.dring_ident = dr->ident,
611-
.start_idx = dr->prod,
638+
.start_idx = start,
612639
.end_idx = (u32) -1,
613640
};
614641
int err, delay;
615642
int retries = 0;
616643

644+
if (port->stop_rx) {
645+
err = vnet_send_ack(port,
646+
&port->vio.drings[VIO_DRIVER_RX_RING],
647+
port->stop_rx_idx, -1,
648+
VIO_DRING_STOPPED);
649+
if (err <= 0)
650+
return err;
651+
}
652+
617653
hdr.seq = dr->snd_nxt;
618654
delay = 1;
619655
do {
@@ -734,14 +770,40 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
734770

735771
d->hdr.state = VIO_DESC_READY;
736772

737-
err = __vnet_tx_trigger(port);
773+
/* Exactly one ldc "start" trigger (for dr->cons) needs to be sent
774+
* to notify the consumer that some descriptors are READY.
775+
* After that "start" trigger, no additional triggers are needed until
776+
* a DRING_STOPPED is received from the consumer. The dr->cons field
777+
* (set up by vnet_ack()) has the value of the next dring index
778+
* that has not yet been ack-ed. We send a "start" trigger here
779+
* if, and only if, start_cons is true (reset it afterward). Conversely,
780+
* vnet_ack() should check if the dring corresponding to cons
781+
* is marked READY, but start_cons was false.
782+
* If so, vnet_ack() should send out the missed "start" trigger.
783+
*
784+
* Note that the wmb() above makes sure the cookies et al. are
785+
* not globally visible before the VIO_DESC_READY, and that the
786+
* stores are ordered correctly by the compiler. The consumer will
787+
* not proceed until the VIO_DESC_READY is visible assuring that
788+
* the consumer does not observe anything related to descriptors
789+
* out of order. The HV trap from the LDC start trigger is the
790+
* producer to consumer announcement that work is available to the
791+
* consumer
792+
*/
793+
if (!port->start_cons)
794+
goto ldc_start_done; /* previous trigger suffices */
795+
796+
err = __vnet_tx_trigger(port, dr->cons);
738797
if (unlikely(err < 0)) {
739798
netdev_info(dev, "TX trigger error %d\n", err);
740799
d->hdr.state = VIO_DESC_FREE;
741800
dev->stats.tx_carrier_errors++;
742801
goto out_dropped_unlock;
743802
}
744803

804+
ldc_start_done:
805+
port->start_cons = false;
806+
745807
dev->stats.tx_packets++;
746808
dev->stats.tx_bytes += skb->len;
747809

@@ -1035,6 +1097,7 @@ static int vnet_port_alloc_tx_bufs(struct vnet_port *port)
10351097
(sizeof(struct ldc_trans_cookie) * 2));
10361098
dr->num_entries = VNET_TX_RING_SIZE;
10371099
dr->prod = dr->cons = 0;
1100+
port->start_cons = true; /* need an initial trigger */
10381101
dr->pending = VNET_TX_RING_SIZE;
10391102
dr->ncookies = ncookies;
10401103

drivers/net/ethernet/sun/sunvnet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ struct vnet_port {
4040
struct vnet_tx_entry tx_bufs[VNET_TX_RING_SIZE];
4141

4242
struct list_head list;
43+
44+
u32 stop_rx_idx;
45+
bool stop_rx;
46+
bool start_cons;
4347
};
4448

4549
static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)

0 commit comments

Comments
 (0)