|
@@ -1,7 +1,7 @@
|
|
/* sunvnet.c: Sun LDOM Virtual Network Driver.
|
|
/* sunvnet.c: Sun LDOM Virtual Network Driver.
|
|
*
|
|
*
|
|
* Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
|
|
* Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
|
|
- * Copyright (C) 2016 Oracle. All rights reserved.
|
|
|
|
|
|
+ * Copyright (C) 2016-2017 Oracle. All rights reserved.
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
@@ -43,7 +43,6 @@ MODULE_LICENSE("GPL");
|
|
MODULE_VERSION("1.1");
|
|
MODULE_VERSION("1.1");
|
|
|
|
|
|
static int __vnet_tx_trigger(struct vnet_port *port, u32 start);
|
|
static int __vnet_tx_trigger(struct vnet_port *port, u32 start);
|
|
-static void vnet_port_reset(struct vnet_port *port);
|
|
|
|
|
|
|
|
static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr)
|
|
static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr)
|
|
{
|
|
{
|
|
@@ -410,8 +409,12 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc)
|
|
|
|
|
|
skb->ip_summed = port->switch_port ? CHECKSUM_NONE : CHECKSUM_PARTIAL;
|
|
skb->ip_summed = port->switch_port ? CHECKSUM_NONE : CHECKSUM_PARTIAL;
|
|
|
|
|
|
|
|
+ if (unlikely(is_multicast_ether_addr(eth_hdr(skb)->h_dest)))
|
|
|
|
+ dev->stats.multicast++;
|
|
dev->stats.rx_packets++;
|
|
dev->stats.rx_packets++;
|
|
dev->stats.rx_bytes += len;
|
|
dev->stats.rx_bytes += len;
|
|
|
|
+ port->stats.rx_packets++;
|
|
|
|
+ port->stats.rx_bytes += len;
|
|
napi_gro_receive(&port->napi, skb);
|
|
napi_gro_receive(&port->napi, skb);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -747,6 +750,13 @@ static int vnet_event_napi(struct vnet_port *port, int budget)
|
|
|
|
|
|
/* RESET takes precedent over any other event */
|
|
/* RESET takes precedent over any other event */
|
|
if (port->rx_event & LDC_EVENT_RESET) {
|
|
if (port->rx_event & LDC_EVENT_RESET) {
|
|
|
|
+ /* a link went down */
|
|
|
|
+
|
|
|
|
+ if (port->vsw == 1) {
|
|
|
|
+ netif_tx_stop_all_queues(dev);
|
|
|
|
+ netif_carrier_off(dev);
|
|
|
|
+ }
|
|
|
|
+
|
|
vio_link_state_change(vio, LDC_EVENT_RESET);
|
|
vio_link_state_change(vio, LDC_EVENT_RESET);
|
|
vnet_port_reset(port);
|
|
vnet_port_reset(port);
|
|
vio_port_up(vio);
|
|
vio_port_up(vio);
|
|
@@ -762,12 +772,21 @@ static int vnet_event_napi(struct vnet_port *port, int budget)
|
|
maybe_tx_wakeup(port);
|
|
maybe_tx_wakeup(port);
|
|
|
|
|
|
port->rx_event = 0;
|
|
port->rx_event = 0;
|
|
|
|
+ port->stats.event_reset++;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if (port->rx_event & LDC_EVENT_UP) {
|
|
if (port->rx_event & LDC_EVENT_UP) {
|
|
|
|
+ /* a link came up */
|
|
|
|
+
|
|
|
|
+ if (port->vsw == 1) {
|
|
|
|
+ netif_carrier_on(port->dev);
|
|
|
|
+ netif_tx_start_all_queues(port->dev);
|
|
|
|
+ }
|
|
|
|
+
|
|
vio_link_state_change(vio, LDC_EVENT_UP);
|
|
vio_link_state_change(vio, LDC_EVENT_UP);
|
|
port->rx_event = 0;
|
|
port->rx_event = 0;
|
|
|
|
+ port->stats.event_up++;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1417,6 +1436,8 @@ ldc_start_done:
|
|
|
|
|
|
dev->stats.tx_packets++;
|
|
dev->stats.tx_packets++;
|
|
dev->stats.tx_bytes += port->tx_bufs[txi].skb->len;
|
|
dev->stats.tx_bytes += port->tx_bufs[txi].skb->len;
|
|
|
|
+ port->stats.tx_packets++;
|
|
|
|
+ port->stats.tx_bytes += port->tx_bufs[txi].skb->len;
|
|
|
|
|
|
dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
|
|
dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
|
|
if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
|
|
if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
|
|
@@ -1631,7 +1652,7 @@ void sunvnet_port_free_tx_bufs_common(struct vnet_port *port)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_free_tx_bufs_common);
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_free_tx_bufs_common);
|
|
|
|
|
|
-static void vnet_port_reset(struct vnet_port *port)
|
|
|
|
|
|
+void vnet_port_reset(struct vnet_port *port)
|
|
{
|
|
{
|
|
del_timer(&port->clean_timer);
|
|
del_timer(&port->clean_timer);
|
|
sunvnet_port_free_tx_bufs_common(port);
|
|
sunvnet_port_free_tx_bufs_common(port);
|
|
@@ -1639,6 +1660,7 @@ static void vnet_port_reset(struct vnet_port *port)
|
|
port->tso = (port->vsw == 0); /* no tso in vsw, misbehaves in bridge */
|
|
port->tso = (port->vsw == 0); /* no tso in vsw, misbehaves in bridge */
|
|
port->tsolen = 0;
|
|
port->tsolen = 0;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(vnet_port_reset);
|
|
|
|
|
|
static int vnet_port_alloc_tx_ring(struct vnet_port *port)
|
|
static int vnet_port_alloc_tx_ring(struct vnet_port *port)
|
|
{
|
|
{
|
|
@@ -1708,20 +1730,32 @@ EXPORT_SYMBOL_GPL(sunvnet_poll_controller_common);
|
|
void sunvnet_port_add_txq_common(struct vnet_port *port)
|
|
void sunvnet_port_add_txq_common(struct vnet_port *port)
|
|
{
|
|
{
|
|
struct vnet *vp = port->vp;
|
|
struct vnet *vp = port->vp;
|
|
- int n;
|
|
|
|
|
|
+ int smallest = 0;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ /* find the first least-used q
|
|
|
|
+ * When there are more ldoms than q's, we start to
|
|
|
|
+ * double up on ports per queue.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < VNET_MAX_TXQS; i++) {
|
|
|
|
+ if (vp->q_used[i] == 0) {
|
|
|
|
+ smallest = i;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (vp->q_used[i] < vp->q_used[smallest])
|
|
|
|
+ smallest = i;
|
|
|
|
+ }
|
|
|
|
|
|
- n = vp->nports++;
|
|
|
|
- n = n & (VNET_MAX_TXQS - 1);
|
|
|
|
- port->q_index = n;
|
|
|
|
- netif_tx_wake_queue(netdev_get_tx_queue(VNET_PORT_TO_NET_DEVICE(port),
|
|
|
|
- port->q_index));
|
|
|
|
|
|
+ vp->nports++;
|
|
|
|
+ vp->q_used[smallest]++;
|
|
|
|
+ port->q_index = smallest;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_add_txq_common);
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_add_txq_common);
|
|
|
|
|
|
void sunvnet_port_rm_txq_common(struct vnet_port *port)
|
|
void sunvnet_port_rm_txq_common(struct vnet_port *port)
|
|
{
|
|
{
|
|
port->vp->nports--;
|
|
port->vp->nports--;
|
|
- netif_tx_stop_queue(netdev_get_tx_queue(VNET_PORT_TO_NET_DEVICE(port),
|
|
|
|
- port->q_index));
|
|
|
|
|
|
+ port->vp->q_used[port->q_index]--;
|
|
|
|
+ port->q_index = 0;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_rm_txq_common);
|
|
EXPORT_SYMBOL_GPL(sunvnet_port_rm_txq_common);
|