mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-07 22:34:18 +08:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
db316d57b6
@ -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 = {
|
|||||||
.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)
|
|||||||
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 = {
|
|||||||
.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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
* 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 {
|
|||||||
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 @@
|
|||||||
#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,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
|
if (p->netpoll)
|
||||||
|
netpoll_send_skb(p->netpoll, skb);
|
||||||
|
#else
|
||||||
|
BUG();
|
||||||
|
#endif
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
|
static netdev_tx_t dsa_slave_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;
|
||||||
|
|
||||||
return p->xmit(skb, dev);
|
dev->stats.tx_packets++;
|
||||||
}
|
dev->stats.tx_bytes += skb->len;
|
||||||
|
|
||||||
static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb,
|
/* Transmit function may have to reallocate the original SKB */
|
||||||
struct net_device *dev)
|
nskb = p->xmit(skb, dev);
|
||||||
{
|
if (!nskb)
|
||||||
struct dsa_slave_priv *p = netdev_priv(dev);
|
return NETDEV_TX_OK;
|
||||||
|
|
||||||
skb->dev = p->parent->dst->master_netdev;
|
/* SKB for netpoll still need to be mangled with the protocol-specific
|
||||||
dev_queue_xmit(skb);
|
* 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)
|
|||||||
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 = {
|
|||||||
.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 @@
|
|||||||
#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)
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user