Commit db316d57 authored by David S. Miller's avatar David S. Miller

Merge branch 'dsa-netconsole'

Florian Fainelli says:

====================
net: GENET, SYSTEMPORT and DSA netconsole

This patch series adds support for netconsole in the GENET, SYSTEMPORT and DSA
drivers.

A small refactoring to the DSA transmit path is required to avoid duplicating
the dsa_netpoll_send_skb() into each and every tagging protocol supported.

Testing on e.g: mv643xx_eth and/or e1000e would be much appreciated!

Changes in v2:

- properly disable/enable interrupts in GENET and SYSTEMPORT

- pass the reallocated SKB back to dsa_slave_xmit() in case a tag protocol had to
  alter the original SKB
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0f7bffd9 04ff53f9
...@@ -933,6 +933,21 @@ static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id) ...@@ -933,6 +933,21 @@ static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER
static void bcm_sysport_poll_controller(struct net_device *dev)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
disable_irq(priv->irq0);
bcm_sysport_rx_isr(priv->irq0, priv);
enable_irq(priv->irq0);
disable_irq(priv->irq1);
bcm_sysport_tx_isr(priv->irq1, priv);
enable_irq(priv->irq1);
}
#endif
static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
...@@ -1723,6 +1738,9 @@ static const struct net_device_ops bcm_sysport_netdev_ops = { ...@@ -1723,6 +1738,9 @@ static const struct net_device_ops bcm_sysport_netdev_ops = {
.ndo_set_features = bcm_sysport_set_features, .ndo_set_features = bcm_sysport_set_features,
.ndo_set_rx_mode = bcm_sysport_set_rx_mode, .ndo_set_rx_mode = bcm_sysport_set_rx_mode,
.ndo_set_mac_address = bcm_sysport_change_mac, .ndo_set_mac_address = bcm_sysport_change_mac,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = bcm_sysport_poll_controller,
#endif
}; };
#define REV_FMT "v%2x.%02x" #define REV_FMT "v%2x.%02x"
......
...@@ -2388,6 +2388,23 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) ...@@ -2388,6 +2388,23 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER
static void bcmgenet_poll_controller(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
/* Invoke the main RX/TX interrupt handler */
disable_irq(priv->irq0);
bcmgenet_isr0(priv->irq0, priv);
enable_irq(priv->irq0);
/* And the interrupt handler for RX/TX priority queues */
disable_irq(priv->irq1);
bcmgenet_isr1(priv->irq1, priv);
enable_irq(priv->irq1);
}
#endif
static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) static void bcmgenet_umac_reset(struct bcmgenet_priv *priv)
{ {
u32 reg; u32 reg;
...@@ -2939,6 +2956,9 @@ static const struct net_device_ops bcmgenet_netdev_ops = { ...@@ -2939,6 +2956,9 @@ static const struct net_device_ops bcmgenet_netdev_ops = {
.ndo_set_mac_address = bcmgenet_set_mac_addr, .ndo_set_mac_address = bcmgenet_set_mac_addr,
.ndo_do_ioctl = bcmgenet_ioctl, .ndo_do_ioctl = bcmgenet_ioctl,
.ndo_set_features = bcmgenet_set_features, .ndo_set_features = bcmgenet_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = bcmgenet_poll_controller,
#endif
}; };
/* Array of GENET hardware parameters/characteristics */ /* Array of GENET hardware parameters/characteristics */
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netpoll.h>
struct dsa_device_ops { struct dsa_device_ops {
netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev); struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
int (*rcv)(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev); struct packet_type *pt, struct net_device *orig_dev);
}; };
...@@ -26,7 +27,7 @@ struct dsa_slave_priv { ...@@ -26,7 +27,7 @@ struct dsa_slave_priv {
* switch port. * switch port.
*/ */
struct net_device *dev; struct net_device *dev;
netdev_tx_t (*xmit)(struct sk_buff *skb, struct sk_buff * (*xmit)(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
/* /*
...@@ -47,6 +48,9 @@ struct dsa_slave_priv { ...@@ -47,6 +48,9 @@ struct dsa_slave_priv {
int old_duplex; int old_duplex;
struct net_device *bridge_dev; struct net_device *bridge_dev;
#ifdef CONFIG_NET_POLL_CONTROLLER
struct netpoll *netpoll;
#endif
}; };
/* dsa.c */ /* dsa.c */
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <net/switchdev.h> #include <net/switchdev.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/netpoll.h>
#include "dsa_priv.h" #include "dsa_priv.h"
/* slave mii_bus handling ***************************************************/ /* slave mii_bus handling ***************************************************/
...@@ -418,24 +419,53 @@ static int dsa_slave_port_attr_get(struct net_device *dev, ...@@ -418,24 +419,53 @@ static int dsa_slave_port_attr_get(struct net_device *dev,
return 0; return 0;
} }
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p,
struct sk_buff *skb)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); #ifdef CONFIG_NET_POLL_CONTROLLER
if (p->netpoll)
return p->xmit(skb, dev); netpoll_send_skb(p->netpoll, skb);
#else
BUG();
#endif
return NETDEV_TX_OK;
} }
static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb, static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct sk_buff *nskb;
skb->dev = p->parent->dst->master_netdev; dev->stats.tx_packets++;
dev_queue_xmit(skb); dev->stats.tx_bytes += skb->len;
/* Transmit function may have to reallocate the original SKB */
nskb = p->xmit(skb, dev);
if (!nskb)
return NETDEV_TX_OK;
/* SKB for netpoll still need to be mangled with the protocol-specific
* tag to be successfully transmitted
*/
if (unlikely(netpoll_tx_running(dev)))
return dsa_netpoll_send_skb(p, nskb);
/* Queue the SKB for transmission on the parent interface, but
* do not modify its EtherType
*/
nskb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(nskb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb,
struct net_device *dev)
{
/* Just return the original SKB */
return skb;
}
/* ethtool operations *******************************************************/ /* ethtool operations *******************************************************/
static int static int
...@@ -665,6 +695,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e) ...@@ -665,6 +695,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
return ret; return ret;
} }
#ifdef CONFIG_NET_POLL_CONTROLLER
static int dsa_slave_netpoll_setup(struct net_device *dev,
struct netpoll_info *ni)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
struct net_device *master = ds->dst->master_netdev;
struct netpoll *netpoll;
int err = 0;
netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
if (!netpoll)
return -ENOMEM;
err = __netpoll_setup(netpoll, master);
if (err) {
kfree(netpoll);
goto out;
}
p->netpoll = netpoll;
out:
return err;
}
static void dsa_slave_netpoll_cleanup(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct netpoll *netpoll = p->netpoll;
if (!netpoll)
return;
p->netpoll = NULL;
__netpoll_free_async(netpoll);
}
static void dsa_slave_poll_controller(struct net_device *dev)
{
}
#endif
static const struct ethtool_ops dsa_slave_ethtool_ops = { static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_settings = dsa_slave_get_settings, .get_settings = dsa_slave_get_settings,
.set_settings = dsa_slave_set_settings, .set_settings = dsa_slave_set_settings,
...@@ -697,6 +770,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = { ...@@ -697,6 +770,11 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_fdb_dump = dsa_slave_fdb_dump, .ndo_fdb_dump = dsa_slave_fdb_dump,
.ndo_do_ioctl = dsa_slave_ioctl, .ndo_do_ioctl = dsa_slave_ioctl,
.ndo_get_iflink = dsa_slave_get_iflink, .ndo_get_iflink = dsa_slave_get_iflink,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_netpoll_setup = dsa_slave_netpoll_setup,
.ndo_netpoll_cleanup = dsa_slave_netpoll_cleanup,
.ndo_poll_controller = dsa_slave_poll_controller,
#endif
}; };
static const struct switchdev_ops dsa_slave_switchdev_ops = { static const struct switchdev_ops dsa_slave_switchdev_ops = {
......
...@@ -58,14 +58,11 @@ ...@@ -58,14 +58,11 @@
#define BRCM_EG_TC_MASK 0x7 #define BRCM_EG_TC_MASK 0x7
#define BRCM_EG_PID_MASK 0x1f #define BRCM_EG_PID_MASK 0x1f
static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
u8 *brcm_tag; u8 *brcm_tag;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
if (skb_cow_head(skb, BRCM_TAG_LEN) < 0) if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
goto out_free; goto out_free;
...@@ -87,17 +84,11 @@ static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -87,17 +84,11 @@ static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
brcm_tag[2] = BRCM_IG_DSTMAP2_MASK; brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK; brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
/* Queue the SKB for transmission on the parent interface, but return skb;
* do not modify its EtherType
*/
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
out_free: out_free:
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NULL;
} }
static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
......
...@@ -15,14 +15,11 @@ ...@@ -15,14 +15,11 @@
#define DSA_HLEN 4 #define DSA_HLEN 4
static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
u8 *dsa_header; u8 *dsa_header;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
/* /*
* Convert the outermost 802.1q tag to a DSA tag for tagged * Convert the outermost 802.1q tag to a DSA tag for tagged
* packets, or insert a DSA tag between the addresses and * packets, or insert a DSA tag between the addresses and
...@@ -63,14 +60,11 @@ static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -63,14 +60,11 @@ static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
dsa_header[3] = 0x00; dsa_header[3] = 0x00;
} }
skb->dev = p->parent->dst->master_netdev; return skb;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
out_free: out_free:
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NULL;
} }
static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
......
...@@ -16,14 +16,11 @@ ...@@ -16,14 +16,11 @@
#define DSA_HLEN 4 #define DSA_HLEN 4
#define EDSA_HLEN 8 #define EDSA_HLEN 8
static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
u8 *edsa_header; u8 *edsa_header;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
/* /*
* Convert the outermost 802.1q tag to a DSA tag and prepend * Convert the outermost 802.1q tag to a DSA tag and prepend
* a DSA ethertype field is the packet is tagged, or insert * a DSA ethertype field is the packet is tagged, or insert
...@@ -76,14 +73,11 @@ static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -76,14 +73,11 @@ static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
edsa_header[7] = 0x00; edsa_header[7] = 0x00;
} }
skb->dev = p->parent->dst->master_netdev; return skb;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
out_free: out_free:
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NULL;
} }
static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
......
...@@ -13,16 +13,13 @@ ...@@ -13,16 +13,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "dsa_priv.h" #include "dsa_priv.h"
static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct sk_buff *nskb; struct sk_buff *nskb;
int padlen; int padlen;
u8 *trailer; u8 *trailer;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
/* /*
* We have to make sure that the trailer ends up as the very * We have to make sure that the trailer ends up as the very
* last 4 bytes of the packet. This means that we have to pad * last 4 bytes of the packet. This means that we have to pad
...@@ -36,7 +33,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -36,7 +33,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC); nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC);
if (nskb == NULL) { if (nskb == NULL) {
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NULL;
} }
skb_reserve(nskb, NET_IP_ALIGN); skb_reserve(nskb, NET_IP_ALIGN);
...@@ -57,10 +54,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -57,10 +54,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
trailer[2] = 0x10; trailer[2] = 0x10;
trailer[3] = 0x00; trailer[3] = 0x00;
nskb->dev = p->parent->dst->master_netdev; return nskb;
dev_queue_xmit(nskb);
return NETDEV_TX_OK;
} }
static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment