* [PATCH net-next v2 2/5] qlcnic: Enhance ethtool Statistics for Multiple Tx queue.
From: Himanshu Madhani @ 2013-11-04 18:31 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Himanshu Madhani
In-Reply-To: <cover.1383612975.git.himanshu.madhani@qlogic.com>
From: Himanshu Madhani <himanshu.madhani@qlogic.com>
o Enhance ethtool statistics to display multiple Tx queue stats for
all supported adapters.
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 13 ++-
.../net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c | 96 +++++++++++++++-------
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 14 ++--
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 33 ++++----
4 files changed, 94 insertions(+), 62 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index db83edf..2d818c1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -533,6 +533,14 @@ struct qlcnic_host_sds_ring {
char name[IFNAMSIZ + 12];
} ____cacheline_internodealigned_in_smp;
+struct qlcnic_tx_queue_stats {
+ u64 xmit_on;
+ u64 xmit_off;
+ u64 xmit_called;
+ u64 xmit_finished;
+ u64 tx_bytes;
+};
+
struct qlcnic_host_tx_ring {
int irq;
void __iomem *crb_intr_mask;
@@ -544,10 +552,7 @@ struct qlcnic_host_tx_ring {
u32 sw_consumer;
u32 num_desc;
- u64 xmit_on;
- u64 xmit_off;
- u64 xmit_called;
- u64 xmit_finished;
+ struct qlcnic_tx_queue_stats tx_stats;
void __iomem *crb_cmd_producer;
struct cmd_desc_type0 *desc_head;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 0aaa52b..9b6dd98 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -27,43 +27,36 @@ static const u32 qlcnic_fw_dump_level[] = {
};
static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
+ {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
+ {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"xmit_called", QLC_SIZEOF(stats.xmitcalled),
- QLC_OFF(stats.xmitcalled)},
+ QLC_OFF(stats.xmitcalled)},
{"xmit_finished", QLC_SIZEOF(stats.xmitfinished),
- QLC_OFF(stats.xmitfinished)},
- {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+ QLC_OFF(stats.xmitfinished)},
+ {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
+ QLC_OFF(stats.tx_dma_map_error)},
+ {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
{"tx_dropped", QLC_SIZEOF(stats.txdropped), QLC_OFF(stats.txdropped)},
- {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+ {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
+ QLC_OFF(stats.rx_dma_map_error)},
{"rx_pkts", QLC_SIZEOF(stats.rx_pkts), QLC_OFF(stats.rx_pkts)},
- {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"rx_bytes", QLC_SIZEOF(stats.rxbytes), QLC_OFF(stats.rxbytes)},
- {"tx_bytes", QLC_SIZEOF(stats.txbytes), QLC_OFF(stats.txbytes)},
+ {"rx_dropped", QLC_SIZEOF(stats.rxdropped), QLC_OFF(stats.rxdropped)},
+ {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
+ {"csummed", QLC_SIZEOF(stats.csummed), QLC_OFF(stats.csummed)},
+ {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
{"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
{"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
- {"xmit_on", QLC_SIZEOF(stats.xmit_on), QLC_OFF(stats.xmit_on)},
- {"xmit_off", QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
{"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
QLC_OFF(stats.skb_alloc_failure)},
- {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
- {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
- QLC_OFF(stats.rx_dma_map_error)},
- {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
- QLC_OFF(stats.tx_dma_map_error)},
{"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
- QLC_OFF(stats.mac_filter_limit_overrun)},
+ QLC_OFF(stats.mac_filter_limit_overrun)},
{"spurious intr", QLC_SIZEOF(stats.spurious_intr),
QLC_OFF(stats.spurious_intr)},
};
static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
- "rx unicast frames",
- "rx multicast frames",
- "rx broadcast frames",
- "rx dropped frames",
- "rx errors",
- "rx local frames",
- "rx numbytes",
"tx unicast frames",
"tx multicast frames",
"tx broadcast frames",
@@ -71,6 +64,13 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx errors",
"tx local frames",
"tx numbytes",
+ "rx unicast frames",
+ "rx multicast frames",
+ "rx broadcast frames",
+ "rx dropped frames",
+ "rx errors",
+ "rx local frames",
+ "rx numbytes",
};
static const char qlcnic_83xx_tx_stats_strings[][ETH_GSTRING_LEN] = {
@@ -126,13 +126,16 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-static const char qlcnic_tx_ring_stats_strings[][ETH_GSTRING_LEN] = {
+static const char qlcnic_tx_queue_stats_strings[][ETH_GSTRING_LEN] = {
"xmit_on",
"xmit_off",
"xmit_called",
"xmit_finished",
+ "tx_bytes",
};
+#define QLCNIC_TX_STATS_LEN ARRAY_SIZE(qlcnic_tx_queue_stats_strings)
+
static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_rx_bytes",
"ctx_rx_pkts",
@@ -1123,11 +1126,11 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
QLCNIC_TEST_LEN * ETH_GSTRING_LEN);
break;
case ETH_SS_STATS:
- num_stats = ARRAY_SIZE(qlcnic_tx_ring_stats_strings);
+ num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings);
for (i = 0; i < adapter->max_drv_tx_rings; i++) {
for (index = 0; index < num_stats; index++) {
- sprintf(data, "tx_ring_%d %s", i,
- qlcnic_tx_ring_stats_strings[index]);
+ sprintf(data, "tx_queue_%d %s", i,
+ qlcnic_tx_queue_stats_strings[index]);
data += ETH_GSTRING_LEN;
}
}
@@ -1225,6 +1228,36 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
return data;
}
+static void qlcnic_update_stats(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_host_tx_ring *tx_ring;
+ int ring;
+
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ adapter->stats.xmit_on += tx_ring->tx_stats.xmit_on;
+ adapter->stats.xmit_off += tx_ring->tx_stats.xmit_off;
+ adapter->stats.xmitcalled += tx_ring->tx_stats.xmit_called;
+ adapter->stats.xmitfinished += tx_ring->tx_stats.xmit_finished;
+ adapter->stats.txbytes += tx_ring->tx_stats.tx_bytes;
+ }
+}
+
+static u64 *qlcnic_fill_tx_queue_stats(u64 *data, void *stats)
+{
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ tx_ring = (struct qlcnic_host_tx_ring *)stats;
+
+ *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_on);
+ *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_off);
+ *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_called);
+ *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.xmit_finished);
+ *data++ = QLCNIC_FILL_STATS(tx_ring->tx_stats.tx_bytes);
+
+ return data;
+}
+
static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
@@ -1232,19 +1265,20 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_esw_statistics port_stats;
struct qlcnic_mac_statistics mac_stats;
- int index, ret, length, size, ring;
+ int index, ret, length, size, tx_size, ring;
char *p;
- memset(data, 0, adapter->max_drv_tx_rings * 4 * sizeof(u64));
+ tx_size = adapter->max_drv_tx_rings * QLCNIC_TX_STATS_LEN;
+
+ memset(data, 0, tx_size * sizeof(u64));
for (ring = 0, index = 0; ring < adapter->max_drv_tx_rings; ring++) {
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
tx_ring = &adapter->tx_ring[ring];
- *data++ = tx_ring->xmit_on;
- *data++ = tx_ring->xmit_off;
- *data++ = tx_ring->xmit_called;
- *data++ = tx_ring->xmit_finished;
+ data = qlcnic_fill_tx_queue_stats(data, tx_ring);
+ qlcnic_update_stats(adapter);
}
}
+
memset(data, 0, stats->n_stats * sizeof(u64));
length = QLCNIC_STATS_LEN;
for (index = 0; index < length; index++) {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 897627d..df31be7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -607,8 +607,7 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_tx_start_queue(tx_ring->txq);
} else {
- adapter->stats.xmit_off++;
- tx_ring->xmit_off++;
+ tx_ring->tx_stats.xmit_off++;
return NETDEV_TX_BUSY;
}
}
@@ -669,9 +668,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->drv_mac_learn)
qlcnic_send_filter(adapter, first_desc, skb);
- adapter->stats.txbytes += skb->len;
- adapter->stats.xmitcalled++;
- tx_ring->xmit_called++;
+ tx_ring->tx_stats.tx_bytes += skb->len;
+ tx_ring->tx_stats.xmit_called++;
qlcnic_update_cmd_producer(tx_ring);
@@ -805,8 +803,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
PCI_DMA_TODEVICE);
frag->dma = 0ULL;
}
- adapter->stats.xmitfinished++;
- tx_ring->xmit_finished++;
+ tx_ring->tx_stats.xmit_finished++;
dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL;
}
@@ -823,8 +820,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
netif_carrier_ok(netdev)) {
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_tx_wake_queue(tx_ring->txq);
- adapter->stats.xmit_on++;
- tx_ring->xmit_on++;
+ tx_ring->tx_stats.xmit_on++;
}
}
adapter->tx_timeo_cnt = 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 46ddbd8..05394a4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -2720,24 +2720,21 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
QLCNIC_FORCE_FW_DUMP_KEY);
} else {
netdev_info(netdev, "Tx timeout, reset adapter context.\n");
- if (qlcnic_82xx_check(adapter)) {
- for (ring = 0; ring < adapter->max_drv_tx_rings;
- ring++) {
- tx_ring = &adapter->tx_ring[ring];
- dev_info(&netdev->dev, "ring=%d\n", ring);
- dev_info(&netdev->dev, "crb_intr_mask=%d\n",
- readl(tx_ring->crb_intr_mask));
- dev_info(&netdev->dev, "producer=%d\n",
- readl(tx_ring->crb_cmd_producer));
- dev_info(&netdev->dev, "sw_consumer = %d\n",
- tx_ring->sw_consumer);
- dev_info(&netdev->dev, "hw_consumer = %d\n",
- le32_to_cpu(*(tx_ring->hw_consumer)));
- dev_info(&netdev->dev, "xmit-on=%llu\n",
- tx_ring->xmit_on);
- dev_info(&netdev->dev, "xmit-off=%llu\n",
- tx_ring->xmit_off);
- }
+ for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+ tx_ring = &adapter->tx_ring[ring];
+ netdev_info(netdev, "Tx ring=%d\n", ring);
+ netdev_info(netdev,
+ "crb_intr_mask=%d, producer=%d, sw_consumer=%d, hw_consumer=%d\n",
+ readl(tx_ring->crb_intr_mask),
+ readl(tx_ring->crb_cmd_producer),
+ tx_ring->sw_consumer,
+ le32_to_cpu(*(tx_ring->hw_consumer)));
+ netdev_info(netdev,
+ "xmit_finished=%llu, xmit_called=%llu, xmit_on=%llu, xmit_off=%llu\n",
+ tx_ring->tx_stats.xmit_finished,
+ tx_ring->tx_stats.xmit_called,
+ tx_ring->tx_stats.xmit_on,
+ tx_ring->tx_stats.xmit_off);
}
adapter->ahw->reset_context = 1;
}
--
1.8.1.4
^ permalink raw reply related
* Re: [PATCH RESEND] packet: Deliver VLAN TPID to userspace
From: Daniel Borkmann @ 2013-11-04 18:33 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Atzm Watanabe, David Miller, netdev, stephen
In-Reply-To: <1383585391.1553.7.camel@bwh-desktop.uk.level5networks.com>
On 11/04/2013 06:16 PM, Ben Hutchings wrote:
> On Wed, 2013-10-30 at 16:03 +0900, Atzm Watanabe wrote:
> [...]
>> Should it be structures as below?
>>
>> struct tpacket_hdr_variant1 {
>> __u32 tp_rxhash;
>> __u32 tp_vlan_tci;
>> };
>>
>> struct tpacket_hdr_variant2 {
>> __u32 tp_rxhash;
>> __u32 tp_vlan_tci;
>> __u32 tp_vlan_tpid;
>> };
>>
>> struct tpacket3_hdr {
>> __u32 tp_next_offset;
>> __u32 tp_sec;
>> __u32 tp_nsec;
>> __u32 tp_snaplen;
>> __u32 tp_len;
>> __u32 tp_status;
>> __u16 tp_mac;
>> __u16 tp_net;
>> /* pkt_hdr variants */
>> union {
>> struct tpacket_hdr_variant1 hv1;
>> struct tpacket_hdr_variant2 hv2;
>> };
>> };
>>
>> If it's ok, I'd like to send the patch v2.
> [...]
>
> I think this makes sense.
>
> Also add a BUILD_BUG_ON(TPACKET3_HDRLEN != 48) somewhere.
Sorry for coming late into this discussion.
I think the packet_mmap API with its 3 different API versions
already is a "bit" terrible, and should only be further extended
for user space if there is a _*huge*_ (!) improvement somewhere
(e.g. in terms of packet capturing/transmission performance) that
would justify it. I'm thinking that this could e.g. be in terms
of packet capturing and transmission performance.
Otherwise, each time we want to add a new member, we add yet
another subheader for userspace into tpacket, making it even
more complicated to use, and adding more "legacy" API fragments?
To solve your problem, why don't you add a socket option that,
if _enabled_, would reconstruct the vlan header as it was seen
on the "wire" and push that up to userspace, just like libpcap
does internally. It's not perfect either, but perhaps a better
way to go. What do you think?
^ permalink raw reply
* Re: [PATCH] phy: Add MOXA RTL8201CP PHY support
From: Florian Fainelli @ 2013-11-04 17:51 UTC (permalink / raw)
To: Jonas Jensen
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
netdev
In-Reply-To: <CACmBeS3aUq_yPVg_GaKmQRQMhAmO8RZVzUGY=T6Ghn7v0sP8Dw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013/11/4 Jonas Jensen <jonas.jensen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>:
> Thanks for the replies.
>
> On 1 November 2013 18:01, Florian Fainelli <florian-p3rKhJxN3npAfugRpC6u6w@public.gmane.org> wrote:
>>> + dev_err(&bus->dev, "%s timed out\n", __func__);
>>
>> I would keep these as a debugging aid and not spawn error messages on
>> the console by default.
>
> Done.
>
>
>>> + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
>>
>> If you only support device tree probing, this might be fine, but you
>> might want to be safe in case someone does a !OF instantiation and
>> also use pdev->id as an additional unique identifier, so something
>> like:
>>
>> %s-%d-mii, pdev->name, pdev->id
>>
>> will work.
>
> Done.
>
>
>>> + /* Setting PHY_IGNORE_INTERRUPT here even if it has no effect,
>>> + * of_mdiobus_register() sets these PHY_POLL.
>>> + * Ideally, the interrupt from MAC controller could be used to
>>> + * detect link state changes, not polling, i.e. if there was
>>> + * a way phy_driver could set PHY_HAS_INTERRUPT but have that
>>> + * interrupt handled in ethernet drivercode.
>>> + */
>>> + for (i = 0; i < PHY_MAX_ADDR; i++)
>>> + bus->irq[i] = PHY_IGNORE_INTERRUPT;
>>
>> This type of configuration where the PHY interrupt is actually
>> serviced by a link interrupt bit in the Ethernet MAC driver now works
>> since 5ea94e768 ("phy: add phy_mac_interrupt() to use with
>> PHY_IGNORE_INTERRUPT") so setting PHY_IGNORE_INTERRUPT is the right
>> way to signal this and this will no longer make the PHY library poll
>> for the link state.
>
> Yes, I tried using phy_mac_interrupt() but had some difficulties (I'll
> explain below). It seemed to be what I want and is wrapped with
> EXPORT_SYMBOL().
>
> However, as of next-20131104 I don't see how this works for DT probed
> devices (those that set PHY_IGNORE_INTERRUPT).
>
> As I tried to explain in my comment, of_mdiobus_register() assigns
> PHY_POLL to the IRQ array:
>
> drivers/of/of_mdio.c
> ..
> int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
> {
> ..
> /* Clear all the IRQ properties */
> if (mdio->irq)
> for (i=0; i<PHY_MAX_ADDR; i++)
> mdio->irq[i] = PHY_POLL;
You are right, I missed that part. We can't really assign a dedicated
interrupt line for your PHY, so we need another way of dealing with
these PHY interrupts present at the Ethernet MAC level.
[snip]
> This is why I ended up setting PHY_IGNORE_INTERRUPT and the comment
> about its effectiveness. Polling works but the extra reads on the bus
> seem unnecessary.
> Ideas how they can be eliminated are appreciated.
As of today, the only way to work around it is not to use
of_mdiobus_register() and use mdiobus_register() directly which will
allow you to properly describe such a configuration.
>
>
> Another problem, when phy_mac_interrupt() is called from NAPI it looks
> like it's trying to take a lock it already has. I tried moving it out
> of poll, placing it directly in IRQ handler, with the same result:
>
> [ 18.230000] moxart-ethernet 90900000.mac eth0: moxart_poll: PHYSTS_CHG
> [ 18.240000]
> [ 18.240000] =================================
> [ 18.240000] [ INFO: inconsistent lock state ]
> [ 18.240000] 3.12.0-rc7-next-20131104+ #1067 Not tainted
> [ 18.240000] ---------------------------------
> [ 18.240000] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
> [ 18.240000] kworker/0:1/123 [HC0[0]:SC0[0]:HE1:SE1] takes:
> [ 18.240000] ((&dev->phy_queue)){+.?...}, at: [<c0028c08>]
> process_one_work+0x13c/0x430
> [ 18.240000] {IN-SOFTIRQ-W} state was registered at:
> [ 18.240000] [<c0055648>] mark_lock+0x144/0x670
> [ 18.240000] [<c005777c>] __lock_acquire+0x5e4/0x1c24
> [ 18.240000] [<c00592cc>] lock_acquire+0x6c/0x80
> [ 18.240000] [<c002a024>] flush_work+0x44/0x278
> [ 18.240000] [<c002a2e0>] __cancel_work_timer+0x88/0x124
> [ 18.240000] [<c002a390>] cancel_work_sync+0x14/0x18
> [ 18.240000] [<c01b0190>] phy_mac_interrupt+0x20/0x40
> [ 18.240000] [<c01b3450>] moxart_poll+0x2b4/0x4b4
> [ 18.240000] [<c01fe3c8>] net_rx_action+0x130/0x22c
> [ 18.240000] [<c00174cc>] __do_softirq+0xe8/0x238
> [ 18.240000] [<c0017a2c>] irq_exit+0xac/0xfc
> [ 18.240000] [<c0009b40>] handle_IRQ+0x3c/0x8c
> [ 18.240000] [<c0008534>] handle_irq+0x98/0xa8
> [ 18.240000] [<c000c478>] __irq_svc+0x38/0x68
> [ 18.240000] [<c00487ec>] rcu_idle_exit+0x78/0xdc
> [ 18.240000] [<c0040618>] cpu_startup_entry+0x88/0x130
> [ 18.240000] [<c026d3c8>] rest_init+0xb8/0xe0
> [ 18.240000] [<c033ea1c>] start_kernel+0x298/0x2dc
> [ 18.240000] irq event stamp: 2659
> [ 18.240000] hardirqs last enabled at (2659): [<c0276298>]
> _raw_spin_unlock_irq+0x2c/0x60
> [ 18.240000] hardirqs last disabled at (2658): [<c02760f0>]
> _raw_spin_lock_irq+0x28/0x78
> [ 18.240000] softirqs last enabled at (2654): [<c0017568>]
> __do_softirq+0x184/0x238
> [ 18.240000] softirqs last disabled at (2637): [<c0017a2c>] irq_exit+0xac/0xfc
> [ 18.240000]
> [ 18.240000] other info that might help us debug this:
> [ 18.240000] Possible unsafe locking scenario:
> [ 18.240000]
> [ 18.240000] CPU0
> [ 18.240000] ----
> [ 18.240000] lock([ 18.240000] moxart-ethernet 90900000.mac
> eth0: TX ring end reached
> [ 18.240000] (&dev->phy_queue));
> [ 18.240000] <Interrupt>
> [ 18.240000] lock((&dev->phy_queue));
> [ 18.240000]
> [ 18.240000] *** DEADLOCK ***
> [ 18.240000]
> [ 18.240000] 1 lock held by kworker/0:1/123:
> [ 18.240000] #0: (events){.+.+..}, at: [<c0028c08>]
> process_one_work+0x13c/0x430
> [ 18.240000]
> [ 18.240000] stack backtrace:
> [ 18.240000] CPU: 0 PID: 123 Comm: kworker/0:1 Not tainted
> 3.12.0-rc7-next-20131104+ #1067
> [ 18.240000] Workqueue: events phy_change
> [ 18.240000] [<c000d214>] (unwind_backtrace+0x0/0xf4) from
> [<c000b964>] (show_stack+0x18/0x1c)
> [ 18.240000] [<c000b964>] (show_stack+0x18/0x1c) from [<c0271614>]
> (dump_stack+0x20/0x28)
> [ 18.240000] [<c0271614>] (dump_stack+0x20/0x28) from [<c026fee0>]
> (print_usage_bug.part.26+0x220/0x288)
> [ 18.240000] [<c026fee0>] (print_usage_bug.part.26+0x220/0x288) from
> [<c0055b3c>] (mark_lock+0x638/0x670)
> [ 18.240000] [<c0055b3c>] (mark_lock+0x638/0x670) from [<c00577c4>]
> (__lock_acquire+0x62c/0x1c24)
> [ 18.240000] [<c00577c4>] (__lock_acquire+0x62c/0x1c24) from
> [<c00592cc>] (lock_acquire+0x6c/0x80)
> [ 18.240000] [<c00592cc>] (lock_acquire+0x6c/0x80) from [<c0028c70>]
> (process_one_work+0x1a4/0x430)
> [ 18.240000] [<c0028c70>] (process_one_work+0x1a4/0x430) from
> [<c0029304>] (worker_thread+0x13c/0x3dc)
> [ 18.240000] [<c0029304>] (worker_thread+0x13c/0x3dc) from
> [<c002f500>] (kthread+0xb8/0xd4)
> [ 18.240000] [<c002f500>] (kthread+0xb8/0xd4) from [<c0009360>]
> (ret_from_fork+0x14/0x34)
> [ 18.610000] libphy: phy_change
Ok, I will take a look into this, I realize that I was calling this
from a workqueue which won't show the locking problem, thanks for the
report.
>
>
>>> + ret = of_mdiobus_register(bus, np);
>>> + if (ret < 0)
>>> + return ret;
>>
>> You still need to call mdiobus_free() here in case registration fails.
>
> Done.
>
>
>>> +/* RTL8201CP */
>>> +static struct phy_driver rtl8201cp_driver = {
>>> + .phy_id = 0x00008201,
>>> + .name = "RTL8201CP Ethernet",
>>> + .phy_id_mask = 0x0000ffff,
>>> + .features = PHY_BASIC_FEATURES,
>>
>> If this PHY is internal to your SoC (same die/package) you should also
>> add PHY_IS_INTERNAL to get a consistent ethtool reporting (among
>> others).
>
> I was wondering about that, and now I'm sure it should not be set, the
> physical chip is separate, as can be seen here:
>
> https://lh4.googleusercontent.com/-A-2FXDrObU8/UMcMc_K2vEI/AAAAAAAABwg/ldaLZ7ps1P4/w1331-h998-no/UC-7112-LX-picture4.jpg
Right, then make that a separate patch instead.
--
Florian
--
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH RFC] ipv6: enable IPV6_FLOWLABEL_MGR for getsockopt
From: Hannes Frederic Sowa @ 2013-11-04 17:46 UTC (permalink / raw)
To: Florent Fourcot; +Cc: netdev
In-Reply-To: <5277D4AD.10308@enst-bretagne.fr>
On Mon, Nov 04, 2013 at 06:09:01PM +0100, Florent Fourcot wrote:
>
> > We should take ip6_fl_lock here, otherwise expires extraction races with
> > the garbage collector (which can update it). There seem to be some other
> > unsafe places, e.g. fl6_renew.
> >
>
> I will fix it, and for fl6_renew too.
Thanks!
> >> + freq->flr_label = sfl->fl->label;
> >> + freq->flr_dst = sfl->fl->dst;
> >> + freq->flr_share = sfl->fl->share;
> >> + freq->flr_expires = (sfl->fl->expires - jiffies) / HZ;
> >> + freq->flr_linger = sfl->fl->linger / HZ;
> >> +
> >> + rcu_read_unlock_bh();
> >> + return 0;
> >> + }
> >> + }
> >> + rcu_read_unlock_bh();
> >> +
> >> + return 0;
> >
> > Maybe return -EINVAL for not found?
> >
>
> I don't like -EINVAL for this case, since the user can not know if there
> are no label or if the request has bad parameters. Could -ENOMSG be OK?
-ENOMSG or we already return -ENOENT from the same setsockopt. I would go with
ENOENT.
Greetings,
Hannes
^ permalink raw reply
* [PATCH 2/2] ixgbe: enable l2 forwarding acceleration for macvlans
From: John Fastabend @ 2013-11-04 17:15 UTC (permalink / raw)
To: nhorman, alexander.h.duyck; +Cc: netdev, andy, davem, jeffrey.t.kirsher
In-Reply-To: <20131104170424.2999.55773.stgit@jf-dev1-dcblab>
Now that l2 acceleration ops are in place from the prior patch,
enable ixgbe to take advantage of these operations. Allow it to
allocate queues for a macvlan so that when we transmit a frame,
we can do the switching in hardware inside the ixgbe card, rather
than in software.
For now this patch limits the hardware to 8 offloaded macvlan ports.
A follow on patch will remove this limitation but to simplify
review/validation of the new macvlan offload ops we leave it at 8
for now.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 20 +
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 12 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 465 +++++++++++++++++++++----
3 files changed, 417 insertions(+), 80 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 0914914..236d4fb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -223,6 +223,15 @@ enum ixgbe_ring_state_t {
__IXGBE_RX_FCOE,
};
+struct ixgbe_fwd_adapter {
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ struct net_device *netdev;
+ struct ixgbe_adapter *real_adapter;
+ unsigned int tx_base_queue;
+ unsigned int rx_base_queue;
+ int pool;
+};
+
#define check_for_tx_hang(ring) \
test_bit(__IXGBE_TX_DETECT_HANG, &(ring)->state)
#define set_check_for_tx_hang(ring) \
@@ -240,6 +249,7 @@ struct ixgbe_ring {
struct ixgbe_q_vector *q_vector; /* backpointer to host q_vector */
struct net_device *netdev; /* netdev ring belongs to */
struct device *dev; /* device for DMA mapping */
+ struct ixgbe_fwd_adapter *l2_accel_priv;
void *desc; /* descriptor ring memory */
union {
struct ixgbe_tx_buffer *tx_buffer_info;
@@ -292,11 +302,15 @@ enum ixgbe_ring_f_enum {
};
#define IXGBE_MAX_RSS_INDICES 16
-#define IXGBE_MAX_VMDQ_INDICES 64
+#define IXGBE_MAX_VMDQ_INDICES 8
#define IXGBE_MAX_FDIR_INDICES 63 /* based on q_vector limit */
#define IXGBE_MAX_FCOE_INDICES 8
#define MAX_RX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
#define MAX_TX_QUEUES (IXGBE_MAX_FDIR_INDICES + 1)
+#define IXGBE_MAX_L2A_QUEUES 4
+#define IXGBE_MAX_L2A_QUEUES 4
+#define IXGBE_BAD_L2A_QUEUE 3
+
struct ixgbe_ring_feature {
u16 limit; /* upper limit on feature indices */
u16 indices; /* current value of indices */
@@ -766,6 +780,7 @@ struct ixgbe_adapter {
#endif /*CONFIG_DEBUG_FS*/
u8 default_up;
+ unsigned long fwd_bitmask; /* Bitmask indicating in use pools */
};
struct ixgbe_fdir_filter {
@@ -939,4 +954,7 @@ void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter);
#endif
+netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
+ struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring);
#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index 90b4e10..5eae76a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -852,7 +852,11 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
/* apply Tx specific ring traits */
ring->count = adapter->tx_ring_count;
- ring->queue_index = txr_idx;
+ if (adapter->num_rx_pools > 1)
+ ring->queue_index =
+ txr_idx % adapter->num_rx_queues_per_pool;
+ else
+ ring->queue_index = txr_idx;
/* assign ring to adapter */
adapter->tx_ring[txr_idx] = ring;
@@ -895,7 +899,11 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
#endif /* IXGBE_FCOE */
/* apply Rx specific ring traits */
ring->count = adapter->rx_ring_count;
- ring->queue_index = rxr_idx;
+ if (adapter->num_rx_pools > 1)
+ ring->queue_index =
+ rxr_idx % adapter->num_rx_queues_per_pool;
+ else
+ ring->queue_index = rxr_idx;
/* assign ring to adapter */
adapter->rx_ring[rxr_idx] = ring;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 5191b3c..fe04e86 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -44,6 +44,7 @@
#include <linux/ethtool.h>
#include <linux/if.h>
#include <linux/if_vlan.h>
+#include <linux/if_macvlan.h>
#include <linux/if_bridge.h>
#include <linux/prefetch.h>
#include <scsi/fc/fc_fcoe.h>
@@ -870,11 +871,18 @@ static u64 ixgbe_get_tx_completed(struct ixgbe_ring *ring)
static u64 ixgbe_get_tx_pending(struct ixgbe_ring *ring)
{
- struct ixgbe_adapter *adapter = netdev_priv(ring->netdev);
- struct ixgbe_hw *hw = &adapter->hw;
+ struct ixgbe_adapter *adapter;
+ struct ixgbe_hw *hw;
+ u32 head, tail;
+
+ if (ring->l2_accel_priv)
+ adapter = ring->l2_accel_priv->real_adapter;
+ else
+ adapter = netdev_priv(ring->netdev);
- u32 head = IXGBE_READ_REG(hw, IXGBE_TDH(ring->reg_idx));
- u32 tail = IXGBE_READ_REG(hw, IXGBE_TDT(ring->reg_idx));
+ hw = &adapter->hw;
+ head = IXGBE_READ_REG(hw, IXGBE_TDH(ring->reg_idx));
+ tail = IXGBE_READ_REG(hw, IXGBE_TDT(ring->reg_idx));
if (head != tail)
return (head < tail) ?
@@ -3003,7 +3011,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
struct ixgbe_q_vector *q_vector = ring->q_vector;
if (q_vector)
- netif_set_xps_queue(adapter->netdev,
+ netif_set_xps_queue(ring->netdev,
&q_vector->affinity_mask,
ring->queue_index);
}
@@ -3393,7 +3401,7 @@ static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
int rss_i = adapter->ring_feature[RING_F_RSS].indices;
- int p;
+ u16 pool;
/* PSRTYPE must be initialized in non 82598 adapters */
u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
@@ -3410,9 +3418,8 @@ static void ixgbe_setup_psrtype(struct ixgbe_adapter *adapter)
else if (rss_i > 1)
psrtype |= 1 << 29;
- for (p = 0; p < adapter->num_rx_pools; p++)
- IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(VMDQ_P(p)),
- psrtype);
+ for_each_set_bit(pool, &adapter->fwd_bitmask, 32)
+ IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(VMDQ_P(pool)), psrtype);
}
static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
@@ -3681,7 +3688,11 @@ static void ixgbe_vlan_strip_disable(struct ixgbe_adapter *adapter)
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
for (i = 0; i < adapter->num_rx_queues; i++) {
- j = adapter->rx_ring[i]->reg_idx;
+ struct ixgbe_ring *ring = adapter->rx_ring[i];
+
+ if (ring->l2_accel_priv)
+ continue;
+ j = ring->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
vlnctrl &= ~IXGBE_RXDCTL_VME;
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
@@ -3711,7 +3722,11 @@ static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter)
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
for (i = 0; i < adapter->num_rx_queues; i++) {
- j = adapter->rx_ring[i]->reg_idx;
+ struct ixgbe_ring *ring = adapter->rx_ring[i];
+
+ if (ring->l2_accel_priv)
+ continue;
+ j = ring->reg_idx;
vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
vlnctrl |= IXGBE_RXDCTL_VME;
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
@@ -3748,7 +3763,7 @@ static int ixgbe_write_uc_addr_list(struct net_device *netdev)
unsigned int rar_entries = hw->mac.num_rar_entries - 1;
int count = 0;
- /* In SR-IOV mode significantly less RAR entries are available */
+ /* In SR-IOV/VMDQ modes significantly less RAR entries are available */
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
rar_entries = IXGBE_MAX_PF_MACVLANS - 1;
@@ -4113,6 +4128,195 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter)
spin_unlock(&adapter->fdir_perfect_lock);
}
+static void ixgbe_macvlan_set_rx_mode(struct net_device *dev, unsigned int pool,
+ struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vmolr;
+
+ /* No unicast promiscuous support for VMDQ devices. */
+ vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(pool));
+ vmolr |= (IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE);
+
+ /* clear the affected bit */
+ vmolr &= ~IXGBE_VMOLR_MPE;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ vmolr |= IXGBE_VMOLR_MPE;
+ } else {
+ vmolr |= IXGBE_VMOLR_ROMPE;
+ hw->mac.ops.update_mc_addr_list(hw, dev);
+ }
+ ixgbe_write_uc_addr_list(adapter->netdev);
+ IXGBE_WRITE_REG(hw, IXGBE_VMOLR(pool), vmolr);
+}
+
+static void ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
+ u8 *addr, u16 pool)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ unsigned int entry;
+
+ entry = hw->mac.num_rar_entries - pool;
+ hw->mac.ops.set_rar(hw, entry, addr, VMDQ_P(pool), IXGBE_RAH_AV);
+}
+
+static void ixgbe_fwd_psrtype(struct ixgbe_fwd_adapter *vadapter)
+{
+ struct ixgbe_adapter *adapter = vadapter->real_adapter;
+ int rss_i = vadapter->netdev->real_num_rx_queues;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 pool = vadapter->pool;
+ u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
+ IXGBE_PSRTYPE_UDPHDR |
+ IXGBE_PSRTYPE_IPV4HDR |
+ IXGBE_PSRTYPE_L2HDR |
+ IXGBE_PSRTYPE_IPV6HDR;
+
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ return;
+
+ if (rss_i > 3)
+ psrtype |= 2 << 29;
+ else if (rss_i > 1)
+ psrtype |= 1 << 29;
+
+ IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(VMDQ_P(pool)), psrtype);
+}
+
+/**
+ * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
+{
+ struct device *dev = rx_ring->dev;
+ unsigned long size;
+ u16 i;
+
+ /* ring already cleared, nothing to do */
+ if (!rx_ring->rx_buffer_info)
+ return;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rx_ring->count; i++) {
+ struct ixgbe_rx_buffer *rx_buffer;
+
+ rx_buffer = &rx_ring->rx_buffer_info[i];
+ if (rx_buffer->skb) {
+ struct sk_buff *skb = rx_buffer->skb;
+ if (IXGBE_CB(skb)->page_released) {
+ dma_unmap_page(dev,
+ IXGBE_CB(skb)->dma,
+ ixgbe_rx_bufsz(rx_ring),
+ DMA_FROM_DEVICE);
+ IXGBE_CB(skb)->page_released = false;
+ }
+ dev_kfree_skb(skb);
+ }
+ rx_buffer->skb = NULL;
+ if (rx_buffer->dma)
+ dma_unmap_page(dev, rx_buffer->dma,
+ ixgbe_rx_pg_size(rx_ring),
+ DMA_FROM_DEVICE);
+ rx_buffer->dma = 0;
+ if (rx_buffer->page)
+ __free_pages(rx_buffer->page,
+ ixgbe_rx_pg_order(rx_ring));
+ rx_buffer->page = NULL;
+ }
+
+ size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
+ memset(rx_ring->rx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_alloc = 0;
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+}
+
+static void ixgbe_disable_fwd_ring(struct ixgbe_fwd_adapter *vadapter,
+ struct ixgbe_ring *rx_ring)
+{
+ struct ixgbe_adapter *adapter = vadapter->real_adapter;
+ int index = rx_ring->queue_index + vadapter->rx_base_queue;
+
+ /* shutdown specific queue receive and wait for dma to settle */
+ ixgbe_disable_rx_queue(adapter, rx_ring);
+ usleep_range(10000, 20000);
+ ixgbe_irq_disable_queues(adapter, ((u64)1 << index));
+ ixgbe_clean_rx_ring(rx_ring);
+ rx_ring->l2_accel_priv = NULL;
+}
+
+static int ixgbe_fwd_ring_up(struct net_device *vdev,
+ struct ixgbe_fwd_adapter *accel)
+{
+ struct ixgbe_adapter *adapter = accel->real_adapter;
+ unsigned int rxbase;
+ unsigned int txbase;
+ int i, vmdq_pool, baseq;
+
+ /* Configure VSI adapter structure */
+ vmdq_pool = VMDQ_P(accel->pool);
+ baseq = vmdq_pool * adapter->num_rx_queues_per_pool;
+
+ netdev_dbg(vdev, "pool %i:%i queues %i:%i VSI bitmask %lx\n",
+ accel->pool, adapter->num_rx_pools,
+ baseq, baseq + adapter->num_rx_queues_per_pool,
+ adapter->fwd_bitmask);
+
+ accel->netdev = vdev;
+ accel->rx_base_queue = rxbase = baseq;
+ accel->tx_base_queue = txbase = baseq;
+
+ for (i = 0; i < vdev->num_rx_queues; i++)
+ ixgbe_disable_fwd_ring(accel, adapter->rx_ring[rxbase + i]);
+
+ for (i = 0; i < vdev->num_rx_queues; i++) {
+ adapter->rx_ring[rxbase + i]->netdev = vdev;
+ adapter->rx_ring[rxbase + i]->l2_accel_priv = accel;
+ ixgbe_configure_rx_ring(adapter, adapter->rx_ring[rxbase + i]);
+ }
+
+ for (i = 0; i < vdev->num_tx_queues; i++) {
+ adapter->tx_ring[txbase + i]->netdev = vdev;
+ adapter->tx_ring[txbase + i]->l2_accel_priv = accel;
+ }
+
+ if (is_valid_ether_addr(vdev->dev_addr))
+ ixgbe_add_mac_filter(adapter, vdev->dev_addr, accel->pool);
+
+ ixgbe_fwd_psrtype(accel);
+ ixgbe_macvlan_set_rx_mode(vdev, accel->pool, adapter);
+ return 0;
+}
+
+static void ixgbe_configure_vsi(struct ixgbe_adapter *adapter)
+{
+ struct net_device *upper;
+ struct list_head *iter;
+ int err;
+
+ netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+ if (netif_is_macvlan(upper)) {
+ struct macvlan_dev *vlan = netdev_priv(upper);
+ struct ixgbe_fwd_adapter *vadapter = vlan->fwd_priv;
+
+ if (vlan->fwd_priv) {
+ err = ixgbe_fwd_ring_up(upper, vadapter);
+ if (err)
+ continue;
+ ixgbe_macvlan_set_rx_mode(upper,
+ vadapter->pool,
+ adapter);
+ }
+ }
+ }
+}
+
static void ixgbe_configure(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
@@ -4164,6 +4368,7 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
#endif /* IXGBE_FCOE */
ixgbe_configure_tx(adapter);
ixgbe_configure_rx(adapter);
+ ixgbe_configure_vsi(adapter);
}
static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
@@ -4317,6 +4522,8 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *upper;
+ struct list_head *iter;
int err;
u32 ctrl_ext;
@@ -4360,6 +4567,16 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
+ /* enable any upper devices */
+ netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+ if (netif_is_macvlan(upper)) {
+ struct macvlan_dev *vlan = netdev_priv(upper);
+
+ if (vlan->fwd_priv)
+ netif_tx_start_all_queues(upper);
+ }
+ }
+
/* bring the link up in the watchdog, this could race with our first
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -4451,59 +4668,6 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
}
/**
- * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
- * @rx_ring: ring to free buffers from
- **/
-static void ixgbe_clean_rx_ring(struct ixgbe_ring *rx_ring)
-{
- struct device *dev = rx_ring->dev;
- unsigned long size;
- u16 i;
-
- /* ring already cleared, nothing to do */
- if (!rx_ring->rx_buffer_info)
- return;
-
- /* Free all the Rx ring sk_buffs */
- for (i = 0; i < rx_ring->count; i++) {
- struct ixgbe_rx_buffer *rx_buffer;
-
- rx_buffer = &rx_ring->rx_buffer_info[i];
- if (rx_buffer->skb) {
- struct sk_buff *skb = rx_buffer->skb;
- if (IXGBE_CB(skb)->page_released) {
- dma_unmap_page(dev,
- IXGBE_CB(skb)->dma,
- ixgbe_rx_bufsz(rx_ring),
- DMA_FROM_DEVICE);
- IXGBE_CB(skb)->page_released = false;
- }
- dev_kfree_skb(skb);
- }
- rx_buffer->skb = NULL;
- if (rx_buffer->dma)
- dma_unmap_page(dev, rx_buffer->dma,
- ixgbe_rx_pg_size(rx_ring),
- DMA_FROM_DEVICE);
- rx_buffer->dma = 0;
- if (rx_buffer->page)
- __free_pages(rx_buffer->page,
- ixgbe_rx_pg_order(rx_ring));
- rx_buffer->page = NULL;
- }
-
- size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
- memset(rx_ring->rx_buffer_info, 0, size);
-
- /* Zero out the descriptor ring */
- memset(rx_ring->desc, 0, rx_ring->size);
-
- rx_ring->next_to_alloc = 0;
- rx_ring->next_to_clean = 0;
- rx_ring->next_to_use = 0;
-}
-
-/**
* ixgbe_clean_tx_ring - Free Tx Buffers
* @tx_ring: ring to be cleaned
**/
@@ -4580,6 +4744,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *upper;
+ struct list_head *iter;
u32 rxctrl;
int i;
@@ -4603,6 +4769,19 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
netif_carrier_off(netdev);
netif_tx_disable(netdev);
+ /* disable any upper devices */
+ netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+ if (netif_is_macvlan(upper)) {
+ struct macvlan_dev *vlan = netdev_priv(upper);
+
+ if (vlan->fwd_priv) {
+ netif_tx_stop_all_queues(upper);
+ netif_carrier_off(upper);
+ netif_tx_disable(upper);
+ }
+ }
+ }
+
ixgbe_irq_disable(adapter);
ixgbe_napi_disable_all(adapter);
@@ -4833,6 +5012,8 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
return -EIO;
}
+ /* PF holds first pool slot */
+ set_bit(0, &adapter->fwd_bitmask);
set_bit(__IXGBE_DOWN, &adapter->state);
return 0;
@@ -5138,7 +5319,7 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
static int ixgbe_open(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- int err;
+ int err, queues;
/* disallow open during test */
if (test_bit(__IXGBE_TESTING, &adapter->state))
@@ -5163,16 +5344,22 @@ static int ixgbe_open(struct net_device *netdev)
goto err_req_irq;
/* Notify the stack of the actual queue counts. */
- err = netif_set_real_num_tx_queues(netdev,
- adapter->num_rx_pools > 1 ? 1 :
- adapter->num_tx_queues);
+ if (adapter->num_rx_pools > 1 &&
+ adapter->num_tx_queues > IXGBE_MAX_L2A_QUEUES)
+ queues = IXGBE_MAX_L2A_QUEUES;
+ else
+ queues = adapter->num_tx_queues;
+
+ err = netif_set_real_num_tx_queues(netdev, queues);
if (err)
goto err_set_queues;
-
- err = netif_set_real_num_rx_queues(netdev,
- adapter->num_rx_pools > 1 ? 1 :
- adapter->num_rx_queues);
+ if (adapter->num_rx_pools > 1 &&
+ adapter->num_rx_queues > IXGBE_MAX_L2A_QUEUES)
+ queues = IXGBE_MAX_L2A_QUEUES;
+ else
+ queues = adapter->num_rx_queues;
+ err = netif_set_real_num_rx_queues(netdev, queues);
if (err)
goto err_set_queues;
@@ -6762,8 +6949,9 @@ out_drop:
return NETDEV_TX_OK;
}
-static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
- struct net_device *netdev)
+static netdev_tx_t __ixgbe_xmit_frame(struct sk_buff *skb,
+ struct net_device *netdev,
+ struct ixgbe_ring *ring)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_ring *tx_ring;
@@ -6779,10 +6967,17 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
skb_set_tail_pointer(skb, 17);
}
- tx_ring = adapter->tx_ring[skb->queue_mapping];
+ tx_ring = ring ? ring : adapter->tx_ring[skb->queue_mapping];
+
return ixgbe_xmit_frame_ring(skb, adapter, tx_ring);
}
+static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ return __ixgbe_xmit_frame(skb, netdev, NULL);
+}
+
/**
* ixgbe_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
@@ -7300,6 +7495,118 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode);
}
+int ixgbe_fwd_ring_down(struct net_device *vdev,
+ struct ixgbe_fwd_adapter *accel)
+{
+ struct ixgbe_adapter *adapter = accel->real_adapter;
+ unsigned int rxbase = accel->rx_base_queue;
+ unsigned int txbase = accel->tx_base_queue;
+ int i;
+
+ netif_tx_stop_all_queues(vdev);
+
+ for (i = 0; i < vdev->num_rx_queues; i++) {
+ ixgbe_disable_fwd_ring(accel, adapter->rx_ring[rxbase + i]);
+ adapter->rx_ring[rxbase + i]->netdev = adapter->netdev;
+ }
+
+ for (i = 0; i < vdev->num_tx_queues; i++) {
+ adapter->tx_ring[txbase + i]->l2_accel_priv = NULL;
+ adapter->tx_ring[txbase + i]->netdev = adapter->netdev;
+ }
+
+
+ return 0;
+}
+
+static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
+{
+ struct ixgbe_fwd_adapter *fwd_adapter = NULL;
+ struct ixgbe_adapter *adapter = netdev_priv(pdev);
+ int pool, err;
+
+ /* Check for hardware restriction on number of rx/tx queues */
+ if (vdev->num_rx_queues != vdev->num_tx_queues ||
+ vdev->num_tx_queues > IXGBE_MAX_L2A_QUEUES ||
+ vdev->num_tx_queues == IXGBE_BAD_L2A_QUEUE) {
+ netdev_info(pdev, "%s: Supports RX/TX Queue counts 1,2, and 4\n",
+ pdev->name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (adapter->num_rx_pools >= IXGBE_MAX_VMDQ_INDICES)
+ return ERR_PTR(-EBUSY);
+
+ fwd_adapter = kcalloc(1, sizeof(struct ixgbe_fwd_adapter), GFP_KERNEL);
+ if (!fwd_adapter)
+ return ERR_PTR(-ENOMEM);
+
+ pool = find_first_zero_bit(&adapter->fwd_bitmask, 32);
+ adapter->num_rx_pools++;
+ set_bit(pool, &adapter->fwd_bitmask);
+
+ /* Enable VMDq flag so device will be set in VM mode */
+ adapter->flags |= IXGBE_FLAG_VMDQ_ENABLED | IXGBE_FLAG_SRIOV_ENABLED;
+ adapter->ring_feature[RING_F_VMDQ].limit = adapter->num_rx_pools;
+ adapter->ring_feature[RING_F_VMDQ].offset = 0;
+ adapter->ring_feature[RING_F_RSS].limit = IXGBE_MAX_L2A_QUEUES;
+
+ /* Force reinit of ring allocation with VMDQ enabled */
+ ixgbe_setup_tc(pdev, netdev_get_num_tc(pdev));
+ fwd_adapter->pool = pool;
+ fwd_adapter->real_adapter = adapter;
+ err = ixgbe_fwd_ring_up(vdev, fwd_adapter);
+ if (err)
+ goto fwd_add_err;
+
+ err = netif_set_real_num_tx_queues(vdev, vdev->num_tx_queues);
+ if (err)
+ goto fwd_queue_err;
+ err = netif_set_real_num_rx_queues(vdev, vdev->num_rx_queues);
+ if (err)
+ goto fwd_queue_err;
+
+ netif_tx_start_all_queues(vdev);
+
+ return fwd_adapter;
+fwd_queue_err:
+ ixgbe_fwd_ring_down(vdev, fwd_adapter);
+fwd_add_err:
+ kfree(fwd_adapter);
+ return ERR_PTR(err);
+}
+
+static void ixgbe_fwd_del(struct net_device *pdev, void *priv)
+{
+ struct ixgbe_fwd_adapter *fwd_adapter = priv;
+ struct ixgbe_adapter *adapter = fwd_adapter->real_adapter;
+
+ clear_bit(fwd_adapter->pool, &adapter->fwd_bitmask);
+ adapter->num_rx_pools--;
+
+ ixgbe_fwd_ring_down(fwd_adapter->netdev, fwd_adapter);
+
+ netdev_dbg(pdev, "pool %i:%i queues %i:%i VSI bitmask %lx\n",
+ fwd_adapter->pool, adapter->num_rx_pools,
+ fwd_adapter->rx_base_queue,
+ fwd_adapter->rx_base_queue + adapter->num_rx_queues_per_pool,
+ adapter->fwd_bitmask);
+}
+
+static netdev_tx_t ixgbe_fwd_xmit(struct sk_buff *skb,
+ struct net_device *dev,
+ void *priv)
+{
+ struct ixgbe_fwd_adapter *fwd_adapter = priv;
+ unsigned int queue;
+ struct ixgbe_ring *tx_ring;
+
+ queue = skb->queue_mapping + fwd_adapter->tx_base_queue;
+ tx_ring = fwd_adapter->real_adapter->tx_ring[queue];
+
+ return __ixgbe_xmit_frame(skb, dev, tx_ring);
+}
+
static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_open = ixgbe_open,
.ndo_stop = ixgbe_close,
@@ -7344,6 +7651,9 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_fdb_add = ixgbe_ndo_fdb_add,
.ndo_bridge_setlink = ixgbe_ndo_bridge_setlink,
.ndo_bridge_getlink = ixgbe_ndo_bridge_getlink,
+ .ndo_dfwd_add_station = ixgbe_fwd_add,
+ .ndo_dfwd_del_station = ixgbe_fwd_del,
+ .ndo_dfwd_start_xmit = ixgbe_fwd_xmit,
};
/**
@@ -7645,7 +7955,8 @@ skip_sriov:
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXHASH |
- NETIF_F_RXCSUM;
+ NETIF_F_RXCSUM |
+ NETIF_F_HW_L2FW_DOFFLOAD;
netdev->hw_features = netdev->features;
^ permalink raw reply related
* [PATCH 0/2] l2 hardware accelerated macvlans
From: John Fastabend @ 2013-11-04 17:15 UTC (permalink / raw)
To: nhorman, alexander.h.duyck; +Cc: netdev, andy, davem, jeffrey.t.kirsher
This patch adds support to offload macvlan net_devices to the
hardware. With these patches packets are pushed to the macvlan
net_device directly and do not pass through the lower dev.
The patches here have made it through multiple iterations
each with a slightly different focus. First I tried to
push these as a new link type called "VMDQ". The patches
shown here,
http://comments.gmane.org/gmane.linux.network/237617
Following this implementation I renamed the link type
"VSI" and addressed various comments. Finally Neil
Horman picked up the patches and integrated the offload
into the macvlan code. Here,
http://permalink.gmane.org/gmane.linux.network/285658
The attached series is clean-up of his patches, with a
few fixes. I suspect Neil will add his signed-off-by
line assuming I didn't mangle anything.
If folks find this series acceptable there are a few
items we can work on next. First broadcast and multicast
will use the hardware even for local traffic with this
series. It would be best (I think) to use the software
path for macvlan to macvlan traffic and save the PCIe
bus. Also this only allows for layer 2 mac forwarding
where some hardware supports more interesting forwarding
capabilities. Integrating with OVS may be useful here.
As always any comments/feedback welcome.
I'm going to continue testing these on top of ixgbe but
I believe these are stable and wanted to get them out to
a wider audience. I've tested multiple offloaded macvlans
with iperf and netperf using multiple sessions of each
and seen no issues.
My basic I/O test is here but I've also done some link
testing and others,
#ip link add link eth2 numtxqueues 4 numrxqueues 4 txqueuelen 50 type macvlan
#tc qdisc add dev macvlan0 mq
#iperf -c 10.0.0.1 -P 8 -t 5000 -i 10
Thanks,
John
---
John Fastabend (2):
ixgbe: enable l2 forwarding acceleration for macvlans
net: Add layer 2 hardware acceleration operations for macvlan devices
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 20 +
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 12 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 465 +++++++++++++++++++++----
drivers/net/macvlan.c | 36 ++
include/linux/if_macvlan.h | 1
include/linux/netdev_features.h | 2
include/linux/netdevice.h | 36 ++
include/uapi/linux/if.h | 1
net/core/dev.c | 18 +
net/core/ethtool.c | 1
net/sched/sch_generic.c | 2
11 files changed, 506 insertions(+), 88 deletions(-)
--
Signature
^ permalink raw reply
* [PATCH 1/2] net: Add layer 2 hardware acceleration operations for macvlan devices
From: John Fastabend @ 2013-11-04 17:15 UTC (permalink / raw)
To: nhorman, alexander.h.duyck; +Cc: netdev, andy, davem, jeffrey.t.kirsher
In-Reply-To: <20131104170424.2999.55773.stgit@jf-dev1-dcblab>
Add a operations structure that allows a network interface to export
the fact that it supports package forwarding in hardware between
physical interfaces and other mac layer devices assigned to it (such
as macvlans). This operaions structure can be used by virtual mac
devices to bypass software switching so that forwarding can be done
in hardware more efficiently.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
---
drivers/net/macvlan.c | 36 +++++++++++++++++++++++++++++++++++-
include/linux/if_macvlan.h | 1 +
include/linux/netdev_features.h | 2 ++
include/linux/netdevice.h | 36 +++++++++++++++++++++++++++++++++++-
include/uapi/linux/if.h | 1 +
net/core/dev.c | 18 +++++++++++++-----
net/core/ethtool.c | 1 +
net/sched/sch_generic.c | 2 +-
8 files changed, 89 insertions(+), 8 deletions(-)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index cc9845e..eb68dd0 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -297,7 +297,13 @@ netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
int ret;
const struct macvlan_dev *vlan = netdev_priv(dev);
- ret = macvlan_queue_xmit(skb, dev);
+ if (vlan->fwd_priv) {
+ skb->dev = vlan->lowerdev;
+ ret = dev_hard_start_xmit(skb, skb->dev, NULL, vlan->fwd_priv);
+ } else {
+ ret = macvlan_queue_xmit(skb, dev);
+ }
+
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
struct macvlan_pcpu_stats *pcpu_stats;
@@ -347,6 +353,21 @@ static int macvlan_open(struct net_device *dev)
goto hash_add;
}
+ if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) {
+ vlan->fwd_priv =
+ lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);
+
+ /* If we get a NULL pointer back, or if we get an error
+ * then we should just fall through to the non accelerated path
+ */
+ if (IS_ERR_OR_NULL(vlan->fwd_priv)) {
+ vlan->fwd_priv = NULL;
+ } else {
+ dev->features &= ~NETIF_F_LLTX;
+ return 0;
+ }
+ }
+
err = -EBUSY;
if (macvlan_addr_busy(vlan->port, dev->dev_addr))
goto out;
@@ -367,6 +388,11 @@ hash_add:
del_unicast:
dev_uc_del(lowerdev, dev->dev_addr);
out:
+ if (vlan->fwd_priv) {
+ lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
+ vlan->fwd_priv);
+ vlan->fwd_priv = NULL;
+ }
return err;
}
@@ -375,6 +401,13 @@ static int macvlan_stop(struct net_device *dev)
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
+ if (vlan->fwd_priv) {
+ lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
+ vlan->fwd_priv);
+ vlan->fwd_priv = NULL;
+ return 0;
+ }
+
dev_uc_unsync(lowerdev, dev);
dev_mc_unsync(lowerdev, dev);
@@ -833,6 +866,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
goto destroy_port;
+ dev->priv_flags |= IFF_MACVLAN;
err = netdev_upper_dev_link(lowerdev, dev);
if (err)
goto destroy_port;
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index ddd33fd..c270285 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -61,6 +61,7 @@ struct macvlan_dev {
struct hlist_node hlist;
struct macvlan_port *port;
struct net_device *lowerdev;
+ void *fwd_priv;
struct macvlan_pcpu_stats __percpu *pcpu_stats;
DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index b05a4b5..1005ebf 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -62,6 +62,7 @@ enum {
NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */
NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */
NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */
+ NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */
/*
* Add your fresh new feature above and remember to update
@@ -116,6 +117,7 @@ enum {
#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
+#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD)
/* Features valid for ethtool to change */
/* = all defined minus driver/device-class-related */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e6353ca..d62c130 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -962,6 +962,25 @@ struct netdev_phys_port_id {
* Called by vxlan to notify the driver about a UDP port and socket
* address family that vxlan is not listening to anymore. The operation
* is protected by the vxlan_net->sock_lock.
+ *
+ * void* (*ndo_dfwd_add_station)(struct net_device *pdev,
+ * struct net_device *dev)
+ * Called by upper layer devices to accelerate switching or other
+ * station functionality into hardware. 'pdev is the lowerdev
+ * to use for the offload and 'dev' is the net device that will
+ * back the offload. Returns a pointer to the private structure
+ * the upper layer will maintain.
+ * void (*ndo_dfwd_del_station)(struct net_device *pdev, void *priv)
+ * Called by upper layer device to delete the station created
+ * by 'ndo_dfwd_add_station'. 'pdev' is the net device backing
+ * the station and priv is the structure returned by the add
+ * operation.
+ * netdev_tx_t (*ndo_dfwd_start_xmit)(struct sk_buff *skb,
+ * struct net_device *dev,
+ * void *priv);
+ * Callback to use for xmit over the accelerated station. This
+ * is used in place of ndo_start_xmit on accelerated net
+ * devices.
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
@@ -1098,6 +1117,15 @@ struct net_device_ops {
void (*ndo_del_vxlan_port)(struct net_device *dev,
sa_family_t sa_family,
__be16 port);
+
+ void* (*ndo_dfwd_add_station)(struct net_device *pdev,
+ struct net_device *dev);
+ void (*ndo_dfwd_del_station)(struct net_device *pdev,
+ void *priv);
+
+ netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb,
+ struct net_device *dev,
+ void *priv);
};
/*
@@ -1195,6 +1223,7 @@ struct net_device {
/* Management operations */
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
+ const struct forwarding_accel_ops *fwd_ops;
/* Hardware header description */
const struct header_ops *header_ops;
@@ -2388,7 +2417,7 @@ int dev_change_carrier(struct net_device *, bool new_carrier);
int dev_get_phys_port_id(struct net_device *dev,
struct netdev_phys_port_id *ppid);
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq);
+ struct netdev_queue *txq, void *accel_priv);
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
extern int netdev_budget;
@@ -2967,6 +2996,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
dev->gso_max_size = size;
}
+static inline bool netif_is_macvlan(struct net_device *dev)
+{
+ return dev->priv_flags & IFF_MACVLAN;
+}
+
static inline bool netif_is_bond_master(struct net_device *dev)
{
return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING;
diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
index 1ec407b..d758163 100644
--- a/include/uapi/linux/if.h
+++ b/include/uapi/linux/if.h
@@ -83,6 +83,7 @@
#define IFF_SUPP_NOFCS 0x80000 /* device supports sending custom FCS */
#define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address
* change when it's running */
+#define IFF_MACVLAN 0x200000 /* Macvlan device */
#define IF_GET_IFACE 0x0001 /* for querying only */
diff --git a/net/core/dev.c b/net/core/dev.c
index 0e61365..8ffc52e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2538,7 +2538,7 @@ static inline int skb_needs_linearize(struct sk_buff *skb,
}
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
- struct netdev_queue *txq)
+ struct netdev_queue *txq, void *accel_priv)
{
const struct net_device_ops *ops = dev->netdev_ops;
int rc = NETDEV_TX_OK;
@@ -2604,9 +2604,13 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
dev_queue_xmit_nit(skb, dev);
skb_len = skb->len;
- rc = ops->ndo_start_xmit(skb, dev);
+ if (accel_priv)
+ rc = ops->ndo_dfwd_start_xmit(skb, dev, accel_priv);
+ else
+ rc = ops->ndo_start_xmit(skb, dev);
+
trace_net_dev_xmit(skb, rc, dev, skb_len);
- if (rc == NETDEV_TX_OK)
+ if (rc == NETDEV_TX_OK && txq)
txq_trans_update(txq);
return rc;
}
@@ -2622,7 +2626,10 @@ gso:
dev_queue_xmit_nit(nskb, dev);
skb_len = nskb->len;
- rc = ops->ndo_start_xmit(nskb, dev);
+ if (accel_priv)
+ rc = ops->ndo_dfwd_start_xmit(nskb, dev, accel_priv);
+ else
+ rc = ops->ndo_start_xmit(nskb, dev);
trace_net_dev_xmit(nskb, rc, dev, skb_len);
if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK)
@@ -2647,6 +2654,7 @@ out_kfree_skb:
out:
return rc;
}
+EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
static void qdisc_pkt_len_init(struct sk_buff *skb)
{
@@ -2854,7 +2862,7 @@ int dev_queue_xmit(struct sk_buff *skb)
if (!netif_xmit_stopped(txq)) {
__this_cpu_inc(xmit_recursion);
- rc = dev_hard_start_xmit(skb, dev, txq);
+ rc = dev_hard_start_xmit(skb, dev, txq, NULL);
__this_cpu_dec(xmit_recursion);
if (dev_xmit_complete(rc)) {
HARD_TX_UNLOCK(dev, txq);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 8629898..30071de 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -96,6 +96,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_LOOPBACK_BIT] = "loopback",
[NETIF_F_RXFCS_BIT] = "rx-fcs",
[NETIF_F_RXALL_BIT] = "rx-all",
+ [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
};
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7fc899a..922a094 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -126,7 +126,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
HARD_TX_LOCK(dev, txq, smp_processor_id());
if (!netif_xmit_frozen_or_stopped(txq))
- ret = dev_hard_start_xmit(skb, dev, txq);
+ ret = dev_hard_start_xmit(skb, dev, txq, NULL);
HARD_TX_UNLOCK(dev, txq);
^ permalink raw reply related
* Re: [PATCH RESEND] packet: Deliver VLAN TPID to userspace
From: Ben Hutchings @ 2013-11-04 17:16 UTC (permalink / raw)
To: Atzm Watanabe; +Cc: David Miller, netdev, stephen
In-Reply-To: <878uxbjl4n.wl%atzm@stratosphere.co.jp>
On Wed, 2013-10-30 at 16:03 +0900, Atzm Watanabe wrote:
[...]
> Should it be structures as below?
>
> struct tpacket_hdr_variant1 {
> __u32 tp_rxhash;
> __u32 tp_vlan_tci;
> };
>
> struct tpacket_hdr_variant2 {
> __u32 tp_rxhash;
> __u32 tp_vlan_tci;
> __u32 tp_vlan_tpid;
> };
>
> struct tpacket3_hdr {
> __u32 tp_next_offset;
> __u32 tp_sec;
> __u32 tp_nsec;
> __u32 tp_snaplen;
> __u32 tp_len;
> __u32 tp_status;
> __u16 tp_mac;
> __u16 tp_net;
> /* pkt_hdr variants */
> union {
> struct tpacket_hdr_variant1 hv1;
> struct tpacket_hdr_variant2 hv2;
> };
> };
>
> If it's ok, I'd like to send the patch v2.
[...]
I think this makes sense.
Also add a BUILD_BUG_ON(TPACKET3_HDRLEN != 48) somewhere.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH RFC] ipv6: enable IPV6_FLOWLABEL_MGR for getsockopt
From: Florent Fourcot @ 2013-11-04 17:09 UTC (permalink / raw)
To: Hannes Frederic Sowa, netdev
In-Reply-To: <20131104000425.GB8832@order.stressinduktion.org>
> We should take ip6_fl_lock here, otherwise expires extraction races with
> the garbage collector (which can update it). There seem to be some other
> unsafe places, e.g. fl6_renew.
>
I will fix it, and for fl6_renew too.
>> + freq->flr_label = sfl->fl->label;
>> + freq->flr_dst = sfl->fl->dst;
>> + freq->flr_share = sfl->fl->share;
>> + freq->flr_expires = (sfl->fl->expires - jiffies) / HZ;
>> + freq->flr_linger = sfl->fl->linger / HZ;
>> +
>> + rcu_read_unlock_bh();
>> + return 0;
>> + }
>> + }
>> + rcu_read_unlock_bh();
>> +
>> + return 0;
>
> Maybe return -EINVAL for not found?
>
I don't like -EINVAL for this case, since the user can not know if there
are no label or if the request has bad parameters. Could -ENOMSG be OK?
>> + case IPV6_FLOWLABEL_MGR:
>> + {
>> + struct in6_flowlabel_req freq;
>> +
>
> Can you think about other actions one might do with this getsockopt? Maybe
> we should copy_from_user freq and check if action specifies a GET
> request. So a further extension to this API won't break users which did
> pass uninitialized memory to this getsockopt.
>
Very good idea.
Regards,
--
Florent.
^ permalink raw reply
* Re: [PATCH v4 net-next] net: introduce dev_set_forwarding()
From: Ben Hutchings @ 2013-11-04 16:55 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, christoph.paasch, herbert, netdev, hkchu, mwdalton
In-Reply-To: <1383422330.4291.58.camel@edumazet-glaptop2.roam.corp.google.com>
On Sat, 2013-11-02 at 12:58 -0700, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> Christoph Paasch and Jerry Chu reported crashes in skb_segment() caused
> by commit 8a29111c7ca6 ("net: gro: allow to build full sized skb")
>
> skb_segment() only deals with a frag_list chain containing MSS sized
> fragments. Even if we fix this problem, its better if GRO layer
> doesn't build skb with a frag_list in the first place, to let TSO
> packets reaching output devices.
>
> David Miller and Ben Hutchings suggested we keep track of number of
> forwarding users to be able to :
>
> - Disable LRO
> - Make sure GRO layer do not use skb frag_list to extend skb capacity
>
> Note that after this patch, LRO is automatically re-enabled if
> forwarding is disabled on the device, or if a device is removed
> from a bridge.
[...]
Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [PATCH net-next 3/3] lib: crc32: reduce number of cases for crc32{,c}_combine
From: Daniel Borkmann @ 2013-11-04 16:10 UTC (permalink / raw)
To: davem; +Cc: netdev, fengguang.wu
In-Reply-To: <cover.1383580331.git.dborkman@redhat.com>
We can safely reduce the number of test cases by a tenth.
There is no particular need to run as many as we're running
now for crc32{,c}_combine, that gives us still ~8000 tests
we're doing if people run kernels with crc selftests enabled
which is perfectly fine.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
lib/crc32.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/crc32.c b/lib/crc32.c
index 3a1dfa8..70f00ca 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -1037,7 +1037,7 @@ static int __init crc32c_combine_test(void)
int i, j;
int errors = 0, runs = 0;
- for (i = 0; i < 100; i++) {
+ for (i = 0; i < 10; i++) {
u32 crc_full;
crc_full = __crc32c_le(test[i].crc, test_buf + test[i].start,
@@ -1131,7 +1131,7 @@ static int __init crc32_combine_test(void)
int i, j;
int errors = 0, runs = 0;
- for (i = 0; i < 100; i++) {
+ for (i = 0; i < 10; i++) {
u32 crc_full;
crc_full = crc32_le(test[i].crc, test_buf + test[i].start,
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 2/3] lib: crc32: conditionally resched when running testcases
From: Daniel Borkmann @ 2013-11-04 16:10 UTC (permalink / raw)
To: davem; +Cc: netdev, fengguang.wu
In-Reply-To: <cover.1383580331.git.dborkman@redhat.com>
Fengguang reports that when crc32 selftests are running on startup, on
some e.g. 32bit systems, we can get a CPU stall like "INFO: rcu_sched
self-detected stall on CPU { 0} (t=2101 jiffies g=4294967081 c=4294967080
q=41)". As this is not intended, add a cond_resched() at the end of a
test case to fix it. Introduced by efba721f63 ("lib: crc32: add test cases
for crc32{, c}_combine routines").
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
lib/crc32.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/crc32.c b/lib/crc32.c
index 69dd124..3a1dfa8 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -29,6 +29,7 @@
#include <linux/crc32.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include "crc32defs.h"
#if CRC_LE_BITS > 8
@@ -1054,6 +1055,7 @@ static int __init crc32c_combine_test(void)
crc_full == test[i].crc32c_le))
errors++;
runs++;
+ cond_resched();
}
}
@@ -1147,6 +1149,7 @@ static int __init crc32_combine_test(void)
crc_full == test[i].crc_le))
errors++;
runs++;
+ cond_resched();
}
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 1/3] net: checksum: fix warning in skb_checksum
From: Daniel Borkmann @ 2013-11-04 16:10 UTC (permalink / raw)
To: davem; +Cc: netdev, fengguang.wu
In-Reply-To: <cover.1383580331.git.dborkman@redhat.com>
This patch fixes a build warning in skb_checksum() by wrapping the
csum_partial() usage in skb_checksum(). The problem is that on a few
architectures, csum_partial is used with prefix asmlinkage whereas
on most architectures it's not. So fix this up generically as we did
with csum_block_add_ext() to match the signature. Introduced by
2817a336d4d ("net: skb_checksum: allow custom update/combine for
walking skb").
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
Only net-next affected, nothing else.
include/net/checksum.h | 5 +++++
net/core/skbuff.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 15f33fd..37a0e24 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -98,6 +98,11 @@ static inline __wsum csum_unfold(__sum16 n)
return (__force __wsum)n;
}
+static inline __wsum csum_partial_ext(const void *buff, int len, __wsum sum)
+{
+ return csum_partial(buff, len, sum);
+}
+
#define CSUM_MANGLED_0 ((__force __sum16)0xffff)
static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 31aab53..e411559 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2003,7 +2003,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
int len, __wsum csum)
{
const struct skb_checksum_ops ops = {
- .update = csum_partial,
+ .update = csum_partial_ext,
.combine = csum_block_add_ext,
};
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 0/3] crc/csum follow-ups
From: Daniel Borkmann @ 2013-11-04 16:10 UTC (permalink / raw)
To: davem; +Cc: netdev, fengguang.wu
Daniel Borkmann (3):
net: checksum: fix warning in skb_checksum
lib: crc32: conditionally resched when running testcases
lib: crc32: reduce number of tests for crc32{,c}_combine
include/net/checksum.h | 5 +++++
lib/crc32.c | 7 +++++--
net/core/skbuff.c | 2 +-
3 files changed, 11 insertions(+), 3 deletions(-)
--
1.8.3.1
^ permalink raw reply
* Re: [PATCH net-next 5/5] net: sctp: fix and consolidate SCTP checksumming code
From: Vlad Yasevich @ 2013-11-04 16:10 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: davem, netdev, linux-sctp
In-Reply-To: <52778EF6.4000801@redhat.com>
On 11/04/2013 07:11 AM, Daniel Borkmann wrote:
> On 10/30/2013 03:29 PM, Vlad Yasevich wrote:
>> On 10/30/2013 06:50 AM, Daniel Borkmann wrote:
> [...]
>> Daniel
>>
>> Here is a follow-on idea that might help even more.
>> What if we put a pointer to skb_checksum_ops() in the skb
>> somewhere (I was thinking of skb_shinfo). Then
>> skb_checksum can simply use the data from there. This would
>> allow us to get rid of all the special cases in SCTP that do
>> checksumming. We can just set it to partial, set up the right
>> fields and let HW or SW always do the right thing.
>
> I need to think about this a bit. This would certainly have the
> negative side-effect of a higher skb->truesize usage and thus
> affecting memory accounting for everyone as we extend
> skb_shared_info.
You are talking a single pointer here... The alternative
is to do a per-protocol table.
-vlad
^ permalink raw reply
* Re: [patch net-next RFC] netfilter: ip6_tables: use reasm skb for matching
From: Jiri Pirko @ 2013-11-04 15:22 UTC (permalink / raw)
To: Florian Westphal
Cc: netdev, davem, pablo, netfilter-devel, yoshfuji, kadlec, kaber,
mleitner
In-Reply-To: <20131030144400.GE16615@breakpoint.cc>
Wed, Oct 30, 2013 at 03:44:00PM CET, fw@strlen.de wrote:
>Jiri Pirko <jiri@resnulli.us> wrote:
>> >This is a bit backwards, I think.
>> >- We gather frags
>> >- Then we invoke ip6t_do_table for each individual fragment
>> >
>> >So basically your patch is equivalent to
>> >for_each_frag( )
>> > ip6t_do_table(reassembled_skb)
>> >
>> >Which makes no sense to me - why traverse the ruleset n times with the same
>> >packet?
>>
>> Because each fragment need to be pushed through separately.
>
>Why? AFAIU we only need to ensure that (in forwarding case) we
>send out the original fragments instead of the reassembled packet.
I don't knot why, that's the way it is done now. From the top of my head
I can't think of any scenario why it would hurt to push the reassebled
packet instead (and of course send out original fragments at the end of
the way for forwarding)
>
>> What different approach would you suggest?
>
>I am sure that current behaviour is intentional, so I'd first like to
>understand WHY this was implemented this way.
>
>Also, this would change very long standing behaviour so one might argue that
>this is a no-go anyway.
Can you think aof any sane use case this change could possible break?
>
>What is the exact problem that this is supposed to solve?
Look at the patch description. There's an example. The problem is that
fragments are not correctly matched.
^ permalink raw reply
* Re: [PATCH/RFC net] ipv6: fix fragmentation bug
From: Eric Dumazet @ 2013-11-04 14:25 UTC (permalink / raw)
To: Alexander Aring; +Cc: davem, kuznet, jmorris, yoshfuji, kaber, netdev
In-Reply-To: <1383557174-19424-2-git-send-email-alex.aring@gmail.com>
On Mon, 2013-11-04 at 10:26 +0100, Alexander Aring wrote:
> In a very poor 6lowpan wireless connection I got this:
>
> I think we need to drop skb_dst_drop(skb) in ip6_frag_queue because we
> send a icmp6_send in the expire function "ip6_expire_frag_queue":
>
> icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME,
> 0);
>
> and it can be that the skb is already freed. This null pointer
> dereference occurs when the timer expires.
>
> Signed-off-by: Alexander Aring <alex.aring@gmail.com>
> ---
> net/ipv6/reassembly.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
> index cc85a9b..6463ae0 100644
> --- a/net/ipv6/reassembly.c
> +++ b/net/ipv6/reassembly.c
> @@ -352,7 +352,6 @@ found:
> return res;
> }
>
> - skb_dst_drop(skb);
> inet_frag_lru_move(&fq->q);
> return -1;
>
Well, no, this call is needed, please check commit
97599dc792b45b1669c3cdb9a4b365aad0232f65
(" net: drop dst before queueing fragments")
for details.
^ permalink raw reply
* Re: [PATCH v3 net-next] net: introduce dev_set_forwarding()
From: Eric Dumazet @ 2013-11-04 13:58 UTC (permalink / raw)
To: Herbert Xu
Cc: Ben Hutchings, David Miller, christoph.paasch, netdev, hkchu,
mwdalton
In-Reply-To: <20131104072155.GA24303@gondor.apana.org.au>
On Mon, 2013-11-04 at 15:21 +0800, Herbert Xu wrote:
> On Sun, Nov 03, 2013 at 11:10:41PM -0800, Eric Dumazet wrote:
> >
> > Using frag_list for skb meant to be delivered to local stack is mostly
> > fine. Its for forwarding that its not a win, since no driver actually
> > supports frag_list and we revert to skb_segment().
>
> Sigh.
>
> Most of the gain these days isn't coming from the hardware anymore,
> especially for virtualisation where the network stack is at least
> twice as long. The gain is in paying the cost of the network once
> instead of n times for an aggregation of n packets. So with your
> mega-GRO patch, the choice comes down to paying for one trip or
> three trips. The difference may not be trivial, even for a router.
I do think we are on the same thoughts.
Please take a look at 2613af0ed18a11d5c566a81f9a6510b73180660a
("virtio_net: migrate mergeable rx buffers to page frag allocators")
Notice it also uses frag_list
So if you don't provide a skb_segment() patch, I will.
I had urgent matters last week.
^ permalink raw reply
* Re: [PATCH] phy: Add MOXA RTL8201CP PHY support
From: Jonas Jensen @ 2013-11-04 13:50 UTC (permalink / raw)
To: Florian Fainelli
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
netdev
In-Reply-To: <CAGVrzcYfdChFNgkh=VAFZQfCRHyNTe_pZxx1Z6Sz1S8_1vzgtA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Thanks for the replies.
On 1 November 2013 18:01, Florian Fainelli <florian-p3rKhJxN3npAfugRpC6u6w@public.gmane.org> wrote:
>> + dev_err(&bus->dev, "%s timed out\n", __func__);
>
> I would keep these as a debugging aid and not spawn error messages on
> the console by default.
Done.
>> + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
>
> If you only support device tree probing, this might be fine, but you
> might want to be safe in case someone does a !OF instantiation and
> also use pdev->id as an additional unique identifier, so something
> like:
>
> %s-%d-mii, pdev->name, pdev->id
>
> will work.
Done.
>> + /* Setting PHY_IGNORE_INTERRUPT here even if it has no effect,
>> + * of_mdiobus_register() sets these PHY_POLL.
>> + * Ideally, the interrupt from MAC controller could be used to
>> + * detect link state changes, not polling, i.e. if there was
>> + * a way phy_driver could set PHY_HAS_INTERRUPT but have that
>> + * interrupt handled in ethernet drivercode.
>> + */
>> + for (i = 0; i < PHY_MAX_ADDR; i++)
>> + bus->irq[i] = PHY_IGNORE_INTERRUPT;
>
> This type of configuration where the PHY interrupt is actually
> serviced by a link interrupt bit in the Ethernet MAC driver now works
> since 5ea94e768 ("phy: add phy_mac_interrupt() to use with
> PHY_IGNORE_INTERRUPT") so setting PHY_IGNORE_INTERRUPT is the right
> way to signal this and this will no longer make the PHY library poll
> for the link state.
Yes, I tried using phy_mac_interrupt() but had some difficulties (I'll
explain below). It seemed to be what I want and is wrapped with
EXPORT_SYMBOL().
However, as of next-20131104 I don't see how this works for DT probed
devices (those that set PHY_IGNORE_INTERRUPT).
As I tried to explain in my comment, of_mdiobus_register() assigns
PHY_POLL to the IRQ array:
drivers/of/of_mdio.c
..
int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
{
..
/* Clear all the IRQ properties */
if (mdio->irq)
for (i=0; i<PHY_MAX_ADDR; i++)
mdio->irq[i] = PHY_POLL;
..
for_each_available_child_of_node(np, child) {
..
if (mdio->irq) {
mdio->irq[addr] = irq_of_parse_and_map(child, 0);
if (!mdio->irq[addr])
mdio->irq[addr] = PHY_POLL;
}
..
PHY_IGNORE_INTERRUPT || PHY_POLL is not a valid interrupt.
The library ends up toggling (polling) between PHY_RUNNING and PHY_CHANGELINK:
drivers/net/phy/phy.c:
..
void phy_state_machine(struct work_struct *work)
{
..
case PHY_RUNNING:
pr_info("%s: %s: PHY_RUNNING\n", __func__,
dev_name(&phydev->dev));
/* Only register a CHANGE if we are
* polling or ignoring interrupts
*/
if (!phy_interrupt_is_valid(phydev))
phydev->state = PHY_CHANGELINK;
break;
..
include/linux/phy.h:
..
static inline bool phy_interrupt_is_valid(struct phy_device *phydev)
{
return phydev->irq != PHY_POLL && phydev->irq != PHY_IGNORE_INTERRUPT;
}
..
This is why I ended up setting PHY_IGNORE_INTERRUPT and the comment
about its effectiveness. Polling works but the extra reads on the bus
seem unnecessary.
Ideas how they can be eliminated are appreciated.
Another problem, when phy_mac_interrupt() is called from NAPI it looks
like it's trying to take a lock it already has. I tried moving it out
of poll, placing it directly in IRQ handler, with the same result:
[ 18.230000] moxart-ethernet 90900000.mac eth0: moxart_poll: PHYSTS_CHG
[ 18.240000]
[ 18.240000] =================================
[ 18.240000] [ INFO: inconsistent lock state ]
[ 18.240000] 3.12.0-rc7-next-20131104+ #1067 Not tainted
[ 18.240000] ---------------------------------
[ 18.240000] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
[ 18.240000] kworker/0:1/123 [HC0[0]:SC0[0]:HE1:SE1] takes:
[ 18.240000] ((&dev->phy_queue)){+.?...}, at: [<c0028c08>]
process_one_work+0x13c/0x430
[ 18.240000] {IN-SOFTIRQ-W} state was registered at:
[ 18.240000] [<c0055648>] mark_lock+0x144/0x670
[ 18.240000] [<c005777c>] __lock_acquire+0x5e4/0x1c24
[ 18.240000] [<c00592cc>] lock_acquire+0x6c/0x80
[ 18.240000] [<c002a024>] flush_work+0x44/0x278
[ 18.240000] [<c002a2e0>] __cancel_work_timer+0x88/0x124
[ 18.240000] [<c002a390>] cancel_work_sync+0x14/0x18
[ 18.240000] [<c01b0190>] phy_mac_interrupt+0x20/0x40
[ 18.240000] [<c01b3450>] moxart_poll+0x2b4/0x4b4
[ 18.240000] [<c01fe3c8>] net_rx_action+0x130/0x22c
[ 18.240000] [<c00174cc>] __do_softirq+0xe8/0x238
[ 18.240000] [<c0017a2c>] irq_exit+0xac/0xfc
[ 18.240000] [<c0009b40>] handle_IRQ+0x3c/0x8c
[ 18.240000] [<c0008534>] handle_irq+0x98/0xa8
[ 18.240000] [<c000c478>] __irq_svc+0x38/0x68
[ 18.240000] [<c00487ec>] rcu_idle_exit+0x78/0xdc
[ 18.240000] [<c0040618>] cpu_startup_entry+0x88/0x130
[ 18.240000] [<c026d3c8>] rest_init+0xb8/0xe0
[ 18.240000] [<c033ea1c>] start_kernel+0x298/0x2dc
[ 18.240000] irq event stamp: 2659
[ 18.240000] hardirqs last enabled at (2659): [<c0276298>]
_raw_spin_unlock_irq+0x2c/0x60
[ 18.240000] hardirqs last disabled at (2658): [<c02760f0>]
_raw_spin_lock_irq+0x28/0x78
[ 18.240000] softirqs last enabled at (2654): [<c0017568>]
__do_softirq+0x184/0x238
[ 18.240000] softirqs last disabled at (2637): [<c0017a2c>] irq_exit+0xac/0xfc
[ 18.240000]
[ 18.240000] other info that might help us debug this:
[ 18.240000] Possible unsafe locking scenario:
[ 18.240000]
[ 18.240000] CPU0
[ 18.240000] ----
[ 18.240000] lock([ 18.240000] moxart-ethernet 90900000.mac
eth0: TX ring end reached
[ 18.240000] (&dev->phy_queue));
[ 18.240000] <Interrupt>
[ 18.240000] lock((&dev->phy_queue));
[ 18.240000]
[ 18.240000] *** DEADLOCK ***
[ 18.240000]
[ 18.240000] 1 lock held by kworker/0:1/123:
[ 18.240000] #0: (events){.+.+..}, at: [<c0028c08>]
process_one_work+0x13c/0x430
[ 18.240000]
[ 18.240000] stack backtrace:
[ 18.240000] CPU: 0 PID: 123 Comm: kworker/0:1 Not tainted
3.12.0-rc7-next-20131104+ #1067
[ 18.240000] Workqueue: events phy_change
[ 18.240000] [<c000d214>] (unwind_backtrace+0x0/0xf4) from
[<c000b964>] (show_stack+0x18/0x1c)
[ 18.240000] [<c000b964>] (show_stack+0x18/0x1c) from [<c0271614>]
(dump_stack+0x20/0x28)
[ 18.240000] [<c0271614>] (dump_stack+0x20/0x28) from [<c026fee0>]
(print_usage_bug.part.26+0x220/0x288)
[ 18.240000] [<c026fee0>] (print_usage_bug.part.26+0x220/0x288) from
[<c0055b3c>] (mark_lock+0x638/0x670)
[ 18.240000] [<c0055b3c>] (mark_lock+0x638/0x670) from [<c00577c4>]
(__lock_acquire+0x62c/0x1c24)
[ 18.240000] [<c00577c4>] (__lock_acquire+0x62c/0x1c24) from
[<c00592cc>] (lock_acquire+0x6c/0x80)
[ 18.240000] [<c00592cc>] (lock_acquire+0x6c/0x80) from [<c0028c70>]
(process_one_work+0x1a4/0x430)
[ 18.240000] [<c0028c70>] (process_one_work+0x1a4/0x430) from
[<c0029304>] (worker_thread+0x13c/0x3dc)
[ 18.240000] [<c0029304>] (worker_thread+0x13c/0x3dc) from
[<c002f500>] (kthread+0xb8/0xd4)
[ 18.240000] [<c002f500>] (kthread+0xb8/0xd4) from [<c0009360>]
(ret_from_fork+0x14/0x34)
[ 18.610000] libphy: phy_change
>> + ret = of_mdiobus_register(bus, np);
>> + if (ret < 0)
>> + return ret;
>
> You still need to call mdiobus_free() here in case registration fails.
Done.
>> +/* RTL8201CP */
>> +static struct phy_driver rtl8201cp_driver = {
>> + .phy_id = 0x00008201,
>> + .name = "RTL8201CP Ethernet",
>> + .phy_id_mask = 0x0000ffff,
>> + .features = PHY_BASIC_FEATURES,
>
> If this PHY is internal to your SoC (same die/package) you should also
> add PHY_IS_INTERNAL to get a consistent ethtool reporting (among
> others).
I was wondering about that, and now I'm sure it should not be set, the
physical chip is separate, as can be seen here:
https://lh4.googleusercontent.com/-A-2FXDrObU8/UMcMc_K2vEI/AAAAAAAABwg/ldaLZ7ps1P4/w1331-h998-no/UC-7112-LX-picture4.jpg
Best regards,
Jonas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [patch] netfilter: nf_tables: use _safe version of list_for_each
From: Dan Carpenter @ 2013-11-04 12:58 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Patrick McHardy, Jozsef Kadlecsik, David S. Miller,
netfilter-devel, netfilter, coreteam, netdev, kernel-janitors
We need to use the _safe version of list_for_each_entry() here otherwise
we have a use after free bug.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
index 4811f76..a82667c 100644
--- a/net/netfilter/nft_compat.c
+++ b/net/netfilter/nft_compat.c
@@ -634,9 +634,9 @@ nft_match_select_ops(const struct nft_ctx *ctx,
static void nft_match_release(void)
{
- struct nft_xt *nft_match;
+ struct nft_xt *nft_match, *tmp;
- list_for_each_entry(nft_match, &nft_match_list, head)
+ list_for_each_entry_safe(nft_match, tmp, &nft_match_list, head)
kfree(nft_match);
}
@@ -705,9 +705,9 @@ nft_target_select_ops(const struct nft_ctx *ctx,
static void nft_target_release(void)
{
- struct nft_xt *nft_target;
+ struct nft_xt *nft_target, *tmp;
- list_for_each_entry(nft_target, &nft_target_list, head)
+ list_for_each_entry_safe(nft_target, tmp, &nft_target_list, head)
kfree(nft_target);
}
^ permalink raw reply related
* Re: [PATCH net-next 5/5] net: sctp: fix and consolidate SCTP checksumming code
From: Daniel Borkmann @ 2013-11-04 12:11 UTC (permalink / raw)
To: Vlad Yasevich; +Cc: davem, netdev, linux-sctp
In-Reply-To: <527117C3.2080306@gmail.com>
On 10/30/2013 03:29 PM, Vlad Yasevich wrote:
> On 10/30/2013 06:50 AM, Daniel Borkmann wrote:
[...]
> Daniel
>
> Here is a follow-on idea that might help even more.
> What if we put a pointer to skb_checksum_ops() in the skb
> somewhere (I was thinking of skb_shinfo). Then
> skb_checksum can simply use the data from there. This would
> allow us to get rid of all the special cases in SCTP that do
> checksumming. We can just set it to partial, set up the right
> fields and let HW or SW always do the right thing.
I need to think about this a bit. This would certainly have the
negative side-effect of a higher skb->truesize usage and thus
affecting memory accounting for everyone as we extend
skb_shared_info.
^ permalink raw reply
* Re: [PATCH/RFC net] ipv6: fix fragmentation bug
From: Alexander Aring @ 2013-11-04 9:51 UTC (permalink / raw)
To: Fan Du; +Cc: davem, kuznet, jmorris, yoshfuji, kaber, netdev
In-Reply-To: <52776D10.4020104@windriver.com>
On Mon, Nov 04, 2013 at 05:46:56PM +0800, Fan Du wrote:
>
>
> On 2013年11月04日 17:43, Alexander Aring wrote:
> >Hi,
> >
> >On Mon, Nov 04, 2013 at 05:39:38PM +0800, Fan Du wrote:
> >>> Hi, Alexander
> >>>
> >>> I don't know whether which head commit you are sitting, this issue might has already been fixed by Steffen:
> >>> https://git.kernel.org/cgit/linux/kernel/git/klassert/ipsec.git/commit/?id=84502b5ef9849a9694673b15c31bd3ac693010ae
> >>>
> >>>
> >oh I am using current net-next which haven't this fix.
> >
>
> Since it's a bug fix, so it's in net tree for the moment...
>
Ok, thanks and sorry for the noise...
- Alex
^ permalink raw reply
* RE: [PATCH] x86: Run checksumming in parallel accross multiple alu's
From: David Laight @ 2013-11-04 9:47 UTC (permalink / raw)
To: Neil Horman
Cc: Ben Hutchings, Doug Ledford, Ingo Molnar, Eric Dumazet,
linux-kernel, netdev
In-Reply-To: <20131101173701.GC8467@hmsreliant.think-freely.org>
> > I think you need 3 instructions, move a 0, conditionally move a 1
> > then add. I suspect it won't be a win!
Or, with an appropriately unrolled loop, for each word:
zero %eax, cmove a 1 to %al
cmove a 1 to %ah
shift %eax left, cmove a 1 to %al
cmove a 1 to %ah, add %eax onto somewhere.
However the 2nd instruction stream would have to use a different
register (IIRC 8bit updates depend on the entire register).
> I agree, that sounds interesting, but very cpu dependent. Thanks for the
> suggestion, Ben, but I think it would be better if we just did the prefetch here
> and re-addressed this area when AVX (or addcx/addox) instructions were available
> for testing on hardware.
I didn't look too closely at the original figures.
With a simple loop you need 4 instructions per iteration (load, adc, inc, branch).
How close to one iteration per clock do you get?
I thought x86 hardware prefetch would load the cache lines for sequential
accesses - so any prefetch instructions are rather pointless.
However reading the value in the previous loop iteration should help.
I've just realised that there is a problem with the loop termination
condition also needing the flags register:-(
I don't remember the 'loop' instruction ever being added to any of the
fast path instruction decodes - so it won't help.
So I suspect the best you'll get is an interleaved sequence of load and adc
with an lea and inc (both to adjust the index) and a bne back to the top.
(the lea wants to be in the middle somewhere).
That might manage 1 clock per word + 1 clock per loop iteration (if the inc
and bne can be 'fused').
David
^ permalink raw reply
* Re: [PATCH/RFC net] ipv6: fix fragmentation bug
From: Fan Du @ 2013-11-04 9:46 UTC (permalink / raw)
To: Alexander Aring; +Cc: davem, kuznet, jmorris, yoshfuji, kaber, netdev
In-Reply-To: <20131104094303.GA20131@omega>
On 2013年11月04日 17:43, Alexander Aring wrote:
> Hi,
>
> On Mon, Nov 04, 2013 at 05:39:38PM +0800, Fan Du wrote:
>> > Hi, Alexander
>> >
>> > I don't know whether which head commit you are sitting, this issue might has already been fixed by Steffen:
>> > https://git.kernel.org/cgit/linux/kernel/git/klassert/ipsec.git/commit/?id=84502b5ef9849a9694673b15c31bd3ac693010ae
>> >
>> >
> oh I am using current net-next which haven't this fix.
>
Since it's a bug fix, so it's in net tree for the moment...
--
浮沉随浪只记今朝笑
--fan
^ permalink raw reply
* Re: [PATCH/RFC net] ipv6: fix fragmentation bug
From: Alexander Aring @ 2013-11-04 9:43 UTC (permalink / raw)
To: Fan Du; +Cc: davem, kuznet, jmorris, yoshfuji, kaber, netdev
In-Reply-To: <52776B5A.6030701@windriver.com>
Hi,
On Mon, Nov 04, 2013 at 05:39:38PM +0800, Fan Du wrote:
> Hi, Alexander
>
> I don't know whether which head commit you are sitting, this issue might has already been fixed by Steffen:
> https://git.kernel.org/cgit/linux/kernel/git/klassert/ipsec.git/commit/?id=84502b5ef9849a9694673b15c31bd3ac693010ae
>
>
oh I am using current net-next which haven't this fix.
Thanks
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox