Netdev List
 help / color / mirror / Atom feed
* Re: [patch net-next-2.6 4/4] bridge: implement slave management operations
From: Jiri Pirko @ 2011-03-01  6:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Stephen Hemminger, netdev, davem, kaber, fubar
In-Reply-To: <20110228144516.0174a9c8@nehalam>

Mon, Feb 28, 2011 at 11:45:16PM CET, shemminger@vyatta.com wrote:
>On Mon, 28 Feb 2011 14:17:29 -0800
>Stephen Hemminger <shemminger@linux-foundation.org> wrote:
>
>> On Fri, 11 Feb 2011 16:23:47 +0100
>> Jiri Pirko <jpirko@redhat.com> wrote:
>> 
>> > 
>> > Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>> 
>
>Never mind, this is good. I was confusing slave with bridge initialization
>and netdevice ops with ethtool ops.
>
>Ethtool ops seems to be growing like weeds lately...


This was replaced by:
bridge: implement [add/del]_slave ops


never intended to be in ethtool
>
>
>
>-- 

^ permalink raw reply

* [patch net-next-2.6] bonding: remove skb_share_check in handle_frame
From: Jiri Pirko @ 2011-03-01  6:22 UTC (permalink / raw)
  To: netdev; +Cc: davem, fubar, eric.dumazet, nicolas.2p.debian, andy

No need to do share check here since call to netif_rx was removed and
skb is passed back.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
 drivers/net/bonding/bond_main.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f3e5d7f..e8c0f95 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1503,10 +1503,6 @@ static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
 	if (unlikely(!slave))
 		return skb;
 
-	skb = skb_share_check(skb, GFP_ATOMIC);
-	if (unlikely(!skb))
-		return NULL;
-
 	bond_dev = ACCESS_ONCE(skb->dev->master);
 	if (unlikely(!bond_dev))
 		return skb;
-- 
1.7.3.4


^ permalink raw reply related

* net: allow handlers to be processed for orig_dev
From: Jiri Pirko @ 2011-03-01  6:26 UTC (permalink / raw)
  To: netdev
  Cc: davem, shemminger, kaber, fubar, eric.dumazet, nicolas.2p.debian,
	andy

This was there before, I forgot about this. Allows deliveries to
ptype_base handlers registered for orig_dev. I presume this is still
desired.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
 net/core/dev.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 30440e7..9f66de9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3208,7 +3208,8 @@ ncls:
 	list_for_each_entry_rcu(ptype,
 			&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
 		if (ptype->type == type &&
-		    (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+		    (ptype->dev == null_or_dev || ptype->dev == skb->dev ||
+		     ptype->dev == orig_dev)) {
 			if (pt_prev)
 				ret = deliver_skb(skb, pt_prev, orig_dev);
 			pt_prev = ptype;
-- 
1.7.3.4


^ permalink raw reply related

* Re: [Open-FCoE] [PATCH] fcoe: correct checking for bonding
From: Jiri Pirko @ 2011-03-01  6:37 UTC (permalink / raw)
  To: Joe Eykholt; +Cc: Jay Vosburgh, James.Bottomley, netdev, devel, linux-scsi
In-Reply-To: <4D6BE155.7050109@gmail.com>

Mon, Feb 28, 2011 at 06:54:29PM CET, joe.eykholt@gmail.com wrote:
>On 2/28/11 9:15 AM, Jay Vosburgh wrote:
>>Jiri Pirko<jpirko@redhat.com>  wrote:
>>
>>>Check for IFF_BONDING as this flag is set-up for all bonding devices.
>>>
>>>Signed-off-by: Jiri Pirko<jpirko@redhat.com>
>>>---
>>>drivers/scsi/fcoe/fcoe.c |    4 +---
>>>1 files changed, 1 insertions(+), 3 deletions(-)
>>>
>>>diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
>>>index 9f9600b..67714a4 100644
>>>--- a/drivers/scsi/fcoe/fcoe.c
>>>+++ b/drivers/scsi/fcoe/fcoe.c
>>>@@ -285,9 +285,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
>>>	}
>>>
>>>	/* Do not support for bonding device */
>>>-	if ((netdev->priv_flags&  IFF_MASTER_ALB) ||
>>>-	    (netdev->priv_flags&  IFF_SLAVE_INACTIVE) ||
>>>-	    (netdev->priv_flags&  IFF_MASTER_8023AD)) {
>>>+	if (netdev->priv_flags&  IFF_BONDING) {
>>>		FCOE_NETDEV_DBG(netdev, "Bonded interfaces not supported\n");
>>>		return -EOPNOTSUPP;
>>>	}
>>
>>	Based on past discussions, I believe the intent of the code is
>>to permit FCOE over bonding only for active-backup mode, and possibly
>>for -xor/-rr as well.
>>
>>	I'm not sure if the slave or the master is what's being tested
>>here, so I'm not sure what the right thing to do is.  I suspect it's the
>>master, as I recall discussion of one configuration involving
>>active-backup mode balancing FCOE traffic over both the active and
>>inactive slaves.  FCOE uses the "orig_dev" logic in __netif_receive_skb
>>to have the packets delivered even on the nominally inactive slave.
>>
>>	-J
>>
>>---
>>	-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
>
>Right.  That was the intent.  It should work on the physical dev, but probably
>not on the master of the bond.
>
>If you have a master/slave bond for IPv4 between eth1 and eth2, say,
>and they are going to two different DCE (FCoE) switches, presumably on
>different VSANs but with ultimate access to the same disks,
>then you want to split the FCoE traffic in active/active
>mode using separate FCoE instances on eth1 and eth2 even though IP
>is using active/standby on bond0.  This should work.  But, putting fcoe
>on bond0 isn't going to do what you want.
>
>However, it seems like the check above shouldn't be checking
>IFF_SLAVE_INACTIVE.   I can't test this.

OK. So I guess the right check should be for:
(netdev->priv_flags & IFF_BONDING && netdev->flags & IFF_MASTER)

This would disable adding all bond devices (like bond0 etc) and allows
to use enslaved physdevs.

Note that checking for mode is irrelevant here. Mode could be easily
changed later without fcoe knowing that.

Jirka
>
>	Joe
>

^ permalink raw reply

* Re: net: allow handlers to be processed for orig_dev
From: Jiri Pirko @ 2011-03-01  6:43 UTC (permalink / raw)
  To: netdev; +Cc: davem
In-Reply-To: <20110301062631.GC2855@psychotron.redhat.com>

ou, forgot [PATCH net-next-2.6] - sorry

Tue, Mar 01, 2011 at 07:26:31AM CET, jpirko@redhat.com wrote:
>This was there before, I forgot about this. Allows deliveries to
>ptype_base handlers registered for orig_dev. I presume this is still
>desired.
>
>Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>---
> net/core/dev.c |    3 ++-
> 1 files changed, 2 insertions(+), 1 deletions(-)
>
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 30440e7..9f66de9 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -3208,7 +3208,8 @@ ncls:
> 	list_for_each_entry_rcu(ptype,
> 			&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
> 		if (ptype->type == type &&
>-		    (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
>+		    (ptype->dev == null_or_dev || ptype->dev == skb->dev ||
>+		     ptype->dev == orig_dev)) {
> 			if (pt_prev)
> 				ret = deliver_skb(skb, pt_prev, orig_dev);
> 			pt_prev = ptype;
>-- 
>1.7.3.4
>

^ permalink raw reply

* [PATCH] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Po-Yu Chuang @ 2011-03-01  6:48 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, bhutchings, eric.dumazet, joe, dilinger, mirqus,
	davem, Po-Yu Chuang
In-Reply-To: <1298627845-1583-1-git-send-email-ratbert.chuang@gmail.com>

From: Po-Yu Chuang <ratbert@faraday-tech.com>

FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
MII.  This driver has been working on some ARM/NDS32 SoC's including
Faraday A320 and Andes AG101.

Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
---
v2:
always use NAPI
do not use our own net_device_stats structure
don't set trans_start and last_rx
stats.rx_packets and stats.rx_bytes include dropped packets
add missed netif_napi_del()
initialize spinlocks in probe function
remove rx_lock and hw_lock
use netdev_[err/info/dbg] instead of dev_* ones
use netdev_alloc_skb_ip_align()
remove ftmac100_get_stats()
use is_valid_ether_addr() instead of is_zero_ether_addr()
add const to ftmac100_ethtool_ops and ftmac100_netdev_ops
use net_ratelimit() instead of printk_ratelimit()
no explicit inline
use %pM to print MAC address
add comment before wmb
use napi poll() to handle all interrupts

v3:
undo "stats.rx_packets and stats.rx_bytes include dropped packets"
ftmac100_mdio_read() returns 0 if error
fix comment typos
use pr_fmt and pr_info
define INT_MASK_ALL_ENABLED
define MACCR_ENABLE_ALL
do not count length error many times
use bool/true/false
use cpu_to_le32/le32_to_cpu to access descriptors
indent style fix

v4:
should not access skb after netif_receive_skb()
use resource_size()
better way to use cpu_to_le32/le32_to_cpu
use spin_lock() for tx_lock
combine all netdev_info() together in ftmac100_poll()

v5:
use dev_kfree_skb() in ftmac100_tx_complete_packet()
cpu_to_le32/le32_to_cpu usage fix
drop GFP_DMA

v6:
cpu_to_le32/le32_to_cpu usage fix
remove "tx queue full" message
reduce critical section protected by tx_lock
add check of MAX_PKT_SIZE and RX_BUF_SIZE
add __exit to ftmac100_remove()
simplify ftmac100_rx_packet()
zero copy - use skb_fill_page_desc() and __pskb_pull_tail().
pull more data to skb head to include tcp/ip header

v7:
allocate 128 bytes skb and pull 64 bytes only

 drivers/net/Kconfig    |    9 +
 drivers/net/Makefile   |    1 +
 drivers/net/ftmac100.c | 1196 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac100.h |  180 ++++++++
 4 files changed, 1386 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/ftmac100.c
 create mode 100644 drivers/net/ftmac100.h

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4f1755b..6b12274 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2014,6 +2014,15 @@ config BCM63XX_ENET
 	  This driver supports the ethernet MACs in the Broadcom 63xx
 	  MIPS chipset family (BCM63XX).
 
+config FTMAC100
+	tristate "Faraday FTMAC100 10/100 Ethernet support"
+	depends on ARM
+	select MII
+	help
+	  This driver supports the FTMAC100 10/100 Ethernet controller
+	  from Faraday. It is used on Faraday A320, Andes AG101 and some
+	  other ARM/NDS32 SoC's.
+
 source "drivers/net/fs_enet/Kconfig"
 
 source "drivers/net/octeon/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b90738d..7c21711 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -147,6 +147,7 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
 obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
 obj-$(CONFIG_AX88796) += ax88796.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_FTMAC100) += ftmac100.o
 
 obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
 obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c
new file mode 100644
index 0000000..df70368
--- /dev/null
+++ b/drivers/net/ftmac100.c
@@ -0,0 +1,1196 @@
+/*
+ * Faraday FTMAC100 10/100 Ethernet
+ *
+ * (C) Copyright 2009-2011 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#include "ftmac100.h"
+
+#define DRV_NAME	"ftmac100"
+#define DRV_VERSION	"0.2"
+
+#define RX_QUEUE_ENTRIES	128	/* must be power of 2 */
+#define TX_QUEUE_ENTRIES	16	/* must be power of 2 */
+
+#define MAX_PKT_SIZE		1518
+#define RX_BUF_SIZE		2044	/* must be smaller than 0x7ff */
+
+#if MAX_PKT_SIZE > 0x7ff
+#error invalid MAX_PKT_SIZE
+#endif
+
+#if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE
+#error invalid RX_BUF_SIZE
+#endif
+
+/******************************************************************************
+ * private data
+ *****************************************************************************/
+struct ftmac100_descs {
+	struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
+	struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES];
+};
+
+struct ftmac100 {
+	struct resource *res;
+	void __iomem *base;
+	int irq;
+
+	struct ftmac100_descs *descs;
+	dma_addr_t descs_dma_addr;
+
+	unsigned int rx_pointer;
+	unsigned int tx_clean_pointer;
+	unsigned int tx_pointer;
+	unsigned int tx_pending;
+
+	spinlock_t tx_lock;
+
+	struct net_device *netdev;
+	struct device *dev;
+	struct napi_struct napi;
+
+	struct mii_if_info mii;
+};
+
+static int ftmac100_alloc_rx_page(struct ftmac100 *priv, struct ftmac100_rxdes *rxdes);
+
+/******************************************************************************
+ * internal functions (hardware register access)
+ *****************************************************************************/
+#define INT_MASK_ALL_ENABLED	(FTMAC100_INT_RPKT_FINISH	| \
+				 FTMAC100_INT_NORXBUF		| \
+				 FTMAC100_INT_XPKT_OK		| \
+				 FTMAC100_INT_XPKT_LOST		| \
+				 FTMAC100_INT_RPKT_LOST		| \
+				 FTMAC100_INT_AHB_ERR		| \
+				 FTMAC100_INT_PHYSTS_CHG)
+
+#define INT_MASK_ALL_DISABLED	0
+
+static void ftmac100_enable_all_int(struct ftmac100 *priv)
+{
+	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR);
+}
+
+static void ftmac100_disable_all_int(struct ftmac100 *priv)
+{
+	iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR);
+}
+
+static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
+{
+	iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR);
+}
+
+static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr)
+{
+	iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR);
+}
+
+static void ftmac100_txdma_start_polling(struct ftmac100 *priv)
+{
+	iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD);
+}
+
+static int ftmac100_reset(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	int i;
+
+	/* NOTE: reset clears all registers */
+	iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR);
+
+	for (i = 0; i < 5; i++) {
+		unsigned int maccr;
+
+		maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR);
+		if (!(maccr & FTMAC100_MACCR_SW_RST)) {
+			/*
+			 * FTMAC100_MACCR_SW_RST cleared does not indicate
+			 * that hardware reset completed (what the f*ck).
+			 * We still need to wait for a while.
+			 */
+			usleep_range(500, 1000);
+			return 0;
+		}
+
+		usleep_range(1000, 10000);
+	}
+
+	netdev_err(netdev, "software reset failed\n");
+	return -EIO;
+}
+
+static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac)
+{
+	unsigned int maddr = mac[0] << 8 | mac[1];
+	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
+
+	iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR);
+	iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR);
+}
+
+#define MACCR_ENABLE_ALL	(FTMAC100_MACCR_XMT_EN	| \
+				 FTMAC100_MACCR_RCV_EN	| \
+				 FTMAC100_MACCR_XDMA_EN	| \
+				 FTMAC100_MACCR_RDMA_EN	| \
+				 FTMAC100_MACCR_CRC_APD	| \
+				 FTMAC100_MACCR_FULLDUP	| \
+				 FTMAC100_MACCR_RX_RUNT	| \
+				 FTMAC100_MACCR_RX_BROADPKT)
+
+static int ftmac100_start_hw(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+
+	if (ftmac100_reset(priv))
+		return -EIO;
+
+	/* setup ring buffer base registers */
+	ftmac100_set_rx_ring_base(priv,
+				  priv->descs_dma_addr +
+				  offsetof(struct ftmac100_descs, rxdes));
+	ftmac100_set_tx_ring_base(priv,
+				  priv->descs_dma_addr +
+				  offsetof(struct ftmac100_descs, txdes));
+
+	iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC);
+
+	ftmac100_set_mac(priv, netdev->dev_addr);
+
+	iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR);
+	return 0;
+}
+
+static void ftmac100_stop_hw(struct ftmac100 *priv)
+{
+	iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR);
+}
+
+/******************************************************************************
+ * internal functions (receive descriptor)
+ *****************************************************************************/
+static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS);
+}
+
+static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS);
+}
+
+static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
+}
+
+static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes)
+{
+	/* clear status bits */
+	rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN);
+}
+
+static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR);
+}
+
+static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR);
+}
+
+static bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL);
+}
+
+static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT);
+}
+
+static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB);
+}
+
+static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes)
+{
+	return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL;
+}
+
+static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes)
+{
+	return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST);
+}
+
+static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes,
+					   unsigned int size)
+{
+	rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR);
+	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size));
+}
+
+static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes)
+{
+	rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR);
+}
+
+static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes,
+					dma_addr_t addr)
+{
+	rxdes->rxdes2 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes)
+{
+	return le32_to_cpu(rxdes->rxdes2);
+}
+
+/*
+ * rxdes3 is not used by hardware. We use it to keep track of page.
+ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
+ */
+static void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page)
+{
+	rxdes->rxdes3 = (unsigned int)page;
+}
+
+static struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes)
+{
+	return (struct page *)rxdes->rxdes3;
+}
+
+/******************************************************************************
+ * internal functions (receive)
+ *****************************************************************************/
+static int ftmac100_next_rx_pointer(int pointer)
+{
+	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
+}
+
+static void ftmac100_rx_pointer_advance(struct ftmac100 *priv)
+{
+	priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer);
+}
+
+static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv)
+{
+	return &priv->descs->rxdes[priv->rx_pointer];
+}
+
+static struct ftmac100_rxdes *
+ftmac100_rx_locate_first_segment(struct ftmac100 *priv)
+{
+	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
+
+	while (!ftmac100_rxdes_owned_by_dma(rxdes)) {
+		if (ftmac100_rxdes_first_segment(rxdes))
+			return rxdes;
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+		ftmac100_rx_pointer_advance(priv);
+		rxdes = ftmac100_current_rxdes(priv);
+	}
+
+	return NULL;
+}
+
+static bool ftmac100_rx_packet_error(struct ftmac100 *priv,
+				     struct ftmac100_rxdes *rxdes)
+{
+	struct net_device *netdev = priv->netdev;
+	bool error = false;
+
+	if (unlikely(ftmac100_rxdes_rx_error(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx err\n");
+
+		netdev->stats.rx_errors++;
+		error = true;
+	}
+
+	if (unlikely(ftmac100_rxdes_crc_error(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx crc err\n");
+
+		netdev->stats.rx_crc_errors++;
+		error = true;
+	}
+
+	if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx frame too long\n");
+
+		netdev->stats.rx_length_errors++;
+		error = true;
+	} else if (unlikely(ftmac100_rxdes_runt(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx runt\n");
+
+		netdev->stats.rx_length_errors++;
+		error = true;
+	} else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) {
+		if (net_ratelimit())
+			netdev_info(netdev, "rx odd nibble\n");
+
+		netdev->stats.rx_length_errors++;
+		error = true;
+	}
+
+	return error;
+}
+
+static void ftmac100_rx_drop_packet(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv);
+	bool done = false;
+
+	if (net_ratelimit())
+		netdev_dbg(netdev, "drop packet %p\n", rxdes);
+
+	do {
+		if (ftmac100_rxdes_last_segment(rxdes))
+			done = true;
+
+		ftmac100_rxdes_set_dma_own(rxdes);
+		ftmac100_rx_pointer_advance(priv);
+		rxdes = ftmac100_current_rxdes(priv);
+	} while (!done && !ftmac100_rxdes_owned_by_dma(rxdes));
+
+	netdev->stats.rx_dropped++;
+}
+
+static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_rxdes *rxdes;
+	struct sk_buff *skb;
+	struct page *page;
+	dma_addr_t map;
+	int length;
+
+	rxdes = ftmac100_rx_locate_first_segment(priv);
+	if (!rxdes)
+		return false;
+
+	if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) {
+		ftmac100_rx_drop_packet(priv);
+		return true;
+	}
+
+	/*
+	 * It is impossible to get multi-segment packets
+	 * because we always provide big enough receive buffers.
+	 */
+	if (unlikely(!ftmac100_rxdes_last_segment(rxdes)))
+		BUG();
+
+	/* start processing */
+	skb = netdev_alloc_skb_ip_align(netdev, 128);
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			netdev_err(netdev, "rx skb alloc failed\n");
+
+		ftmac100_rx_drop_packet(priv);
+		return true;
+	}
+
+	if (unlikely(ftmac100_rxdes_multicast(rxdes)))
+		netdev->stats.multicast++;
+
+	map = ftmac100_rxdes_get_dma_addr(rxdes);
+	dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+	length = ftmac100_rxdes_frame_length(rxdes);
+	page = ftmac100_rxdes_get_page(rxdes);
+	skb_fill_page_desc(skb, 0, page, 0, length);
+	skb->len += length;
+	skb->data_len += length;
+	skb->truesize += length;
+	__pskb_pull_tail(skb, min(length, 64));
+
+	ftmac100_alloc_rx_page(priv, rxdes);
+
+	ftmac100_rx_pointer_advance(priv);
+
+	skb->protocol = eth_type_trans(skb, netdev);
+
+	netdev->stats.rx_packets++;
+	netdev->stats.rx_bytes += skb->len;
+
+	/* push packet to protocol stack */
+	netif_receive_skb(skb);
+
+	(*processed)++;
+	return true;
+}
+
+/******************************************************************************
+ * internal functions (transmit descriptor)
+ *****************************************************************************/
+static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes)
+{
+	/* clear all except end of ring bit */
+	txdes->txdes0 = 0;
+	txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
+	txdes->txdes2 = 0;
+	txdes->txdes3 = 0;
+}
+
+static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
+}
+
+static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes)
+{
+	/*
+	 * Make sure dma own bit will not be set before any other
+	 * descriptor fields.
+	 */
+	wmb();
+	txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN);
+}
+
+static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL);
+}
+
+static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes)
+{
+	return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL);
+}
+
+static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR);
+}
+
+static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS);
+}
+
+static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS);
+}
+
+static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC);
+}
+
+static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes,
+					   unsigned int len)
+{
+	txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len));
+}
+
+static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes,
+					dma_addr_t addr)
+{
+	txdes->txdes2 = cpu_to_le32(addr);
+}
+
+static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes)
+{
+	return le32_to_cpu(txdes->txdes2);
+}
+
+/*
+ * txdes3 is not used by hardware. We use it to keep track of socket buffer.
+ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
+ */
+static void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb)
+{
+	txdes->txdes3 = (unsigned int)skb;
+}
+
+static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes)
+{
+	return (struct sk_buff *)txdes->txdes3;
+}
+
+/******************************************************************************
+ * internal functions (transmit)
+ *****************************************************************************/
+static int ftmac100_next_tx_pointer(int pointer)
+{
+	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
+}
+
+static void ftmac100_tx_pointer_advance(struct ftmac100 *priv)
+{
+	priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer);
+}
+
+static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv)
+{
+	priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer);
+}
+
+static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv)
+{
+	return &priv->descs->txdes[priv->tx_pointer];
+}
+
+static struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv)
+{
+	return &priv->descs->txdes[priv->tx_clean_pointer];
+}
+
+static bool ftmac100_tx_complete_packet(struct ftmac100 *priv)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_txdes *txdes;
+	struct sk_buff *skb;
+	dma_addr_t map;
+
+	if (priv->tx_pending == 0)
+		return false;
+
+	txdes = ftmac100_current_clean_txdes(priv);
+
+	if (ftmac100_txdes_owned_by_dma(txdes))
+		return false;
+
+	skb = ftmac100_txdes_get_skb(txdes);
+	map = ftmac100_txdes_get_dma_addr(txdes);
+
+	if (unlikely(ftmac100_txdes_excessive_collision(txdes) ||
+		     ftmac100_txdes_late_collision(txdes))) {
+		/*
+		 * packet transmitted to ethernet lost due to late collision
+		 * or excessive collision
+		 */
+		netdev->stats.tx_aborted_errors++;
+	} else {
+		netdev->stats.tx_packets++;
+		netdev->stats.tx_bytes += skb->len;
+	}
+
+	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+	dev_kfree_skb(skb);
+
+	ftmac100_txdes_reset(txdes);
+
+	ftmac100_tx_clean_pointer_advance(priv);
+
+	spin_lock(&priv->tx_lock);
+	priv->tx_pending--;
+	spin_unlock(&priv->tx_lock);
+	netif_wake_queue(netdev);
+
+	return true;
+}
+
+static void ftmac100_tx_complete(struct ftmac100 *priv)
+{
+	while (ftmac100_tx_complete_packet(priv))
+		;
+}
+
+static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb,
+			 dma_addr_t map)
+{
+	struct net_device *netdev = priv->netdev;
+	struct ftmac100_txdes *txdes;
+	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+
+	txdes = ftmac100_current_txdes(priv);
+	ftmac100_tx_pointer_advance(priv);
+
+	/* setup TX descriptor */
+	ftmac100_txdes_set_skb(txdes, skb);
+	ftmac100_txdes_set_dma_addr(txdes, map);
+
+	ftmac100_txdes_set_first_segment(txdes);
+	ftmac100_txdes_set_last_segment(txdes);
+	ftmac100_txdes_set_txint(txdes);
+	ftmac100_txdes_set_buffer_size(txdes, len);
+
+	spin_lock(&priv->tx_lock);
+	priv->tx_pending++;
+	if (priv->tx_pending == TX_QUEUE_ENTRIES)
+		netif_stop_queue(netdev);
+
+	/* start transmit */
+	ftmac100_txdes_set_dma_own(txdes);
+	spin_unlock(&priv->tx_lock);
+
+	ftmac100_txdma_start_polling(priv);
+	return NETDEV_TX_OK;
+}
+
+/******************************************************************************
+ * internal functions (buffer)
+ *****************************************************************************/
+static int ftmac100_alloc_rx_page(struct ftmac100 *priv, struct ftmac100_rxdes *rxdes)
+{
+	struct net_device *netdev = priv->netdev;
+	struct page *page;
+	dma_addr_t map;
+
+	page = alloc_page(GFP_KERNEL);
+	if (!page) {
+		if (net_ratelimit())
+			netdev_err(netdev, "failed to allocate rx page\n");
+		return -ENOMEM;
+	}
+
+	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(priv->dev, map))) {
+		if (net_ratelimit())
+			netdev_err(netdev, "failed to map rx page\n");
+		__free_page(page);
+		return -ENOMEM;
+	}
+
+	ftmac100_rxdes_set_page(rxdes, page);
+	ftmac100_rxdes_set_dma_addr(rxdes, map);
+	ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE);
+	ftmac100_rxdes_set_dma_own(rxdes);
+	return 0;
+}
+
+static void ftmac100_free_buffers(struct ftmac100 *priv)
+{
+	int i;
+
+	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+		struct page *page = ftmac100_rxdes_get_page(rxdes);
+		dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes);
+
+		if (!page)
+			continue;
+
+		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+		__free_page(page);
+	}
+
+	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
+		struct ftmac100_txdes *txdes = &priv->descs->txdes[i];
+		struct sk_buff *skb = ftmac100_txdes_get_skb(txdes);
+		dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes);
+
+		if (!skb)
+			continue;
+
+		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+		dev_kfree_skb(skb);
+	}
+
+	dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs),
+			  priv->descs, priv->descs_dma_addr);
+}
+
+static int ftmac100_alloc_buffers(struct ftmac100 *priv)
+{
+	int i;
+
+	priv->descs = dma_alloc_coherent(priv->dev, sizeof(struct ftmac100_descs),
+					 &priv->descs_dma_addr, GFP_KERNEL);
+	if (!priv->descs)
+		return -ENOMEM;
+
+	memset(priv->descs, 0, sizeof(struct ftmac100_descs));
+
+	/* initialize RX ring */
+	ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+
+	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+		struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+
+		if (ftmac100_alloc_rx_page(priv, rxdes))
+			goto err;
+	}
+
+	/* initialize TX ring */
+	ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
+	return 0;
+
+err:
+	ftmac100_free_buffers(priv);
+	return -ENOMEM;
+}
+
+/******************************************************************************
+ * struct mii_if_info functions
+ *****************************************************************************/
+static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	unsigned int phycr;
+	int i;
+
+	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
+		FTMAC100_PHYCR_REGAD(reg) |
+		FTMAC100_PHYCR_MIIRD;
+
+	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
+
+	for (i = 0; i < 10; i++) {
+		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
+
+		if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
+			return phycr & FTMAC100_PHYCR_MIIRDATA;
+
+		usleep_range(100, 1000);
+	}
+
+	netdev_err(netdev, "mdio read timed out\n");
+	return 0;
+}
+
+static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg,
+				int data)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	unsigned int phycr;
+	int i;
+
+	phycr = FTMAC100_PHYCR_PHYAD(phy_id) |
+		FTMAC100_PHYCR_REGAD(reg) |
+		FTMAC100_PHYCR_MIIWR;
+
+	data = FTMAC100_PHYWDATA_MIIWDATA(data);
+
+	iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA);
+	iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR);
+
+	for (i = 0; i < 10; i++) {
+		phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR);
+
+		if ((phycr & FTMAC100_PHYCR_MIIWR) == 0)
+			return;
+
+		usleep_range(100, 1000);
+	}
+
+	netdev_err(netdev, "mdio write timed out\n");
+}
+
+/******************************************************************************
+ * struct ethtool_ops functions
+ *****************************************************************************/
+static void ftmac100_get_drvinfo(struct net_device *netdev,
+				 struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, dev_name(&netdev->dev));
+}
+
+static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_ethtool_gset(&priv->mii, cmd);
+}
+
+static int ftmac100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_ethtool_sset(&priv->mii, cmd);
+}
+
+static int ftmac100_nway_reset(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_nway_restart(&priv->mii);
+}
+
+static u32 ftmac100_get_link(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	return mii_link_ok(&priv->mii);
+}
+
+static const struct ethtool_ops ftmac100_ethtool_ops = {
+	.set_settings		= ftmac100_set_settings,
+	.get_settings		= ftmac100_get_settings,
+	.get_drvinfo		= ftmac100_get_drvinfo,
+	.nway_reset		= ftmac100_nway_reset,
+	.get_link		= ftmac100_get_link,
+};
+
+/******************************************************************************
+ * interrupt handler
+ *****************************************************************************/
+static irqreturn_t ftmac100_interrupt(int irq, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct ftmac100 *priv = netdev_priv(netdev);
+
+	if (likely(netif_running(netdev))) {
+		/* Disable interrupts for polling */
+		ftmac100_disable_all_int(priv);
+		napi_schedule(&priv->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/******************************************************************************
+ * struct napi_struct functions
+ *****************************************************************************/
+static int ftmac100_poll(struct napi_struct *napi, int budget)
+{
+	struct ftmac100 *priv = container_of(napi, struct ftmac100, napi);
+	struct net_device *netdev = priv->netdev;
+	unsigned int status;
+	bool completed = true;
+	int rx = 0;
+
+	status = ioread32(priv->base + FTMAC100_OFFSET_ISR);
+
+	if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) {
+		/*
+		 * FTMAC100_INT_RPKT_FINISH:
+		 *	RX DMA has received packets into RX buffer successfully
+		 *
+		 * FTMAC100_INT_NORXBUF:
+		 *	RX buffer unavailable
+		 */
+		bool retry;
+
+		do {
+			retry = ftmac100_rx_packet(priv, &rx);
+		} while (retry && rx < budget);
+
+		if (retry && rx == budget)
+			completed = false;
+	}
+
+	if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) {
+		/*
+		 * FTMAC100_INT_XPKT_OK:
+		 *	packet transmitted to ethernet successfully
+		 *
+		 * FTMAC100_INT_XPKT_LOST:
+		 *	packet transmitted to ethernet lost due to late
+		 *	collision or excessive collision
+		 */
+		ftmac100_tx_complete(priv);
+	}
+
+	if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST |
+		      FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) {
+		if (net_ratelimit())
+			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
+				    status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "",
+				    status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
+				    status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
+				    status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
+
+		if (status & FTMAC100_INT_NORXBUF) {
+			/* RX buffer unavailable */
+			netdev->stats.rx_over_errors++;
+		}
+
+		if (status & FTMAC100_INT_RPKT_LOST) {
+			/* received packet lost due to RX FIFO full */
+			netdev->stats.rx_fifo_errors++;
+		}
+
+		if (status & FTMAC100_INT_PHYSTS_CHG) {
+			/* PHY link status change */
+			mii_check_link(&priv->mii);
+		}
+	}
+
+	if (completed) {
+		/* stop polling */
+		napi_complete(napi);
+		ftmac100_enable_all_int(priv);
+	}
+
+	return rx;
+}
+
+/******************************************************************************
+ * struct net_device_ops functions
+ *****************************************************************************/
+static int ftmac100_open(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	int err;
+
+	err = ftmac100_alloc_buffers(priv);
+	if (err) {
+		netdev_err(netdev, "failed to allocate buffers\n");
+		goto err_alloc;
+	}
+
+	err = request_irq(priv->irq, ftmac100_interrupt, 0, netdev->name, netdev);
+	if (err) {
+		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
+		goto err_irq;
+	}
+
+	priv->rx_pointer = 0;
+	priv->tx_clean_pointer = 0;
+	priv->tx_pointer = 0;
+	priv->tx_pending = 0;
+
+	err = ftmac100_start_hw(priv);
+	if (err)
+		goto err_hw;
+
+	napi_enable(&priv->napi);
+	netif_start_queue(netdev);
+
+	ftmac100_enable_all_int(priv);
+
+	return 0;
+
+err_hw:
+	free_irq(priv->irq, netdev);
+err_irq:
+	ftmac100_free_buffers(priv);
+err_alloc:
+	return err;
+}
+
+static int ftmac100_stop(struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+
+	ftmac100_disable_all_int(priv);
+	netif_stop_queue(netdev);
+	napi_disable(&priv->napi);
+	ftmac100_stop_hw(priv);
+	free_irq(priv->irq, netdev);
+	ftmac100_free_buffers(priv);
+
+	return 0;
+}
+
+static int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	dma_addr_t map;
+
+	if (unlikely(skb->len > MAX_PKT_SIZE)) {
+		if (net_ratelimit())
+			netdev_dbg(netdev, "tx packet too big\n");
+
+		netdev->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(priv->dev, map))) {
+		/* drop packet */
+		if (net_ratelimit())
+			netdev_err(netdev, "map socket buffer failed\n");
+
+		netdev->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	return ftmac100_xmit(priv, skb, map);
+}
+
+/* optional */
+static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct ftmac100 *priv = netdev_priv(netdev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+
+	return generic_mii_ioctl(&priv->mii, data, cmd, NULL);
+}
+
+static const struct net_device_ops ftmac100_netdev_ops = {
+	.ndo_open		= ftmac100_open,
+	.ndo_stop		= ftmac100_stop,
+	.ndo_start_xmit		= ftmac100_hard_start_xmit,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= ftmac100_do_ioctl,
+};
+
+/******************************************************************************
+ * struct platform_driver functions
+ *****************************************************************************/
+static int ftmac100_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int irq;
+	struct net_device *netdev;
+	struct ftmac100 *priv;
+	int err;
+
+	if (!pdev)
+		return -ENODEV;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	/* setup net_device */
+	netdev = alloc_etherdev(sizeof(*priv));
+	if (!netdev) {
+		err = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	SET_ETHTOOL_OPS(netdev, &ftmac100_ethtool_ops);
+	netdev->netdev_ops = &ftmac100_netdev_ops;
+
+	platform_set_drvdata(pdev, netdev);
+
+	/* setup private data */
+	priv = netdev_priv(netdev);
+	priv->netdev = netdev;
+	priv->dev = &pdev->dev;
+
+	spin_lock_init(&priv->tx_lock);
+
+	/* initialize NAPI */
+	netif_napi_add(netdev, &priv->napi, ftmac100_poll, 64);
+
+	/* map io memory */
+	priv->res = request_mem_region(res->start, resource_size(res),
+				       dev_name(&pdev->dev));
+	if (!priv->res) {
+		dev_err(&pdev->dev, "Could not reserve memory region\n");
+		err = -ENOMEM;
+		goto err_req_mem;
+	}
+
+	priv->base = ioremap(res->start, res->end - res->start);
+	if (!priv->base) {
+		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
+		err = -EIO;
+		goto err_ioremap;
+	}
+
+	priv->irq = irq;
+
+	/* initialize struct mii_if_info */
+	priv->mii.phy_id	= 0;
+	priv->mii.phy_id_mask	= 0x1f;
+	priv->mii.reg_num_mask	= 0x1f;
+	priv->mii.dev		= netdev;
+	priv->mii.mdio_read	= ftmac100_mdio_read;
+	priv->mii.mdio_write	= ftmac100_mdio_write;
+
+	/* register network device */
+	err = register_netdev(netdev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register netdev\n");
+		goto err_register_netdev;
+	}
+
+	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
+
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
+		random_ether_addr(netdev->dev_addr);
+		netdev_info(netdev, "generated random MAC address %pM\n",
+			    netdev->dev_addr);
+	}
+
+	return 0;
+
+err_register_netdev:
+	iounmap(priv->base);
+err_ioremap:
+	release_resource(priv->res);
+err_req_mem:
+	netif_napi_del(&priv->napi);
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+err_alloc_etherdev:
+	return err;
+}
+
+static int __exit ftmac100_remove(struct platform_device *pdev)
+{
+	struct net_device *netdev;
+	struct ftmac100 *priv;
+
+	netdev = platform_get_drvdata(pdev);
+	priv = netdev_priv(netdev);
+
+	unregister_netdev(netdev);
+
+	iounmap(priv->base);
+	release_resource(priv->res);
+
+	netif_napi_del(&priv->napi);
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+	return 0;
+}
+
+static struct platform_driver ftmac100_driver = {
+	.probe		= ftmac100_probe,
+	.remove		= __exit_p(ftmac100_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+/******************************************************************************
+ * initialization / finalization
+ *****************************************************************************/
+static int __init ftmac100_init(void)
+{
+	pr_info("Loading version " DRV_VERSION " ...\n");
+	return platform_driver_register(&ftmac100_driver);
+}
+
+static void __exit ftmac100_exit(void)
+{
+	platform_driver_unregister(&ftmac100_driver);
+}
+
+module_init(ftmac100_init);
+module_exit(ftmac100_exit);
+
+MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
+MODULE_DESCRIPTION("FTMAC100 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ftmac100.h b/drivers/net/ftmac100.h
new file mode 100644
index 0000000..46a0c47
--- /dev/null
+++ b/drivers/net/ftmac100.h
@@ -0,0 +1,180 @@
+/*
+ * Faraday FTMAC100 10/100 Ethernet
+ *
+ * (C) Copyright 2009-2011 Faraday Technology
+ * Po-Yu Chuang <ratbert@faraday-tech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FTMAC100_H
+#define __FTMAC100_H
+
+#define	FTMAC100_OFFSET_ISR		0x00
+#define	FTMAC100_OFFSET_IMR		0x04
+#define	FTMAC100_OFFSET_MAC_MADR	0x08
+#define	FTMAC100_OFFSET_MAC_LADR	0x0c
+#define	FTMAC100_OFFSET_MAHT0		0x10
+#define	FTMAC100_OFFSET_MAHT1		0x14
+#define	FTMAC100_OFFSET_TXPD		0x18
+#define	FTMAC100_OFFSET_RXPD		0x1c
+#define	FTMAC100_OFFSET_TXR_BADR	0x20
+#define	FTMAC100_OFFSET_RXR_BADR	0x24
+#define	FTMAC100_OFFSET_ITC		0x28
+#define	FTMAC100_OFFSET_APTC		0x2c
+#define	FTMAC100_OFFSET_DBLAC		0x30
+#define	FTMAC100_OFFSET_MACCR		0x88
+#define	FTMAC100_OFFSET_MACSR		0x8c
+#define	FTMAC100_OFFSET_PHYCR		0x90
+#define	FTMAC100_OFFSET_PHYWDATA	0x94
+#define	FTMAC100_OFFSET_FCR		0x98
+#define	FTMAC100_OFFSET_BPR		0x9c
+#define	FTMAC100_OFFSET_TS		0xc4
+#define	FTMAC100_OFFSET_DMAFIFOS	0xc8
+#define	FTMAC100_OFFSET_TM		0xcc
+#define	FTMAC100_OFFSET_TX_MCOL_SCOL	0xd4
+#define	FTMAC100_OFFSET_RPF_AEP		0xd8
+#define	FTMAC100_OFFSET_XM_PG		0xdc
+#define	FTMAC100_OFFSET_RUNT_TLCC	0xe0
+#define	FTMAC100_OFFSET_CRCER_FTL	0xe4
+#define	FTMAC100_OFFSET_RLC_RCC		0xe8
+#define	FTMAC100_OFFSET_BROC		0xec
+#define	FTMAC100_OFFSET_MULCA		0xf0
+#define	FTMAC100_OFFSET_RP		0xf4
+#define	FTMAC100_OFFSET_XP		0xf8
+
+/*
+ * Interrupt status register & interrupt mask register
+ */
+#define	FTMAC100_INT_RPKT_FINISH	(1 << 0)
+#define	FTMAC100_INT_NORXBUF		(1 << 1)
+#define	FTMAC100_INT_XPKT_FINISH	(1 << 2)
+#define	FTMAC100_INT_NOTXBUF		(1 << 3)
+#define	FTMAC100_INT_XPKT_OK		(1 << 4)
+#define	FTMAC100_INT_XPKT_LOST		(1 << 5)
+#define	FTMAC100_INT_RPKT_SAV		(1 << 6)
+#define	FTMAC100_INT_RPKT_LOST		(1 << 7)
+#define	FTMAC100_INT_AHB_ERR		(1 << 8)
+#define	FTMAC100_INT_PHYSTS_CHG		(1 << 9)
+
+/*
+ * Interrupt timer control register
+ */
+#define FTMAC100_ITC_RXINT_CNT(x)	(((x) & 0xf) << 0)
+#define FTMAC100_ITC_RXINT_THR(x)	(((x) & 0x7) << 4)
+#define FTMAC100_ITC_RXINT_TIME_SEL	(1 << 7)
+#define FTMAC100_ITC_TXINT_CNT(x)	(((x) & 0xf) << 8)
+#define FTMAC100_ITC_TXINT_THR(x)	(((x) & 0x7) << 12)
+#define FTMAC100_ITC_TXINT_TIME_SEL	(1 << 15)
+
+/*
+ * Automatic polling timer control register
+ */
+#define	FTMAC100_APTC_RXPOLL_CNT(x)	(((x) & 0xf) << 0)
+#define	FTMAC100_APTC_RXPOLL_TIME_SEL	(1 << 4)
+#define	FTMAC100_APTC_TXPOLL_CNT(x)	(((x) & 0xf) << 8)
+#define	FTMAC100_APTC_TXPOLL_TIME_SEL	(1 << 12)
+
+/*
+ * DMA burst length and arbitration control register
+ */
+#define FTMAC100_DBLAC_INCR4_EN		(1 << 0)
+#define FTMAC100_DBLAC_INCR8_EN		(1 << 1)
+#define FTMAC100_DBLAC_INCR16_EN	(1 << 2)
+#define FTMAC100_DBLAC_RXFIFO_LTHR(x)	(((x) & 0x7) << 3)
+#define FTMAC100_DBLAC_RXFIFO_HTHR(x)	(((x) & 0x7) << 6)
+#define FTMAC100_DBLAC_RX_THR_EN	(1 << 9)
+
+/*
+ * MAC control register
+ */
+#define	FTMAC100_MACCR_XDMA_EN		(1 << 0)
+#define	FTMAC100_MACCR_RDMA_EN		(1 << 1)
+#define	FTMAC100_MACCR_SW_RST		(1 << 2)
+#define	FTMAC100_MACCR_LOOP_EN		(1 << 3)
+#define	FTMAC100_MACCR_CRC_DIS		(1 << 4)
+#define	FTMAC100_MACCR_XMT_EN		(1 << 5)
+#define	FTMAC100_MACCR_ENRX_IN_HALFTX	(1 << 6)
+#define	FTMAC100_MACCR_RCV_EN		(1 << 8)
+#define	FTMAC100_MACCR_HT_MULTI_EN	(1 << 9)
+#define	FTMAC100_MACCR_RX_RUNT		(1 << 10)
+#define	FTMAC100_MACCR_RX_FTL		(1 << 11)
+#define	FTMAC100_MACCR_RCV_ALL		(1 << 12)
+#define	FTMAC100_MACCR_CRC_APD		(1 << 14)
+#define	FTMAC100_MACCR_FULLDUP		(1 << 15)
+#define	FTMAC100_MACCR_RX_MULTIPKT	(1 << 16)
+#define	FTMAC100_MACCR_RX_BROADPKT	(1 << 17)
+
+/*
+ * PHY control register
+ */
+#define FTMAC100_PHYCR_MIIRDATA		0xffff
+#define FTMAC100_PHYCR_PHYAD(x)		(((x) & 0x1f) << 16)
+#define FTMAC100_PHYCR_REGAD(x)		(((x) & 0x1f) << 21)
+#define FTMAC100_PHYCR_MIIRD		(1 << 26)
+#define FTMAC100_PHYCR_MIIWR		(1 << 27)
+
+/*
+ * PHY write data register
+ */
+#define FTMAC100_PHYWDATA_MIIWDATA(x)	((x) & 0xffff)
+
+/*
+ * Transmit descriptor, aligned to 16 bytes
+ */
+struct ftmac100_txdes {
+	unsigned int	txdes0;
+	unsigned int	txdes1;
+	unsigned int	txdes2;	/* TXBUF_BADR */
+	unsigned int	txdes3;	/* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define	FTMAC100_TXDES0_TXPKT_LATECOL	(1 << 0)
+#define	FTMAC100_TXDES0_TXPKT_EXSCOL	(1 << 1)
+#define	FTMAC100_TXDES0_TXDMA_OWN	(1 << 31)
+
+#define	FTMAC100_TXDES1_TXBUF_SIZE(x)	((x) & 0x7ff)
+#define	FTMAC100_TXDES1_LTS		(1 << 27)
+#define	FTMAC100_TXDES1_FTS		(1 << 28)
+#define	FTMAC100_TXDES1_TX2FIC		(1 << 29)
+#define	FTMAC100_TXDES1_TXIC		(1 << 30)
+#define	FTMAC100_TXDES1_EDOTR		(1 << 31)
+
+/*
+ * Receive descriptor, aligned to 16 bytes
+ */
+struct ftmac100_rxdes {
+	unsigned int	rxdes0;
+	unsigned int	rxdes1;
+	unsigned int	rxdes2;	/* RXBUF_BADR */
+	unsigned int	rxdes3;	/* not used by HW */
+} __attribute__ ((aligned(16)));
+
+#define	FTMAC100_RXDES0_RFL		0x7ff
+#define	FTMAC100_RXDES0_MULTICAST	(1 << 16)
+#define	FTMAC100_RXDES0_BROADCAST	(1 << 17)
+#define	FTMAC100_RXDES0_RX_ERR		(1 << 18)
+#define	FTMAC100_RXDES0_CRC_ERR		(1 << 19)
+#define	FTMAC100_RXDES0_FTL		(1 << 20)
+#define	FTMAC100_RXDES0_RUNT		(1 << 21)
+#define	FTMAC100_RXDES0_RX_ODD_NB	(1 << 22)
+#define	FTMAC100_RXDES0_LRS		(1 << 28)
+#define	FTMAC100_RXDES0_FRS		(1 << 29)
+#define	FTMAC100_RXDES0_RXDMA_OWN	(1 << 31)
+
+#define	FTMAC100_RXDES1_RXBUF_SIZE(x)	((x) & 0x7ff)
+#define	FTMAC100_RXDES1_EDORR		(1 << 31)
+
+#endif /* __FTMAC100_H */
-- 
1.6.3.3


^ permalink raw reply related

* Re: txqueuelen has wrong units; should be time
From: Albert Cahalan @ 2011-03-01  6:54 UTC (permalink / raw)
  To: David Miller
  Cc: johnwheffner, linville, eric.dumazet, jussi.kivilinna, swmike,
	linux-kernel, netdev
In-Reply-To: <20110228.201852.193726064.davem@davemloft.net>

On Mon, Feb 28, 2011 at 11:18 PM, David Miller <davem@davemloft.net> wrote:
> From: Albert Cahalan <acahalan@gmail.com>
> Date: Mon, 28 Feb 2011 23:11:13 -0500
>
>> It sounds like you need a callback or similar, so that TCP can be
>> informed later that the drop has occurred.
>
> By that point we could have already sent an entire RTT's worth
> of data, or more.
>
> It needs to be synchronous, otherwise performance suffers.

Ouch. OTOH, the current situation: performance suffers.

In case it makes you feel any better, consider two cases
where synchronous feedback is already impossible.
One is when you're routing packets that merely pass through.
The other is when some other box is doing that to you.
Either way, packets go bye-bye and nobody tells TCP.

^ permalink raw reply

* Re: Bug inkvm_set_irq
From: Michael S. Tsirkin @ 2011-03-01  7:03 UTC (permalink / raw)
  To: Jean-Philippe Menil; +Cc: netdev, kvm, virtualization
In-Reply-To: <4D6C22E8.2020007@univ-nantes.fr>

On Mon, Feb 28, 2011 at 11:34:16PM +0100, Jean-Philippe Menil wrote:
> Hi,
> 
> here is another trace with kvm.ko compiled with debug flags.
> 
> the bug:
> [12099.503414] BUG: unable to handle kernel paging request at
> 000000000b6635e9
> [12099.503462] IP: [<ffffffffa03ee877>] kvm_set_irq+0x37/0x140 [kvm]
> [12099.503521] PGD 45d8d2067 PUD 45d58e067 PMD 0
> [12099.503560] Oops: 0000 [#1] SMP
> [12099.503591] last sysfs file:
> /sys/devices/system/cpu/cpu11/cache/index2/shared_cpu_map
> [12099.503641] CPU 0
> [12099.503648] Modules linked in: netconsole configfs vhost_net
> macvtap macvlan tun veth powernow_k8 mperf cpufreq_userspace
> cpufreq_stats cpufreq_powersave cpufreq_ondemand freq_table
> cpufreq_conservative fuse xt_physdev ip6t_LOG ip6table_filter
> ip6_tables ipt_LOG xt_multiport xt_limit xt_tcpudp xt_state
> iptable_filter ip_tables x_tables nf_conntrack_tftp nf_conntrack_ftp
> nf_conntrack_ipv4 nf_defrag_ipv4 8021q bridge stp ext2 mbcache
> dm_round_robin dm_multipath nf_conntrack_ipv6 nf_conntrack
> nf_defrag_ipv6 kvm_amd kvm ipv6 snd_pcm snd_timer snd soundcore
> snd_page_alloc shpchp pci_hotplug tpm_tis i2c_nforce2 tpm i2c_core
> pcspkr evdev psmouse joydev tpm_bios processor ghes dcdbas hed
> button serio_raw thermal_sys xfs exportfs dm_mod sg sr_mod cdrom
> usbhid hid usb_storage ses sd_mod enclosure megaraid_sas ohci_hcd
> lpfc scsi_transport_fc bnx2 scsi_tgt scsi_mod ehci_hcd [last
> unloaded: scsi_wait_scan]
> [12099.504277]
> [12099.504302] Pid: 1742, comm: kworker/0:2 Not tainted
> 2.6.37.2-dsiun-110105+ #2 Dell Inc. PowerEdge M605/0K543T
> [12099.504373] RIP: 0010:[<ffffffffa03ee877>]  [<ffffffffa03ee877>]
> kvm_set_irq+0x37/0x140 [kvm]
> [12099.504444] RSP: 0018:ffff88045e013d00  EFLAGS: 00010246
> [12099.504474] RAX: 000000000b6634c1 RBX: 0000000000000018 RCX:
> 0000000000000001
> [12099.504508] RDX: 0000000000000000 RSI: 0000000000000000 RDI:
> ffff880419b600c0
> [12099.504541] RBP: ffff88045e013dd0 R08: ffff88045e012000 R09:
> 0000000000000000
> [12099.504575] R10: 0000000000000000 R11: 00000000ffffffff R12:
> ffff880419b600c0
> [12099.504609] R13: ffff880419b600c0 R14: ffffffffa03efaa0 R15:
> 0000000000000001
> [12099.504643] FS:  00007f3abaa05710(0000) GS:ffff88007f800000(0000)
> knlGS:0000000000000000
> [12099.504693] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> [12099.504724] CR2: 000000000b6635e9 CR3: 000000045e2bc000 CR4:
> 00000000000006f0
> [12099.504757] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [12099.504791] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
> 0000000000000400
> [12099.504825] Process kworker/0:2 (pid: 1742, threadinfo
> ffkvm_set_irqff88045e012000, task ffff88045ffb0d60)
> [12099.504874] Stack:
> [12099.504897]  00000000000119c0 00000000000119c0 00000000000119c0
> ffff88045ffb0d60
> [12099.504953]  ffff88045ffb1010 ffff88045e013fd8 ffff88045ffb1018
> ffff88045e012010
> [12099.505009]  00000000000119c0 ffff88045e013fd8 00000000000119c0
> 00000000000119c0
> [12099.505065] Call Trace:
> [12099.505099]  [<ffffffff813818ce>] ? common_interrupt+0xe/0x13
> [12099.505145]  [<ffffffffa03efaa0>] ? irqfd_inject+0x0/0x50 [kvm]
> [12099.505145]  [<ffffffffa03efaca>] irqfd_inject+0x2a/0x50 [kvm]
> [12099.505145]  [<ffffffff8106b7bb>] process_one_work+0x11b/0x450
> [12099.505145]  [<ffffffff8106bf37>] worker_thread+0x157/0x410
> [12099.505145]  [<ffffffff8103a569>] ? __wake_up_common+0x59/0x90
> [12099.505145]  [<ffffffff8106bde0>] ? worker_thread+0x0/0x410
> [12099.505145]  [<ffffffff8106f996>] kthread+0x96/0xa0
> [12099.505145]  [<ffffffff81003c64>] kernel_thread_helper+0x4/0x10
> [12099.505145]  [<ffffffff8106f900>] ? kthread+0x0/0xa0
> [12099.505145]  [<ffffffff81003c60>] ? kernel_thread_helper+0x0/0x10
> [12099.505145] Code: 55 49 89 fd 41 54 53 89 d3 48 81 ec a8 00 00 00
> 8b 15 a6 75 03 00 89 b5 3c ff ff ff 85 d2 0f 85 d5 00 00 00 49 8b 85
> 58 24 00 00 <3b> 98 28 01 00 00 73 61 89 db 48 8b 84 d8 30 01 00 00
> 48 85 c0
> [12099.505145] RIP  [<ffffffffa03ee877>] kvm_set_irq+0x37/0x140 [kvm]
> [12099.505145]  RSP <ffff88045e013d00>
> [12099.505145] CR2: 000000000b6635e9
> 
> 
> markup_oops result:
> 
> root@ayrshire:~# cat bug.txt | perl markup_oops.pl -m
> /lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko
> /boot/vmlinuz-2.6.37.2-dsiun-110105+
> vmaoffset = 18446744072103034880 ffffffffa03ee841:	48 89 e5   	mov
> %rsp,%rbp
>  ffffffffa03ee844:	41 57                	push   %r15
>  ffffffffa03ee846:	41 89 cf             	mov    %ecx,%r15d  |  %r15
> => 1  %ecx = 1
>  ffffffffa03ee849:	41 56                	push   %r14        |  %r14
> => ffffffffa03efaa0
>  ffffffffa03ee84b:	41 55                	push   %r13
>  ffffffffa03ee84d:	49 89 fd             	mov    %rdi,%r13   |  %edi
> = ffff880419b600c0  %r13 => ffff880419b600c0
>  ffffffffa03ee850:	41 54                	push   %r12        |  %r12
> => ffff880419b600c0
>  ffffffffa03ee852:	53                   	push   %rbx
>  ffffffffa03ee853:	89 d3                	mov    %edx,%ebx   |  %ebx => 18
>  ffffffffa03ee855:	48 81 ec a8 00 00 00 	sub    $0xa8,%rsp
>  ffffffffa03ee85c:	8b 15 00 00 00 00    	mov    0x0(%rip),%edx
> # ffffffffa03ee862 <kvm_set_irq+0x22>
>  ffffffffa03ee862:	89 b5 3c ff ff ff    	mov    %esi,-0xc4(%rbp) |
> %esi = 0
>  ffffffffa03ee868:	85 d2                	test   %edx,%edx   |  %edx => 0
>  ffffffffa03ee86a:	0f 85 d5 00 00 00    	jne    ffffffffa03ee945
> <kvm_set_irq+0x105>
>  ffffffffa03ee870:	49 8b 85 58 24 00 00 	mov    0x2458(%r13),%rax |
> %eax => b6634c1  %r13 = ffff880419b600c0
> *ffffffffa03ee877:	3b 98 28 01 00 00    	cmp    0x128(%rax),%ebx |
> %eax = b6634c1  %ebx = 18 <--- faulting instruction
>  ffffffffa03ee87d:	73 61                	jae    ffffffffa03ee8e0
> <kvm_set_irq+0xa0>
>  ffffffffa03ee87f:	89 db                	mov    %ebx,%ebx
>  ffffffffa03ee881:	48 8b 84 d8 30 01 00 	mov    0x130(%rax,%rbx,8),%rax
>  ffffffffa03ee888:	00
>  ffffffffa03ee889:	48 85 c0             	test   %rax,%rax
>  ffffffffa03ee88c:	74 52                	je     ffffffffa03ee8e0
> <kvm_set_irq+0xa0>
>  ffffffffa03ee88e:	48 8d 95 40 ff ff ff 	lea    -0xc0(%rbp),%rdx
>  ffffffffa03ee895:	31 db                	xor    %ebx,%ebx
>  ffffffffa03ee897:	48 8b 08             	mov    (%rax),%rcx
>  ffffffffa03ee89a:	83 c3 01             	add    $0x1,%ebx
>  ffffffffa03ee89d:	0f 18 09             	prefetcht0 (%rcx)
>  ffffffffa03ee8a0:	48 8b 48 e0          	mov    -0x20(%rax),%rcx
>  ffffffffa03ee8a4:	48 89 0a             	mov    %rcx,(%rdx)
>  ffffffffa03ee8a7:	48 8b 48 e8          	mov    -0x18(%rax),%rcx
>  ffffffffa03ee8ab:	48 89 4a 08          	mov    %rcx,0x8(%rdx)
>  ffffffffa03ee8af:	48 8b 48 f0          	mov    -0x10(%rax),%rcx
>  ffffffffa03ee8b3:	48 89 4a 10          	mov    %rcx,0x10(%rdx)
>  ffffffffa03ee8b7:	48 8b 48 f8          	mov    -0x8(%rax),%rcx
>  ffffffffa03ee8bb:	48 89 4a 18          	mov    %rcx,0x18(%rdx)
>  ffffffffa03ee8bf:	48 8b 08             	mov    (%rax),%rcx
> 
> The relvant part of objdump for kvm_set_irq:
> root@ayrshire:~# objdump -ldS
> /lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko >
> dump.txt
> 
> 0000000000006840 <kvm_set_irq>:
> kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:148
>     6840:       55                      push   %rbp
>     6841:       48 89 e5                mov    %rsp,%rbp
>     6844:       41 57                   push   %r15
>     6846:       41 89 cf                mov    %ecx,%r15d
>     6849:       41 56                   push   %r14
>     684b:       41 55                   push   %r13
>     684d:       49 89 fd                mov    %rdi,%r13
>     6850:       41 54                   push   %r12
>     6852:       53                      push   %rbx
>     6853:       89 d3                   mov    %edx,%ebx
>     6855:       48 81 ec a8 00 00 00    sub    $0xa8,%rsp
> trace_kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
>     685c:       8b 15 00 00 00 00       mov    0x0(%rip),%edx
> # 6862 <kvm_set_irq+0x22>
> kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:148
>     6862:       89 b5 3c ff ff ff       mov    %esi,-0xc4(%rbp)
> trace_kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
>     6868:       85 d2                   test   %edx,%edx
>     686a:       0f 85 d5 00 00 00       jne    6945 <kvm_set_irq+0x105>
> kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:161
>     6870:       49 8b 85 58 24 00 00    mov    0x2458(%r13),%rax
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
>     6877:       3b 98 28 01 00 00       cmp    0x128(%rax),%ebx
>     687d:       73 61                   jae    68e0 <kvm_set_irq+0xa0>
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
>     687f:       89 db                   mov    %ebx,%ebx
>     6881:       48 8b 84 d8 30 01 00    mov    0x130(%rax,%rbx,8),%rax
>     6888:       00
>     6889:       48 85 c0                test   %rax,%rax
>     688c:       74 52                   je     68e0 <kvm_set_irq+0xa0>
>     688e:       48 8d 95 40 ff ff ff    lea    -0xc0(%rbp),%rdx
>     6895:       31 db                   xor    %ebx,%ebx
>     6897:       48 8b 08                mov    (%rax),%rcx
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:164
>     689a:       83 c3 01                add    $0x1,%ebx
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
>     689d:       0f 18 09                prefetcht0 (%rcx)
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:164
>     68a0:       48 8b 48 e0             mov    -0x20(%rax),%rcx
>     68a4:       48 89 0a                mov    %rcx,(%rdx)
>     68a7:       48 8b 48 e8             mov    -0x18(%rax),%rcx
>     68ab:       48 89 4a 08             mov    %rcx,0x8(%rdx)
>     68af:       48 8b 48 f0             mov    -0x10(%rax),%rcx
>     68b3:       48 89 4a 10             mov    %rcx,0x10(%rdx)
>     68b7:       48 8b 48 f8             mov    -0x8(%rax),%rcx
>     68bb:       48 89 4a 18             mov    %rcx,0x18(%rdx)
>     68bf:       48 8b 08                mov    (%rax),%rcx
>     68c2:       48 89 4a 20             mov    %rcx,0x20(%rdx)
>     68c6:       48 8b 48 08             mov    0x8(%rax),%rcx
>     68ca:       48 89 4a 28             mov    %rcx,0x28(%rdx)
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:163
>     68ce:       48 8b 00                mov    (%rax),%rax
>     68d1:       48 83 c2 30             add    $0x30,%rdx
>     68d5:       48 85 c0                test   %rax,%rax
>     68d8:       75 bd                   jne    6897 <kvm_set_irq+0x57>
>     68da:       eb 06                   jmp    68e2 <kvm_set_irq+0xa2>
>     68dc:       0f 1f 40 00             nopl   0x0(%rax)
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
>     68e0:       31 db                   xor    %ebx,%ebx
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:169
>     68e2:       4c 8d b5 40 ff ff ff    lea    -0xc0(%rbp),%r14
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
>     68e9:       41 bc ff ff ff ff       mov    $0xffffffff,%r12d
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
>     68ef:       85 db                   test   %ebx,%ebx
>     68f1:       74 3d                   je     6930 <kvm_set_irq+0xf0>
>     68f3:       83 eb 01                sub    $0x1,%ebx
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:169
>     68f6:       44 89 f9                mov    %r15d,%ecx
>     68f9:       8b 95 3c ff ff ff       mov    -0xc4(%rbp),%edx
>     68ff:       48 63 c3                movslq %ebx,%rax
>     6902:       4c 89 ee                mov    %r13,%rsi
>     6905:       48 8d 04 40             lea    (%rax,%rax,2),%rax
>     6909:       48 c1 e0 04             shl    $0x4,%rax
>     690d:       49 8d 3c 06             lea    (%r14,%rax,1),%rdi
>     6911:       ff 94 05 48 ff ff ff    callq  *-0xb8(%rbp,%rax,1)
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:170
>     6918:       85 c0                   test   %eax,%eax
>     691a:       78 d3                   js     68ef <kvm_set_irq+0xaf>
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:173
>     691c:       45 85 e4                test   %r12d,%r12d
>     691f:       ba 00 00 00 00          mov    $0x0,%edx
>     6924:       44 0f 48 e2             cmovs  %edx,%r12d
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
>     6928:       85 db                   test   %ebx,%ebx
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:173
>     692a:       46 8d 24 20             lea    (%rax,%r12,1),%r12d
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:167
>     692e:       75 c3                   jne    68f3 <kvm_set_irq+0xb3>
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:177
>     6930:       48 81 c4 a8 00 00 00    add    $0xa8,%rsp
>     6937:       44 89 e0                mov    %r12d,%eax
>     693a:       5b                      pop    %rbx
>     693b:       41 5c                   pop    %r12
>     693d:       41 5d                   pop    %r13
>     693f:       41 5e                   pop    %r14
>     6941:       41 5f                   pop    %r15
>     6943:       c9                      leaveq
>     6944:       c3                      retq
> trace_kvm_set_irq():
> /usr/src/GIT/linux-2.6-stable/include/trace/events/kvm.h:10
>     6945:       4c 8b 25 00 00 00 00    mov    0x0(%rip),%r12
> # 694c <kvm_set_irq+0x10c>
>     694c:       4d 85 e4                test   %r12,%r12
>     694f:       0f 84 1b ff ff ff       je     6870 <kvm_set_irq+0x30>
>     6955:       49 8b 04 24             mov    (%r12),%rax
>     6959:       49 8b 7c 24 08          mov    0x8(%r12),%rdi
>     695e:       49 83 c4 10             add    $0x10,%r12
>     6962:       8b 8d 3c ff ff ff       mov    -0xc4(%rbp),%ecx
>     6968:       44 89 fa                mov    %r15d,%edx
>     696b:       89 de                   mov    %ebx,%esi
>     696d:       ff d0                   callq  *%rax
>     696f:       49 8b 04 24             mov    (%r12),%rax
>     6973:       48 85 c0                test   %rax,%rax
>     6976:       75 e1                   jne    6959 <kvm_set_irq+0x119>
>     6978:       e9 f3 fe ff ff          jmpq   6870 <kvm_set_irq+0x30>
> kvm_set_irq():
>     697d:       0f 1f 00                nopl   (%rax)
> 
> So, if i've read correctly, the offset is 0x6877 ?
> 
> root@ayrshire:~# addr2line -e
> /lib/modules/2.6.37.2-dsiun-110105+/kernel/arch/x86/kvm/kvm.ko
> 0x6877
> /usr/src/GIT/linux-2.6-stable/arch/x86/kvm/../../../virt/kvm/irq_comm.c:162
> 
> 
> Is it the correct way to analyse this?
> 
> Regards.

Yes.  So we have:

        irq_rt = rcu_dereference(kvm->irq_routing);

>  ffffffffa03ee870:	49 8b 85 58 24 00 00 	mov    0x2458(%r13),%rax |
> %eax => b6634c1  %r13 = ffff880419b600c0

        if (irq < irq_rt->nr_rt_entries)

> *ffffffffa03ee877:	3b 98 28 01 00 00    	cmp    0x128(%rax),%ebx |
> %eax = b6634c1  %ebx = 18 <--- faulting instruction

The problem then is that while the kvm pointer is
ffff880419b600c0 which looks sane,
the value we read from kvm->irq_routing is b6634c1 which
does not make sense. When we dereference that, kaboom.

Is the kvm pointer wrong or the memory corrupted?
Try printing the kvm pointer during
initialization, e.g. in kvm_vm_ioctl_create_vcpu,
then and compare to markup_oops.


-- 
MST

^ permalink raw reply

* Re: txqueuelen has wrong units; should be time
From: David Miller @ 2011-03-01  7:25 UTC (permalink / raw)
  To: acahalan
  Cc: johnwheffner, linville, eric.dumazet, jussi.kivilinna, swmike,
	linux-kernel, netdev
In-Reply-To: <AANLkTi=eDQh9Kvr9N_dTC5Cnbcfb+DbO-6tLxkZiEp9v@mail.gmail.com>

From: Albert Cahalan <acahalan@gmail.com>
Date: Tue, 1 Mar 2011 01:54:09 -0500

> In case it makes you feel any better, consider two cases
> where synchronous feedback is already impossible.
> One is when you're routing packets that merely pass through.
> The other is when some other box is doing that to you.
> Either way, packets go bye-bye and nobody tells TCP.

I consider ECN quite synchronous, and routers will set ECN bits to
propagate congestion information when they do or are about to drop
packets.

^ permalink raw reply

* Re: txqueuelen has wrong units; should be time
From: Eric Dumazet @ 2011-03-01  7:26 UTC (permalink / raw)
  To: Albert Cahalan
  Cc: David Miller, johnwheffner, linville, jussi.kivilinna, swmike,
	linux-kernel, netdev
In-Reply-To: <AANLkTi=eDQh9Kvr9N_dTC5Cnbcfb+DbO-6tLxkZiEp9v@mail.gmail.com>

Le mardi 01 mars 2011 à 01:54 -0500, Albert Cahalan a écrit :
> On Mon, Feb 28, 2011 at 11:18 PM, David Miller <davem@davemloft.net> wrote:
> > From: Albert Cahalan <acahalan@gmail.com>
> > Date: Mon, 28 Feb 2011 23:11:13 -0500
> >
> >> It sounds like you need a callback or similar, so that TCP can be
> >> informed later that the drop has occurred.
> >
> > By that point we could have already sent an entire RTT's worth
> > of data, or more.
> >
> > It needs to be synchronous, otherwise performance suffers.
> 
> Ouch. OTOH, the current situation: performance suffers.
> 
> In case it makes you feel any better, consider two cases
> where synchronous feedback is already impossible.
> One is when you're routing packets that merely pass through.
> The other is when some other box is doing that to you.
> Either way, packets go bye-bye and nobody tells TCP.

So in a hurry we decide to drop packets blindly because kernel took the
cpu to perform an urgent task ?

Bufferbloat is a configuration/tuning problem, not a "everything must be
redone" problem. We add new qdiscs (CHOKe, SFB, QFQ, ...) and let admins
do their job. Problem is most admins are unaware of the problems, and
only buy more bandwidth.

And no, there is no "generic" solution, unless you have a lab with two
machines back to back (private link) and a known workload.

We might need some changes (including new APIs).

ECN is a forward step. Blindly dropping packets before ever sending them
is a step backward.

We should allow some trafic spikes, or many applications will stop
working. Unless all applications are fixed, we are stuck.

Only if the queue stay loaded a long time (yet another parameter) we can
try to drop packets.

^ permalink raw reply

* Re: [PATCH] net: add Faraday FTMAC100 10/100 Ethernet driver
From: Eric Dumazet @ 2011-03-01  7:27 UTC (permalink / raw)
  To: Po-Yu Chuang
  Cc: netdev, linux-kernel, bhutchings, joe, dilinger, mirqus, davem,
	Po-Yu Chuang
In-Reply-To: <1298962129-1605-1-git-send-email-ratbert.chuang@gmail.com>

Le mardi 01 mars 2011 à 14:48 +0800, Po-Yu Chuang a écrit :
> From: Po-Yu Chuang <ratbert@faraday-tech.com>
> 
> FTMAC100 Ethernet Media Access Controller supports 10/100 Mbps and
> MII.  This driver has been working on some ARM/NDS32 SoC's including
> Faraday A320 and Andes AG101.
> 
> Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
> ---
> v2:
> always use NAPI
> do not use our own net_device_stats structure
> don't set trans_start and last_rx
> stats.rx_packets and stats.rx_bytes include dropped packets
> add missed netif_napi_del()
> initialize spinlocks in probe function
> remove rx_lock and hw_lock
> use netdev_[err/info/dbg] instead of dev_* ones
> use netdev_alloc_skb_ip_align()
> remove ftmac100_get_stats()
> use is_valid_ether_addr() instead of is_zero_ether_addr()
> add const to ftmac100_ethtool_ops and ftmac100_netdev_ops
> use net_ratelimit() instead of printk_ratelimit()
> no explicit inline
> use %pM to print MAC address
> add comment before wmb
> use napi poll() to handle all interrupts
> 
> v3:
> undo "stats.rx_packets and stats.rx_bytes include dropped packets"
> ftmac100_mdio_read() returns 0 if error
> fix comment typos
> use pr_fmt and pr_info
> define INT_MASK_ALL_ENABLED
> define MACCR_ENABLE_ALL
> do not count length error many times
> use bool/true/false
> use cpu_to_le32/le32_to_cpu to access descriptors
> indent style fix
> 
> v4:
> should not access skb after netif_receive_skb()
> use resource_size()
> better way to use cpu_to_le32/le32_to_cpu
> use spin_lock() for tx_lock
> combine all netdev_info() together in ftmac100_poll()
> 
> v5:
> use dev_kfree_skb() in ftmac100_tx_complete_packet()
> cpu_to_le32/le32_to_cpu usage fix
> drop GFP_DMA
> 
> v6:
> cpu_to_le32/le32_to_cpu usage fix
> remove "tx queue full" message
> reduce critical section protected by tx_lock
> add check of MAX_PKT_SIZE and RX_BUF_SIZE
> add __exit to ftmac100_remove()
> simplify ftmac100_rx_packet()
> zero copy - use skb_fill_page_desc() and __pskb_pull_tail().
> pull more data to skb head to include tcp/ip header
> 
> v7:
> allocate 128 bytes skb and pull 64 bytes only
> 
>  drivers/net/Kconfig    |    9 +
>  drivers/net/Makefile   |    1 +
>  drivers/net/ftmac100.c | 1196 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/ftmac100.h |  180 ++++++++
>  4 files changed, 1386 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/ftmac100.c
>  create mode 100644 drivers/net/ftmac100.h

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>

^ permalink raw reply

* Re: [PATCH] f_phonet: avoid pskb_pull(), fix OOPS with CONFIG_HIGHMEM
From: Rémi Denis-Courmont @ 2011-03-01  7:34 UTC (permalink / raw)
  To: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20110228.123844.70195701.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>

On Monday 28 February 2011 22:38:44 ext David Miller, you wrote:
> From: Rémi Denis-Courmont <remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> Date: Wed, 23 Feb 2011 14:51:33 +0200
> 
> > This is similar to what we already do in cdc-phonet.c in the same
> > situation. pskb_pull() refuses to work with HIGHMEM, even if it is
> > known that the socket buffer is entirely in "low" memory.
> > 
> > Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
> 
> Applied, thanks.

Hmm, this is already somewhere in linux-usb, from what I understood (I suppose 
git-merge does not care much).

-- 
Rémi Denis-Courmont
http://www.remlab.net/
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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] f_phonet: avoid pskb_pull(), fix OOPS with CONFIG_HIGHMEM
From: David Miller @ 2011-03-01  7:37 UTC (permalink / raw)
  To: remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <201103010934.30730.remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>

From: "Rémi Denis-Courmont" <remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
Date: Tue, 1 Mar 2011 09:34:30 +0200

> On Monday 28 February 2011 22:38:44 ext David Miller, you wrote:
>> From: Rémi Denis-Courmont <remi.denis-courmont-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
>> Date: Wed, 23 Feb 2011 14:51:33 +0200
>> 
>> > This is similar to what we already do in cdc-phonet.c in the same
>> > situation. pskb_pull() refuses to work with HIGHMEM, even if it is
>> > known that the socket buffer is entirely in "low" memory.
>> > 
>> > Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont-xNZwKgViW5g@public.gmane.orgm>
>> 
>> Applied, thanks.
> 
> Hmm, this is already somewhere in linux-usb, from what I understood (I suppose 
> git-merge does not care much).

Yeah, it'll work itself out without any problems.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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

* [question] bond_set_slave_inactive_flags
From: Jiri Pirko @ 2011-03-01  7:43 UTC (permalink / raw)
  To: fubar; +Cc: netdev

Jay,

Looking at function bond_set_slave_inactive_flags:

static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
        struct bonding *bond = netdev_priv(slave->dev->master);
        if (!bond_is_lb(bond))
                slave->state = BOND_STATE_BACKUP;
        if (!bond->params.all_slaves_active)
                slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
        if (slave_do_arp_validate(bond, slave))
                slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}

Why BOND_STATE_BACKUP is set only for non-lb bonds?
This was introduced by 8f903c708fcc2b579ebf16542bf6109bad593a1d but
I do not see why.

Thanks for reply in advance.

Jirka

^ permalink raw reply

* Re: [PATCH] cxgb{3,4}*: improve Kconfig dependencies
From: Jan Beulich @ 2011-03-01  7:46 UTC (permalink / raw)
  To: Dimitris Michailidis; +Cc: linux-scsi, netdev
In-Reply-To: <1298950455-4497-1-git-send-email-dm@chelsio.com>

>>> On 01.03.11 at 04:34, Dimitris Michailidis <dm@chelsio.com> wrote:
> - Remove the dependency of cxgb4 and cxgb4vf on INET.  cxgb3 really
>   depends on INET, keep it but add it directly to the driver's Kconfig
>   entry.
> - Make the iSCSI drivers cxgb3i and cxgb4i available in the SCSI menu
>   without requiring any options in the net driver menu to be enabled
>   first.  Add needed selects so the iSCSI drivers can build their
>   corresponding net drivers.
> - Remove CHELSIO_T*_DEPENDS.
> 
> Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
> ---
>  drivers/net/Kconfig               |   21 +++------------------
>  drivers/scsi/cxgbi/cxgb3i/Kconfig |    4 +++-
>  drivers/scsi/cxgbi/cxgb4i/Kconfig |    4 +++-
>  3 files changed, 9 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index f4b3927..6e09d5f 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -2595,14 +2595,9 @@ config CHELSIO_T1_1G
>  	  Enables support for Chelsio's gigabit Ethernet PCI cards.  If you
>  	  are using only 10G cards say 'N' here.
>  
> -config CHELSIO_T3_DEPENDS
> -	tristate
> -	depends on PCI && INET
> -	default y
> -
>  config CHELSIO_T3
>  	tristate "Chelsio Communications T3 10Gb Ethernet support"
> -	depends on CHELSIO_T3_DEPENDS
> +	depends on PCI && INET

Forgot to remove INET here?

Besides that,
Acked-by: Jan Beulich <jbeulich@novell.com>

>  	select FW_LOADER
>  	select MDIO
>  	help
> @@ -2620,14 +2615,9 @@ config CHELSIO_T3
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called cxgb3.
>  
> -config CHELSIO_T4_DEPENDS
> -	tristate
> -	depends on PCI && INET
> -	default y
> -
>  config CHELSIO_T4
>  	tristate "Chelsio Communications T4 Ethernet support"
> -	depends on CHELSIO_T4_DEPENDS
> +	depends on PCI
>  	select FW_LOADER
>  	select MDIO
>  	help
> @@ -2645,14 +2635,9 @@ config CHELSIO_T4
>  	  To compile this driver as a module choose M here; the module
>  	  will be called cxgb4.
>  
> -config CHELSIO_T4VF_DEPENDS
> -	tristate
> -	depends on PCI && INET
> -	default y
> -
>  config CHELSIO_T4VF
>  	tristate "Chelsio Communications T4 Virtual Function Ethernet support"
> -	depends on CHELSIO_T4VF_DEPENDS
> +	depends on PCI
>  	help
>  	  This driver supports Chelsio T4-based gigabit and 10Gb Ethernet
>  	  adapters with PCI-E SR-IOV Virtual Functions.
> diff --git a/drivers/scsi/cxgbi/cxgb3i/Kconfig 
> b/drivers/scsi/cxgbi/cxgb3i/Kconfig
> index 5cf4e98..11dff23 100644
> --- a/drivers/scsi/cxgbi/cxgb3i/Kconfig
> +++ b/drivers/scsi/cxgbi/cxgb3i/Kconfig
> @@ -1,6 +1,8 @@
>  config SCSI_CXGB3_ISCSI
>  	tristate "Chelsio T3 iSCSI support"
> -	depends on CHELSIO_T3_DEPENDS
> +	depends on PCI && INET
> +	select NETDEVICES
> +	select NETDEV_10000
>  	select CHELSIO_T3
>  	select SCSI_ISCSI_ATTRS
>  	---help---
> diff --git a/drivers/scsi/cxgbi/cxgb4i/Kconfig 
> b/drivers/scsi/cxgbi/cxgb4i/Kconfig
> index bb94b39..d5302c2 100644
> --- a/drivers/scsi/cxgbi/cxgb4i/Kconfig
> +++ b/drivers/scsi/cxgbi/cxgb4i/Kconfig
> @@ -1,6 +1,8 @@
>  config SCSI_CXGB4_ISCSI
>  	tristate "Chelsio T4 iSCSI support"
> -	depends on CHELSIO_T4_DEPENDS
> +	depends on PCI && INET
> +	select NETDEVICES
> +	select NETDEV_10000
>  	select CHELSIO_T4
>  	select SCSI_ISCSI_ATTRS
>  	---help---





^ permalink raw reply

* [PATCH 0/4] rcu: don't assume the size of struct rcu_head
From: Lai Jiangshan @ 2011-03-01  8:03 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Christoph Lameter, Pekka Enberg, Eric Dumazet,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev


We always keep the struct rcu_head very small, but we may change it in future
or under some CONFIGs.

There are some other systems may assume the size of struct rcu_head as 2 * sizeof(long).
These assumptions obstruct us to add debug information or priority information
to struct rcu_head. It is time to fix them.

It is glad that I just find 3 places which need to be fixed. These 4 patches
are just cleanup patches when the size of struct rcu_head == 2 * sizeof(long).
NO overhead added and NO behavior changed.
Even when the size of struct rcu_head becomes larger, only slub is changed a little.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* [PATCH 1/4] slub: automatically reserve bytes at the end of slab
From: Lai Jiangshan @ 2011-03-01  8:03 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Christoph Lameter, Pekka Enberg, Eric Dumazet,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev

There is no "struct" for slub's slab, it shares with struct page.
But struct page is very small, it is insufficient when we need
to add some metadata for slab.

So we add a field "reserved" to struct kmem_cache, when a slab
is allocated, kmem_cache->reserved bytes are automatically reserved
at the end of the slab for slab's metadata.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
 include/linux/slub_def.h |    1 +
 mm/slub.c                |   40 +++++++++++++++++++++++-----------------
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 8b6e8ae..ae0093c 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -83,6 +83,7 @@ struct kmem_cache {
 	void (*ctor)(void *);
 	int inuse;		/* Offset to metadata */
 	int align;		/* Alignment */
+	int reserved;		/* Reserved bytes at the end of slabs */
 	unsigned long min_partial;
 	const char *name;	/* Name (only for display!) */
 	struct list_head list;	/* List of slab caches */
diff --git a/mm/slub.c b/mm/slub.c
index e15aa7f..ad545b2 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -281,11 +281,16 @@ static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
 	return (p - addr) / s->size;
 }
 
+static inline int order_objects(int order, unsigned long size, int reserved)
+{
+	return ((PAGE_SIZE << order) - reserved) / size;
+}
+
 static inline struct kmem_cache_order_objects oo_make(int order,
-						unsigned long size)
+		unsigned long size, int reserved)
 {
 	struct kmem_cache_order_objects x = {
-		(order << OO_SHIFT) + (PAGE_SIZE << order) / size
+		(order << OO_SHIFT) + order_objects(order, size, reserved)
 	};
 
 	return x;
@@ -617,7 +622,7 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
 		return 1;
 
 	start = page_address(page);
-	length = (PAGE_SIZE << compound_order(page));
+	length = (PAGE_SIZE << compound_order(page)) - s->reserved;
 	end = start + length;
 	remainder = length % s->size;
 	if (!remainder)
@@ -698,7 +703,7 @@ static int check_slab(struct kmem_cache *s, struct page *page)
 		return 0;
 	}
 
-	maxobj = (PAGE_SIZE << compound_order(page)) / s->size;
+	maxobj = order_objects(compound_order(page), s->size, s->reserved);
 	if (page->objects > maxobj) {
 		slab_err(s, page, "objects %u > max %u",
 			s->name, page->objects, maxobj);
@@ -748,7 +753,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 		nr++;
 	}
 
-	max_objects = (PAGE_SIZE << compound_order(page)) / s->size;
+	max_objects = order_objects(compound_order(page), s->size, s->reserved);
 	if (max_objects > MAX_OBJS_PER_PAGE)
 		max_objects = MAX_OBJS_PER_PAGE;
 
@@ -1988,13 +1993,13 @@ static int slub_nomerge;
  * the smallest order which will fit the object.
  */
 static inline int slab_order(int size, int min_objects,
-				int max_order, int fract_leftover)
+				int max_order, int fract_leftover, int reserved)
 {
 	int order;
 	int rem;
 	int min_order = slub_min_order;
 
-	if ((PAGE_SIZE << min_order) / size > MAX_OBJS_PER_PAGE)
+	if (order_objects(min_order, size, reserved) > MAX_OBJS_PER_PAGE)
 		return get_order(size * MAX_OBJS_PER_PAGE) - 1;
 
 	for (order = max(min_order,
@@ -2003,10 +2008,10 @@ static inline int slab_order(int size, int min_objects,
 
 		unsigned long slab_size = PAGE_SIZE << order;
 
-		if (slab_size < min_objects * size)
+		if (slab_size < min_objects * size + reserved)
 			continue;
 
-		rem = slab_size % size;
+		rem = (slab_size - reserved) % size;
 
 		if (rem <= slab_size / fract_leftover)
 			break;
@@ -2016,7 +2021,7 @@ static inline int slab_order(int size, int min_objects,
 	return order;
 }
 
-static inline int calculate_order(int size)
+static inline int calculate_order(int size, int reserved)
 {
 	int order;
 	int min_objects;
@@ -2034,14 +2039,14 @@ static inline int calculate_order(int size)
 	min_objects = slub_min_objects;
 	if (!min_objects)
 		min_objects = 4 * (fls(nr_cpu_ids) + 1);
-	max_objects = (PAGE_SIZE << slub_max_order)/size;
+	max_objects = order_objects(slub_max_order, size, reserved);
 	min_objects = min(min_objects, max_objects);
 
 	while (min_objects > 1) {
 		fraction = 16;
 		while (fraction >= 4) {
 			order = slab_order(size, min_objects,
-						slub_max_order, fraction);
+					slub_max_order, fraction, reserved);
 			if (order <= slub_max_order)
 				return order;
 			fraction /= 2;
@@ -2053,14 +2058,14 @@ static inline int calculate_order(int size)
 	 * We were unable to place multiple objects in a slab. Now
 	 * lets see if we can place a single object there.
 	 */
-	order = slab_order(size, 1, slub_max_order, 1);
+	order = slab_order(size, 1, slub_max_order, 1, reserved);
 	if (order <= slub_max_order)
 		return order;
 
 	/*
 	 * Doh this slab cannot be placed using slub_max_order.
 	 */
-	order = slab_order(size, 1, MAX_ORDER, 1);
+	order = slab_order(size, 1, MAX_ORDER, 1, reserved);
 	if (order < MAX_ORDER)
 		return order;
 	return -ENOSYS;
@@ -2311,7 +2316,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 	if (forced_order >= 0)
 		order = forced_order;
 	else
-		order = calculate_order(size);
+		order = calculate_order(size, s->reserved);
 
 	if (order < 0)
 		return 0;
@@ -2329,8 +2334,8 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 	/*
 	 * Determine the number of objects per slab
 	 */
-	s->oo = oo_make(order, size);
-	s->min = oo_make(get_order(size), size);
+	s->oo = oo_make(order, size, s->reserved);
+	s->min = oo_make(get_order(size), size, s->reserved);
 	if (oo_objects(s->oo) > oo_objects(s->max))
 		s->max = s->oo;
 
@@ -2349,6 +2354,7 @@ static int kmem_cache_open(struct kmem_cache *s,
 	s->objsize = size;
 	s->align = align;
 	s->flags = kmem_cache_flags(size, flags, name, ctor);
+	s->reserved = 0;
 
 	if (!calculate_sizes(s, -1))
 		goto error;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* [PATCH 2/4] slub,rcu: don't assume the size of struct rcu_head
From: Lai Jiangshan @ 2011-03-01  8:03 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Christoph Lameter, Pekka Enberg, Eric Dumazet,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev


The size of struct rcu_head may be changed. When it becomes larger,
it will pollute the page array.

We reserve some some bytes for struct rcu_head when a slab
is allocated in this situation.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
 slub.c |   30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index ad545b2..ceb135a 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1254,21 +1254,38 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
 	__free_pages(page, order);
 }
 
+#define need_reserve_slab_rcu						\
+	(sizeof(((struct page *)NULL)->lru) < sizeof(struct rcu_head))
+
 static void rcu_free_slab(struct rcu_head *h)
 {
 	struct page *page;
 
-	page = container_of((struct list_head *)h, struct page, lru);
+	if (need_reserve_slab_rcu)
+		page = virt_to_head_page(h);
+	else
+		page = container_of((struct list_head *)h, struct page, lru);
+
 	__free_slab(page->slab, page);
 }
 
 static void free_slab(struct kmem_cache *s, struct page *page)
 {
 	if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
-		/*
-		 * RCU free overloads the RCU head over the LRU
-		 */
-		struct rcu_head *head = (void *)&page->lru;
+		struct rcu_head *head;
+
+		if (need_reserve_slab_rcu) {
+			int order = compound_order(page);
+			int offset = (PAGE_SIZE << order) - s->reserved;
+
+			BUG_ON(s->reserved != sizeof(*head));
+			head = page_address(page) + offset;
+		} else {
+			/*
+			 * RCU free overloads the RCU head over the LRU
+			 */
+			head = (void *)&page->lru;
+		}
 
 		call_rcu(head, rcu_free_slab);
 	} else
@@ -2356,6 +2373,9 @@ static int kmem_cache_open(struct kmem_cache *s,
 	s->flags = kmem_cache_flags(size, flags, name, ctor);
 	s->reserved = 0;
 
+	if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
+		s->reserved = sizeof(struct rcu_head);
+
 	if (!calculate_sizes(s, -1))
 		goto error;
 	if (disable_higher_order_debug) {

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* [PATCH 3/4] slab,rcu: don't assume the size of struct rcu_head
From: Lai Jiangshan @ 2011-03-01  8:03 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Christoph Lameter, Pekka Enberg, Eric Dumazet,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev


The size of struct rcu_head may be changed. When it becomes larger,
it may pollute the data after struct slab.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
diff --git a/mm/slab.c b/mm/slab.c
index 37961d1..52cf0b4 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -191,22 +191,6 @@ typedef unsigned int kmem_bufctl_t;
 #define	SLAB_LIMIT	(((kmem_bufctl_t)(~0U))-3)
 
 /*
- * struct slab
- *
- * Manages the objs in a slab. Placed either at the beginning of mem allocated
- * for a slab, or allocated from an general cache.
- * Slabs are chained into three list: fully used, partial, fully free slabs.
- */
-struct slab {
-	struct list_head list;
-	unsigned long colouroff;
-	void *s_mem;		/* including colour offset */
-	unsigned int inuse;	/* num of objs active in slab */
-	kmem_bufctl_t free;
-	unsigned short nodeid;
-};
-
-/*
  * struct slab_rcu
  *
  * slab_destroy on a SLAB_DESTROY_BY_RCU cache uses this structure to
@@ -219,8 +203,6 @@ struct slab {
  *
  * rcu_read_lock before reading the address, then rcu_read_unlock after
  * taking the spinlock within the structure expected at that address.
- *
- * We assume struct slab_rcu can overlay struct slab when destroying.
  */
 struct slab_rcu {
 	struct rcu_head head;
@@ -229,6 +211,27 @@ struct slab_rcu {
 };
 
 /*
+ * struct slab
+ *
+ * Manages the objs in a slab. Placed either at the beginning of mem allocated
+ * for a slab, or allocated from an general cache.
+ * Slabs are chained into three list: fully used, partial, fully free slabs.
+ */
+struct slab {
+	union {
+		struct {
+			struct list_head list;
+			unsigned long colouroff;
+			void *s_mem;		/* including colour offset */
+			unsigned int inuse;	/* num of objs active in slab */
+			kmem_bufctl_t free;
+			unsigned short nodeid;
+		};
+		struct slab_rcu __slab_cover_slab_rcu;
+	};
+};
+
+/*
  * struct array_cache
  *
  * Purpose:

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* [PATCH 4/4] net,rcu: don't assume the size of struct rcu_head
From: Lai Jiangshan @ 2011-03-01  8:03 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Christoph Lameter, Pekka Enberg, Eric Dumazet,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev


struct dst_entry assumes the size of struct rcu_head as 2 * sizeof(long)
and manually adds pads for aligning for "__refcnt".

When the size of struct rcu_head is changed, these manual padding
is wrong. Use __attribute__((aligned (64))) instead.

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
diff --git a/include/net/dst.h b/include/net/dst.h
index 93b0310..4ef6c4a 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -62,8 +62,6 @@ struct dst_entry {
 	struct hh_cache		*hh;
 #ifdef CONFIG_XFRM
 	struct xfrm_state	*xfrm;
-#else
-	void			*__pad1;
 #endif
 	int			(*input)(struct sk_buff*);
 	int			(*output)(struct sk_buff*);
@@ -74,23 +72,18 @@ struct dst_entry {
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	__u32			tclassid;
-#else
-	__u32			__pad2;
 #endif
 
 
 	/*
 	 * Align __refcnt to a 64 bytes alignment
 	 * (L1_CACHE_SIZE would be too much)
-	 */
-#ifdef CONFIG_64BIT
-	long			__pad_to_align_refcnt[1];
-#endif
-	/*
+	 *
 	 * __refcnt wants to be on a different cache line from
 	 * input/output/ops or performance tanks badly
 	 */
-	atomic_t		__refcnt;	/* client references	*/
+	atomic_t		__refcnt	/* client references	*/
+				__attribute__((aligned (64)));
 	int			__use;
 	unsigned long		lastuse;
 	union {

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related

* Re: [PATCH 4/4] net,rcu: don't assume the size of struct rcu_head
From: David Miller @ 2011-03-01  8:16 UTC (permalink / raw)
  To: laijs
  Cc: mingo, paulmck, cl, penberg, eric.dumazet, mpm, linux-mm,
	linux-kernel, netdev
In-Reply-To: <4D6CA860.3020409@cn.fujitsu.com>

From: Lai Jiangshan <laijs@cn.fujitsu.com>
Date: Tue, 01 Mar 2011 16:03:44 +0800

> 
> struct dst_entry assumes the size of struct rcu_head as 2 * sizeof(long)
> and manually adds pads for aligning for "__refcnt".
> 
> When the size of struct rcu_head is changed, these manual padding
> is wrong. Use __attribute__((aligned (64))) instead.
> 
> Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>

We don't want to use the align if it's going to waste lots of space.

Instead we want to rearrange the structure so that the alignment comes
more cheaply.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH 4/4] net,rcu: don't assume the size of struct rcu_head
From: Eric Dumazet @ 2011-03-01  8:20 UTC (permalink / raw)
  To: Lai Jiangshan
  Cc: Ingo Molnar, Paul E. McKenney, Christoph Lameter, Pekka Enberg,
	David S. Miller, Matt Mackall, linux-mm, linux-kernel, netdev
In-Reply-To: <4D6CA860.3020409@cn.fujitsu.com>

Le mardi 01 mars 2011 à 16:03 +0800, Lai Jiangshan a écrit :
> struct dst_entry assumes the size of struct rcu_head as 2 * sizeof(long)
> and manually adds pads for aligning for "__refcnt".
> 
> When the size of struct rcu_head is changed, these manual padding
> is wrong. Use __attribute__((aligned (64))) instead.
> 
> Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
> ---

> diff --git a/include/net/dst.h b/include/net/dst.h
> index 93b0310..4ef6c4a 100644
> --- a/include/net/dst.h
> +++ b/include/net/dst.h
> @@ -62,8 +62,6 @@ struct dst_entry {
>  	struct hh_cache		*hh;
>  #ifdef CONFIG_XFRM
>  	struct xfrm_state	*xfrm;
> -#else
> -	void			*__pad1;
>  #endif
>  	int			(*input)(struct sk_buff*);
>  	int			(*output)(struct sk_buff*);
> @@ -74,23 +72,18 @@ struct dst_entry {
>  
>  #ifdef CONFIG_NET_CLS_ROUTE
>  	__u32			tclassid;
> -#else
> -	__u32			__pad2;
>  #endif
>  
> 
>  	/*
>  	 * Align __refcnt to a 64 bytes alignment
>  	 * (L1_CACHE_SIZE would be too much)
> -	 */
> -#ifdef CONFIG_64BIT
> -	long			__pad_to_align_refcnt[1];
> -#endif
> -	/*
> +	 *
>  	 * __refcnt wants to be on a different cache line from
>  	 * input/output/ops or performance tanks badly
>  	 */
> -	atomic_t		__refcnt;	/* client references	*/
> +	atomic_t		__refcnt	/* client references	*/
> +				__attribute__((aligned (64)));
>  	int			__use;
>  	unsigned long		lastuse;
>  	union {

If struct rcu_head is bigger, this is for debugging purposes, so we dont
care about performance, and can avoid wasting ~64 bytes.

Some machines still have about 2.000.000 active dst entries : the
convoluted checks we added in include/net/dst.h are here to make sure we
dont have huge holes in the dst structure.

(This might change when/if IP route cache is gone)



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH 4/4] net,rcu: don't assume the size of struct rcu_head
From: Eric Dumazet @ 2011-03-01  8:20 UTC (permalink / raw)
  To: David Miller
  Cc: laijs, mingo, paulmck, cl, penberg, mpm, linux-mm, linux-kernel,
	netdev
In-Reply-To: <20110301.001638.104075130.davem@davemloft.net>

Le mardi 01 mars 2011 à 00:16 -0800, David Miller a écrit :
> From: Lai Jiangshan <laijs@cn.fujitsu.com>
> Date: Tue, 01 Mar 2011 16:03:44 +0800
> 
> > 
> > struct dst_entry assumes the size of struct rcu_head as 2 * sizeof(long)
> > and manually adds pads for aligning for "__refcnt".
> > 
> > When the size of struct rcu_head is changed, these manual padding
> > is wrong. Use __attribute__((aligned (64))) instead.
> > 
> > Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
> 
> We don't want to use the align if it's going to waste lots of space.
> 
> Instead we want to rearrange the structure so that the alignment comes
> more cheaply.

Oh well, I should have read your answer before sending mine :)



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: net: allow handlers to be processed for orig_dev
From: Nicolas de Pesloüan @ 2011-03-01  8:24 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev, davem, shemminger, kaber, fubar, eric.dumazet, andy
In-Reply-To: <20110301062631.GC2855@psychotron.redhat.com>

Le 01/03/2011 07:26, Jiri Pirko a écrit :
> This was there before, I forgot about this. Allows deliveries to
> ptype_base handlers registered for orig_dev. I presume this is still
> desired.

Yes, it is. Sorry for missing it in my review.

> Signed-off-by: Jiri Pirko<jpirko@redhat.com>

Reviewed-by: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>

> ---
>   net/core/dev.c |    3 ++-
>   1 files changed, 2 insertions(+), 1 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 30440e7..9f66de9 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -3208,7 +3208,8 @@ ncls:
>   	list_for_each_entry_rcu(ptype,
>   			&ptype_base[ntohs(type)&  PTYPE_HASH_MASK], list) {
>   		if (ptype->type == type&&
> -		    (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
> +		    (ptype->dev == null_or_dev || ptype->dev == skb->dev ||
> +		     ptype->dev == orig_dev)) {
>   			if (pt_prev)
>   				ret = deliver_skb(skb, pt_prev, orig_dev);
>   			pt_prev = ptype;


^ permalink raw reply

* ICMP reply uses wrong source address as destinatio
From: Anders Nilsson Plymoth @ 2011-03-01  8:49 UTC (permalink / raw)
  To: netdev

Dear linux kernel enthusiasts,

I came upon an issue where ICMP reply packets were issued towards the
IP address of the receiving interface, rather than the source IP
address.
Looking at the kernel code, I saw that this is caused by the following
line in net/ipv4/icmp.c function icmp_reply:

daddr = ipc.addr = rt->rt_src;

For most cases the original line of code is ok, but in some situations
doesn't arrive to the kernel from the network device, but through some
other mechanism such as a userspace application. In these cases the
receiving device in the skb appears to be the loopback interface, not
a physical device. icmp_reply will thus issue the reply to the
loopback IP address, rather than the source IP address as it should.

While googling to see if this issue have been submitted, I found this
two posts that address the same problem:
h**p://www.mail-archive.com/linux-kernel@vger.kernel.org/msg209746.html
h**p://www.mail-archive.com/linux-kernel@vger.kernel.org/msg208272.html
Some of the questions there are easy to answer; such as this doesn't
affect DNAT, and if source address is not set then you can' reply
anyway.

As to the statement:
"... which IP address should be used as the source

1. the destination address of the packet that generated the message

or.

2. the IP address that the machine would use by default if the machine
were to generate a new connection to the destination."

These may be relevant questions, but the ICMP RFC clearly states the
answer is 1. 2. may seem relevant to multi-homing, but its not the
role of the ICMP reply to resolve multi-homing issues.

The following code will correct the issue.

{
   struct iphdr *ip = ip_hdr(skb);
   daddr = ipc.addr = ip->saddr;
}

The only functions that use icmp_reply are icmp_echo and
icmp_timestamp, and this change do not modify their behavior. After
extensive testing, in regular setups and DNATed situations, I can
verify this change works as intended.

Thanks,
Anders

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox