Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next-2.6] bridge: Fix build error when IGMP_SNOOPING is not enabled
From: Randy Dunlap @ 2010-03-01 20:54 UTC (permalink / raw)
  To: Sridhar Samudrala; +Cc: Herbert Xu, David Miller, netdev
In-Reply-To: <1267473184.31728.7.camel@w-sridhar.beaverton.ibm.com>

On 03/01/10 11:53, Sridhar Samudrala wrote:
> Fix the following build error when IGMP_SNOOPING is not enabled.
> In file included from net/bridge/br.c:24:
> net/bridge/br_private.h: In function 'br_multicast_is_router':
> net/bridge/br_private.h:361: error: 'struct net_bridge' has no member named 'multicast_router'
> net/bridge/br_private.h:362: error: 'struct net_bridge' has no member named 'multicast_router'
> net/bridge/br_private.h:363: error: 'struct net_bridge' has no member named 'multicast_router_timer'
> 
> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
> 
> diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
> index 9191198..1cf2cef 100644
> --- a/net/bridge/br_private.h
> +++ b/net/bridge/br_private.h
> @@ -302,6 +302,13 @@ extern int br_multicast_set_port_router(struct net_bridge_port *p,
>  					unsigned long val);
>  extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
>  extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
> +
> +static inline bool br_multicast_is_router(struct net_bridge *br)
> +{
> +	return br->multicast_router == 2 ||
> +	       (br->multicast_router == 1 &&
> +		timer_pending(&br->multicast_router_timer));
> +}
>  #else
>  static inline int br_multicast_rcv(struct net_bridge *br,
>  				   struct net_bridge_port *port,
> @@ -354,14 +361,11 @@ static inline void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
>  					struct sk_buff *skb2)
>  {
>  }
> -#endif
> -
>  static inline bool br_multicast_is_router(struct net_bridge *br)
>  {
> -	return br->multicast_router == 2 ||
> -	       (br->multicast_router == 1 &&
> -		timer_pending(&br->multicast_router_timer));
> +	return 0;
>  }
> +#endif
>  
>  /* br_netfilter.c */
>  #ifdef CONFIG_BRIDGE_NETFILTER
> 
> 
> --

Acked-by: Randy Dunlap <randy.dunlap@oracle.com>


Thanks.
-- 
~Randy

^ permalink raw reply

* Re: linux-next: Tree for March 1 (bluetooth/hci_sysfs)
From: Randy Dunlap @ 2010-03-01 21:08 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: linux-next, LKML, Marcel Holtmann, linux-bluetooth, Netdev
In-Reply-To: <20100301210210.c6f465e6.sfr@canb.auug.org.au>

On 03/01/10 02:02, Stephen Rothwell wrote:
> Hi all,
> 
> Changes since 20100226:
> 
> We are seeing conflicts migrate from being between 2 trees in linux-next
> to be between a tree and Linus' tree as things start to get merged.
> 
> 
> The net tree gained a conflict against Linus' tree.

static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct hci_dev *hdev = file->private_data;
	struct inquiry_cache *cache = &hdev->inq_cache;
	struct inquiry_entry *e;
	char buf[4096]; // <<<<<<<<<<<<<<<<<<<<<<<<<<< huh? don't do that on stack.
	int n = 0;


-- 
~Randy

^ permalink raw reply

* Re: Was: Re: [RFC PATCH] fix problems with NETIF_F_HIGHDMA in networking, Now: SWIOTLB dynamic allocation
From: Robert Hancock @ 2010-03-01 21:12 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: David Miller, fujita.tomonori, bzolnier, linux-kernel, netdev,
	linux-usb
In-Reply-To: <20100301163437.GE7881@phenom.dumpdata.com>

On Mon, Mar 1, 2010 at 10:34 AM, Konrad Rzeszutek Wilk
<konrad.wilk@oracle.com> wrote:
> On Sun, Feb 28, 2010 at 12:16:28AM -0800, David Miller wrote:
>> From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
>> Date: Sun, 28 Feb 2010 03:38:19 +0900
>>
>> > When I proposed such approach (always use swiotlb) before, IIRC,
>> > the objections were:
>> >
>> > - better to make allocation respect dma_mask. (I don't think that this
>> >   approach is possible since we don't know which device handles data
>> >   later when we allocate memory).
>>
>> And such objects might end up being processed by multiple devices with
>> different DMA restrictions.
>>
>> > - swiotlb is not good for small systems since it allocates too much
>> >   memory (we can fix this though).
>>
>> Indeed.
>
> What would be a good mechanism for this? Enumerating all of the PCI
> devices to find out which ones are 32-bit and then allocate some chunk
> of memory based on the amount of them? say, 1MB per card?
>
> Or maybe a simpler one - figure out how many pages we have an allocate
> based on some sliding rule (say, 8MB for under 512MB, 16MB between 512MB
> and 2GB, and 32MB for 2GB to 4GB, and after that the full 64MB?)

Why do we need to allocate SWIOTLB if your highest memory address is
under 4GB? You can just disable it in that case, like x86_64 does.

^ permalink raw reply

* [PATCH net-next] drivers/net/e100.c: Use pr_<level> and netif_<level>
From: Joe Perches @ 2010-03-01 21:16 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: David Miller, netdev, Jesse Brandeburg, Bruce Allan, Alex Duyck,
	PJ Waskiewicz, John Ronciak, Andrew Gallatin, Brice Goglin,
	linux-kernel, e1000-devel
In-Reply-To: <9929d2391002231833j65008a1ev1d2297672a39a483@mail.gmail.com>

Convert DPRINTK, commonly used for debugging, to netif_<level>
Remove #define PFX
Use #define pr_fmt
Consistently use no periods for non-sentence logging messages

Signed-off-by: Joe Perches <joe@perches.com>
---
 drivers/net/e100.c |  183 ++++++++++++++++++++++++++++------------------------
 1 files changed, 98 insertions(+), 85 deletions(-)

diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index a26ccab..c33d12a 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -147,6 +147,8 @@
  *      - add clean lowlevel I/O emulation for cards with MII-lacking PHYs
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
@@ -174,7 +176,6 @@
 #define DRV_VERSION		"3.5.24-k2"DRV_EXT
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel Corporation"
-#define PFX			DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD	(2 * HZ)
 #define E100_NAPI_WEIGHT	16
@@ -200,10 +201,6 @@ module_param(use_io, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
 MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
-#define DPRINTK(nlevel, klevel, fmt, args...) \
-	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
-	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
-		__func__ , ## args))
 
 #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
 	PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
@@ -689,12 +686,13 @@ static int e100_self_test(struct nic *nic)
 
 	/* Check results of self-test */
 	if (nic->mem->selftest.result != 0) {
-		DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",
-			nic->mem->selftest.result);
+		netif_err(nic, hw, nic->netdev,
+			  "Self-test failed: result=0x%08X\n",
+			  nic->mem->selftest.result);
 		return -ETIMEDOUT;
 	}
 	if (nic->mem->selftest.signature == 0) {
-		DPRINTK(HW, ERR, "Self-test failed: timed out\n");
+		netif_err(nic, hw, nic->netdev, "Self-test failed: timed out\n");
 		return -ETIMEDOUT;
 	}
 
@@ -797,7 +795,7 @@ static int e100_eeprom_load(struct nic *nic)
 	/* The checksum, stored in the last word, is calculated such that
 	 * the sum of words should be 0xBABA */
 	if (cpu_to_le16(0xBABA - checksum) != nic->eeprom[nic->eeprom_wc - 1]) {
-		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
+		netif_err(nic, probe, nic->netdev, "EEPROM corrupted\n");
 		if (!eeprom_bad_csum_allow)
 			return -EAGAIN;
 	}
@@ -953,8 +951,7 @@ static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
 		udelay(20);
 	}
 	if (unlikely(!i)) {
-		printk("e100.mdio_ctrl(%s) won't go Ready\n",
-			nic->netdev->name );
+		netdev_err(nic->netdev, "e100.mdio_ctrl won't go Ready\n");
 		spin_unlock_irqrestore(&nic->mdio_lock, flags);
 		return 0;		/* No way to indicate timeout error */
 	}
@@ -966,9 +963,10 @@ static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
 			break;
 	}
 	spin_unlock_irqrestore(&nic->mdio_lock, flags);
-	DPRINTK(HW, DEBUG,
-		"%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
-		dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
+		     dir == mdi_read ? "READ" : "WRITE",
+		     addr, reg, data, data_out);
 	return (u16)data_out;
 }
 
@@ -1028,17 +1026,19 @@ static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic,
 			return	ADVERTISE_10HALF |
 				ADVERTISE_10FULL;
 		default:
-			DPRINTK(HW, DEBUG,
-		"%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
-		dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+			netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+				     "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+				     dir == mdi_read ? "READ" : "WRITE",
+				     addr, reg, data);
 			return 0xFFFF;
 		}
 	} else {
 		switch (reg) {
 		default:
-			DPRINTK(HW, DEBUG,
-		"%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
-		dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+			netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+				     "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+				     dir == mdi_read ? "READ" : "WRITE",
+				     addr, reg, data);
 			return 0xFFFF;
 		}
 	}
@@ -1155,12 +1155,15 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
 		}
 	}
 
-	DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
-	DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
-	DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-		c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		     c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		     c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		     c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
 }
 
 /*************************************************************************
@@ -1253,16 +1256,18 @@ static const struct firmware *e100_request_firmware(struct nic *nic)
 		err = request_firmware(&fw, fw_name, &nic->pdev->dev);
 
 	if (err) {
-		DPRINTK(PROBE, ERR, "Failed to load firmware \"%s\": %d\n",
-			fw_name, err);
+		netif_err(nic, probe, nic->netdev,
+			  "Failed to load firmware \"%s\": %d\n",
+			  fw_name, err);
 		return ERR_PTR(err);
 	}
 
 	/* Firmware should be precisely UCODE_SIZE (words) plus three bytes
 	   indicating the offsets for BUNDLESMALL, BUNDLEMAX, INTDELAY */
 	if (fw->size != UCODE_SIZE * 4 + 3) {
-		DPRINTK(PROBE, ERR, "Firmware \"%s\" has wrong size %zu\n",
-			fw_name, fw->size);
+		netif_err(nic, probe, nic->netdev,
+			  "Firmware \"%s\" has wrong size %zu\n",
+			  fw_name, fw->size);
 		release_firmware(fw);
 		return ERR_PTR(-EINVAL);
 	}
@@ -1274,9 +1279,9 @@ static const struct firmware *e100_request_firmware(struct nic *nic)
 
 	if (timer >= UCODE_SIZE || bundle >= UCODE_SIZE ||
 	    min_size >= UCODE_SIZE) {
-		DPRINTK(PROBE, ERR,
-			"\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n",
-			fw_name, timer, bundle, min_size);
+		netif_err(nic, probe, nic->netdev,
+			  "\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n",
+			  fw_name, timer, bundle, min_size);
 		release_firmware(fw);
 		return ERR_PTR(-EINVAL);
 	}
@@ -1328,7 +1333,8 @@ static inline int e100_load_ucode_wait(struct nic *nic)
 		return PTR_ERR(fw);
 
 	if ((err = e100_exec_cb(nic, (void *)fw, e100_setup_ucode)))
-		DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err);
+		netif_err(nic, probe, nic->netdev,
+			  "ucode cmd failed with error %d\n", err);
 
 	/* must restart cuc */
 	nic->cuc_cmd = cuc_start;
@@ -1348,7 +1354,7 @@ static inline int e100_load_ucode_wait(struct nic *nic)
 
 	/* if the command failed, or is not OK, notify and return */
 	if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
-		DPRINTK(PROBE,ERR, "ucode load failed\n");
+		netif_err(nic, probe, nic->netdev, "ucode load failed\n");
 		err = -EPERM;
 	}
 
@@ -1386,8 +1392,8 @@ static int e100_phy_check_without_mii(struct nic *nic)
 		 * media is sensed automatically based on how the link partner
 		 * is configured.  This is, in essence, manual configuration.
 		 */
-		DPRINTK(PROBE, INFO,
-			 "found MII-less i82503 or 80c24 or other PHY\n");
+		netif_info(nic, probe, nic->netdev,
+			   "found MII-less i82503 or 80c24 or other PHY\n");
 
 		nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated;
 		nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */
@@ -1434,18 +1440,20 @@ static int e100_phy_init(struct nic *nic)
 			return 0; /* simply return and hope for the best */
 		else {
 			/* for unknown cases log a fatal error */
-			DPRINTK(HW, ERR,
-				"Failed to locate any known PHY, aborting.\n");
+			netif_err(nic, hw, nic->netdev,
+				  "Failed to locate any known PHY, aborting\n");
 			return -EAGAIN;
 		}
 	} else
-		DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
+		netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+			     "phy_addr = %d\n", nic->mii.phy_id);
 
 	/* Get phy ID */
 	id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
 	id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);
 	nic->phy = (u32)id_hi << 16 | (u32)id_lo;
-	DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "phy ID = 0x%08X\n", nic->phy);
 
 	/* Select the phy and isolate the rest */
 	for (addr = 0; addr < 32; addr++) {
@@ -1507,7 +1515,7 @@ static int e100_hw_init(struct nic *nic)
 
 	e100_hw_reset(nic);
 
-	DPRINTK(HW, ERR, "e100_hw_init\n");
+	netif_err(nic, hw, nic->netdev, "e100_hw_init\n");
 	if (!in_interrupt() && (err = e100_self_test(nic)))
 		return err;
 
@@ -1555,8 +1563,9 @@ static void e100_set_multicast_list(struct net_device *netdev)
 {
 	struct nic *nic = netdev_priv(netdev);
 
-	DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
-		netdev_mc_count(netdev), netdev->flags);
+	netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+		     "mc_count=%d, flags=0x%04X\n",
+		     netdev_mc_count(netdev), netdev->flags);
 
 	if (netdev->flags & IFF_PROMISC)
 		nic->flags |= promiscuous;
@@ -1629,7 +1638,8 @@ static void e100_update_stats(struct nic *nic)
 
 
 	if (e100_exec_cmd(nic, cuc_dump_reset, 0))
-		DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
+		netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+			     "exec cuc_dump_reset failed\n");
 }
 
 static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
@@ -1659,20 +1669,19 @@ static void e100_watchdog(unsigned long data)
 	struct nic *nic = (struct nic *)data;
 	struct ethtool_cmd cmd;
 
-	DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies);
+	netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
+		     "right now = %ld\n", jiffies);
 
 	/* mii library handles link maintenance tasks */
 
 	mii_ethtool_gset(&nic->mii, &cmd);
 
 	if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
-		printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n",
-		       nic->netdev->name,
-		       cmd.speed == SPEED_100 ? "100" : "10",
-		       cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
+		netdev_info(nic->netdev, "NIC Link is Up %u Mbps %s Duplex\n",
+			    cmd.speed == SPEED_100 ? 100 : 10,
+			    cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
 	} else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
-		printk(KERN_INFO "e100: %s NIC Link is Down\n",
-		       nic->netdev->name);
+		netdev_info(nic->netdev, "NIC Link is Down\n");
 	}
 
 	mii_check_link(&nic->mii);
@@ -1732,7 +1741,8 @@ static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
 		   Issue a NOP command followed by a 1us delay before
 		   issuing the Tx command. */
 		if (e100_exec_cmd(nic, cuc_nop, 0))
-			DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
+			netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+				     "exec cuc_nop failed\n");
 		udelay(1);
 	}
 
@@ -1741,12 +1751,14 @@ static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
 	switch (err) {
 	case -ENOSPC:
 		/* We queued the skb, but now we're out of space. */
-		DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
+		netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+			     "No space for CB\n");
 		netif_stop_queue(netdev);
 		break;
 	case -ENOMEM:
 		/* This is a hard error - log it. */
-		DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");
+		netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+			     "Out of Tx resources, returning skb\n");
 		netif_stop_queue(netdev);
 		return NETDEV_TX_BUSY;
 	}
@@ -1767,9 +1779,10 @@ static int e100_tx_clean(struct nic *nic)
 	for (cb = nic->cb_to_clean;
 	    cb->status & cpu_to_le16(cb_complete);
 	    cb = nic->cb_to_clean = cb->next) {
-		DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
-		        (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
-		        cb->status);
+		netif_printk(nic, tx_done, KERN_DEBUG, nic->netdev,
+			     "cb[%d]->status = 0x%04X\n",
+			     (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
+			     cb->status);
 
 		if (likely(cb->skb != NULL)) {
 			dev->stats.tx_packets++;
@@ -1912,7 +1925,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 		sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
 	rfd_status = le16_to_cpu(rfd->status);
 
-	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
+	netif_printk(nic, rx_status, KERN_DEBUG, nic->netdev,
+		     "status=0x%04X\n", rfd_status);
 
 	/* If data isn't ready, nothing to indicate */
 	if (unlikely(!(rfd_status & cb_complete))) {
@@ -2123,7 +2137,8 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
 	struct nic *nic = netdev_priv(netdev);
 	u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
 
-	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
+	netif_printk(nic, intr, KERN_DEBUG, nic->netdev,
+		     "stat_ack = 0x%02X\n", stat_ack);
 
 	if (stat_ack == stat_ack_not_ours ||	/* Not our interrupt */
 	   stat_ack == stat_ack_not_present)	/* Hardware is ejected */
@@ -2263,8 +2278,8 @@ static void e100_tx_timeout_task(struct work_struct *work)
 	struct nic *nic = container_of(work, struct nic, tx_timeout_task);
 	struct net_device *netdev = nic->netdev;
 
-	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
-		ioread8(&nic->csr->scb.status));
+	netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+		     "scb.status=0x%02X\n", ioread8(&nic->csr->scb.status));
 	e100_down(netdev_priv(netdev));
 	e100_up(netdev_priv(netdev));
 }
@@ -2526,8 +2541,8 @@ static int e100_set_ringparam(struct net_device *netdev,
 	rfds->count = min(rfds->count, rfds->max);
 	cbs->count = max(ring->tx_pending, cbs->min);
 	cbs->count = min(cbs->count, cbs->max);
-	DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
-	        rfds->count, cbs->count);
+	netif_info(nic, drv, nic->netdev, "Ring Param settings: rx: %d, tx %d\n",
+		   rfds->count, cbs->count);
 	if (netif_running(netdev))
 		e100_up(nic);
 
@@ -2704,7 +2719,7 @@ static int e100_open(struct net_device *netdev)
 
 	netif_carrier_off(netdev);
 	if ((err = e100_up(nic)))
-		DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
+		netif_err(nic, ifup, nic->netdev, "Cannot open interface, aborting\n");
 	return err;
 }
 
@@ -2738,7 +2753,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
 	if (!(netdev = alloc_etherdev(sizeof(struct nic)))) {
 		if (((1 << debug) - 1) & NETIF_MSG_PROBE)
-			printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
+			pr_err("Etherdev alloc failed, aborting\n");
 		return -ENOMEM;
 	}
 
@@ -2756,35 +2771,34 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 	pci_set_drvdata(pdev, netdev);
 
 	if ((err = pci_enable_device(pdev))) {
-		DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot enable PCI device, aborting\n");
 		goto err_out_free_dev;
 	}
 
 	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-		DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
-			"base address, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot find proper PCI device base address, aborting\n");
 		err = -ENODEV;
 		goto err_out_disable_pdev;
 	}
 
 	if ((err = pci_request_regions(pdev, DRV_NAME))) {
-		DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot obtain PCI resources, aborting\n");
 		goto err_out_disable_pdev;
 	}
 
 	if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) {
-		DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "No usable DMA configuration, aborting\n");
 		goto err_out_free_res;
 	}
 
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	if (use_io)
-		DPRINTK(PROBE, INFO, "using i/o access mode\n");
+		netif_info(nic, probe, nic->netdev, "using i/o access mode\n");
 
 	nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
 	if (!nic->csr) {
-		DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot map device registers, aborting\n");
 		err = -ENOMEM;
 		goto err_out_free_res;
 	}
@@ -2818,7 +2832,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 	INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
 
 	if ((err = e100_alloc(nic))) {
-		DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot alloc driver memory, aborting\n");
 		goto err_out_iounmap;
 	}
 
@@ -2831,13 +2845,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 	memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
 	if (!is_valid_ether_addr(netdev->perm_addr)) {
 		if (!eeprom_bad_csum_allow) {
-			DPRINTK(PROBE, ERR, "Invalid MAC address from "
-			        "EEPROM, aborting.\n");
+			netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n");
 			err = -EAGAIN;
 			goto err_out_free;
 		} else {
-			DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
-			        "you MUST configure one.\n");
+			netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, you MUST configure one.\n");
 		}
 	}
 
@@ -2853,7 +2865,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
 	strcpy(netdev->name, "eth%d");
 	if ((err = register_netdev(netdev))) {
-		DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
+		netif_err(nic, probe, nic->netdev, "Cannot register net device, aborting\n");
 		goto err_out_free;
 	}
 	nic->cbs_pool = pci_pool_create(netdev->name,
@@ -2861,9 +2873,10 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 			   nic->params.cbs.count * sizeof(struct cb),
 			   sizeof(u32),
 			   0);
-	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
-		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
-		pdev->irq, netdev->dev_addr);
+	netif_info(nic, probe, nic->netdev,
+		   "addr 0x%llx, irq %d, MAC addr %pM\n",
+		   (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+		   pdev->irq, netdev->dev_addr);
 
 	return 0;
 
@@ -3021,7 +3034,7 @@ static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev)
 	struct nic *nic = netdev_priv(netdev);
 
 	if (pci_enable_device(pdev)) {
-		printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n");
+		pr_err("Cannot re-enable PCI device after reset\n");
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
 	pci_set_master(pdev);
@@ -3080,8 +3093,8 @@ static struct pci_driver e100_driver = {
 static int __init e100_init_module(void)
 {
 	if (((1 << debug) - 1) & NETIF_MSG_DRV) {
-		printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
-		printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+		pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+		pr_info("%s\n", DRV_COPYRIGHT);
 	}
 	return pci_register_driver(&e100_driver);
 }

^ permalink raw reply related

* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Eric W. Biederman @ 2010-03-01 21:42 UTC (permalink / raw)
  To: Daniel Lezcano
  Cc: Pavel Emelyanov, hadi, Patrick McHardy, Linux Netdev List,
	containers, Netfilter Development Mailinglist, Ben Greear,
	Serge Hallyn, Matt Helsley
In-Reply-To: <4B8AE8C1.1030305@free.fr>

Daniel Lezcano <daniel.lezcano@free.fr> writes:

> I agree with all the points you and Pavel you talked about but I don't feel
> comfortable to have the current process to switch the pid namespace because of
> the process tree hierarchy (what will be the parent of the process when you
> enter the pid namespace for example). What is the difference with the sys_bindns
> or the sys_hijack, proposed a couple of years ago ?

I think what has changed is:
- We have mostly completed most of the namespace work.
- We have operational experience with the current namespaces.
- We have people not in the core containers group feeling the pain
  of not having some of these features.

So I think we are at point where we can perhaps talk about these
things and finally solve some of these issues.

Clearly how to enter a container is on your and Pavel's mind as big
concerns.  I am aiming a little lower.

I am of two mind about my patches.  Right now they are a brilliant
proof of concept that we can name namespaces without needing a
namespace for the names of namespaces, and start to be a practical
solution to the join problem.   At the same time, I'm not certain
I like a solution that requires yet more syscalls so I ask myself
is there not yet a simpler way.

Hopefully we can resolve something before the next merge window.

Eric

^ permalink raw reply

* Hospitals - 23,747 Hospital Administrators in over 7,145 Hospitals (full contact info no emails)
From: Everett litigate @ 2010-03-01 21:46 UTC (permalink / raw)
  To: caniond, kay.hairclinic, good4seo, resume.cn, misecretservice

For details, samples and counts on our US listings please
email me at my other email address  Dominic.Farris@fastlist.Co.CC

  




Forward email to rembox@fastlist.Co.CC to purge you from our records

^ permalink raw reply

* [RFC] ppp: Bridge Control Protocol
From: Stephen Hemminger @ 2010-03-01 22:59 UTC (permalink / raw)
  To: David, "Miller <davem", Paul Mackerras
  Cc: linux-ppp, bridge, netdev, dane

This is a port of an old patch to provide BCP support.
BCP allows bridging PPP tunnels, it useful to do bridging between
virtualized environments. Original patch was done by
Dan Eble but was for 2.4.21.

Note: still needs testing. Does anyone have hardware to make
sure this interoperates with other implementations?

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
 drivers/net/Kconfig       |    7 
 drivers/net/ppp_generic.c |  359 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/ppp_defs.h  |   31 +++
 3 files changed, 385 insertions(+), 12 deletions(-)

--- a/include/linux/ppp_defs.h	2009-12-26 13:40:48.000000000 -0800
+++ b/include/linux/ppp_defs.h	2010-03-01 14:50:10.973353622 -0800
@@ -70,15 +70,18 @@
 #define PPP_IPX		0x2b	/* IPX protocol */
 #define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
 #define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_BRIDGE	0x31	/* Bridged LAN traffic or BPDU */
 #define PPP_MP		0x3d	/* Multilink protocol */
 #define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
 #define PPP_COMPFRAG	0xfb	/* fragment compressed below bundle */
 #define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_BPDU_IEEE	0x0201	/* IEEE 802.1 (D or G) bridge PDU */
 #define PPP_MPLS_UC	0x0281	/* Multi Protocol Label Switching - Unicast */
 #define PPP_MPLS_MC	0x0283	/* Multi Protocol Label Switching - Multicast */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol */
+#define PPP_BCP		0x8031	/* Bridging Control Protocol */
 #define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCPFRAG	0x80fb	/* CCP at link level (below MP bundle) */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
@@ -181,4 +184,32 @@ struct ppp_idle {
     __kernel_time_t recv_idle;	/* time since last NP packet received */
 };
 
+/*
+ * Bridging Control Protocol (BCP)
+ */
+struct bcp_hdr {
+	u8	flags;
+	u8	mactype;
+	u8	padbyte;	/* not used (present when "control" is also) */
+	u8	control;	/* 802.4, 802.5, and FDDI only */
+};
+#define BCP_802_3_HDRLEN	2
+
+/*
+ * Fields in bcp_hdr flags.
+ */
+#define BCP_LAN_FCS		0x80	/* set when LAN FCS is present */
+#define BCP_ZERO_PAD		0x20	/* set to pad 802.3 to min size */
+#define BCP_PADS_MASK		0x0F	/* 0-15 bytes padding before PPP FCS */
+
+/*
+ * Values for bcp_hdr mactype.
+ */
+#define BCP_MAC_802_3		0x01	/* 802.3 / Ethernet */
+#define BCP_MAC_802_4		0x02
+#define BCP_MAC_802_5_NC	0x03	/* with non-canonical address */
+#define BCP_MAC_FDDI_NC		0x04	/* with non-canonical address */
+#define BCP_MAC_802_5		0x0B	/* with canonical address */
+#define BCP_MAC_FDDI		0x0C	/* with canonical address */
+
 #endif /* _PPP_DEFS_H_ */
--- a/drivers/net/ppp_generic.c	2010-02-17 09:31:54.707473382 -0800
+++ b/drivers/net/ppp_generic.c	2010-03-01 14:51:49.439297517 -0800
@@ -29,6 +29,7 @@
 #include <linux/list.h>
 #include <linux/idr.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
 #include <linux/filter.h>
@@ -64,7 +65,9 @@
 #define NP_AT	3		/* Appletalk protocol */
 #define NP_MPLS_UC 4		/* MPLS unicast */
 #define NP_MPLS_MC 5		/* MPLS multicast */
-#define NUM_NP	6		/* Number of NPs. */
+#define NP_BRIDGE	6	/* Bridged LAN packets */
+#define NP_BPDU_IEEE	7	/* IEEE 802.1 (D or G) bridge PDU */
+#define NUM_NP	8		/* Number of NPs. */
 
 #define MPHDRLEN	6	/* multilink protocol header length */
 #define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
@@ -136,6 +139,9 @@ struct ppp {
 	unsigned pass_len, active_len;
 #endif /* CONFIG_PPP_FILTER */
 	struct net	*ppp_net;	/* the net we belong to */
+#ifdef CONFIG_PPP_BCP
+	struct net_device *bcp;		/* network device for bridging */
+#endif
 };
 
 /*
@@ -296,6 +302,10 @@ static inline int proto_to_npindex(int p
 		return NP_MPLS_UC;
 	case PPP_MPLS_MC:
 		return NP_MPLS_MC;
+	case PPP_BRIDGE:
+		return NP_BRIDGE;
+	case PPP_BPDU_IEEE:
+		return NP_BPDU_IEEE;
 	}
 	return -EINVAL;
 }
@@ -308,6 +318,8 @@ static const int npindex_to_proto[NUM_NP
 	PPP_AT,
 	PPP_MPLS_UC,
 	PPP_MPLS_MC,
+	PPP_BRIDGE,
+	PPP_BPDU_IEEE,
 };
 
 /* Translates an ethertype into an NP index */
@@ -341,6 +353,13 @@ static const int npindex_to_ethertype[NU
 	ETH_P_MPLS_MC,
 };
 
+/* IEEE 802.1D bridge PDU destination address */
+static const u8 ieee_8021d_dstaddr[ETH_ALEN] = { 1, 0x80, 0xC2, 0, 0, 0 };
+
+/* A few bytes that are present when and IEEE 802.1D bridge PDU is
+ * packed into an IEEE 802.3 frame. */
+static const u8 ieee_8021d_8023_hdr[] = { 0x42, 0x42, 0x03 };
+
 /*
  * Locking shorthand.
  */
@@ -732,7 +751,22 @@ static long ppp_ioctl(struct file *file,
 			if (copy_to_user(argp, &npi, sizeof(npi)))
 				break;
 		} else {
-			ppp->npmode[i] = npi.mode;
+#ifdef CONFIG_PPP_BCP
+			if (i == NP_BRIDGE) {
+				if (npi.mode == NPMODE_PASS) {
+					err = ppp_create_bcp(ppp);
+					if (err < 0)
+						break;
+					ppp->npmode[i] = npi.mode;
+				} else {
+					ppp->npmode[NP_BRIDGE] = npi.mode;
+					ppp->npmode[NP_BPDU_IEEE] = npi.mode;
+					ppp_shutdown_bcp(ppp);
+				}
+			} else
+#endif
+				ppp->npmode[i] = npi.mode;
+
 			/* we may be able to transmit more packets now (??) */
 			netif_wake_queue(ppp->dev);
 		}
@@ -935,14 +969,15 @@ out:
 /*
  * Network interface unit routines.
  */
+
+/* Called by PPP and BCP transmission routines. */
 static netdev_tx_t
-ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ppp_common_start_xmit(int npi, struct sk_buff *skb, struct net_device *dev)
 {
 	struct ppp *ppp = netdev_priv(dev);
-	int npi, proto;
+	int proto;
 	unsigned char *pp;
 
-	npi = ethertype_to_npindex(ntohs(skb->protocol));
 	if (npi < 0)
 		goto outf;
 
@@ -980,6 +1015,14 @@ ppp_start_xmit(struct sk_buff *skb, stru
 	return NETDEV_TX_OK;
 }
 
+static netdev_tx_t
+ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	int npi = ethertype_to_npindex(ntohs(skb->protocol));
+
+	return ppp_common_start_xmit(npi, skb, dev);
+}
+
 static int
 ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -1643,6 +1686,81 @@ ppp_receive_error(struct ppp *ppp)
 		slhc_toss(ppp->vj);
 }
 
+#ifdef CONFIG_PPP_BCP
+/* Decapsulate a packet from BCP. */
+static struct sk_buff *bcp_decap(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	const struct bcp_hdr *hdr;
+
+	/* Make sure that the data we examine are present. */
+	if (!pskb_may_pull(skb, BCP_802_3_HDRLEN))
+		goto drop;
+
+	/* Currently, only 802.3/Ethernet bridging is supported. */
+	hdr = (struct bcp_hdr *) skb->data;
+	if (hdr->mactype != BCP_MAC_802_3)
+		goto drop;
+
+	skb_pull(skb, BCP_802_3_HDRLEN);
+	skb->mac.raw = skb->data;
+
+	/* remove LAN FCS */
+	if (hdr->flags & BCP_LAN_FCS) {
+		if (skb->len < ETH_FCS_LEN)
+			goto drop;
+		skb_trim(skb, skb->len - ETH_FCS_LEN);
+	}
+
+	/* decompress "Tinygrams" */
+	if ((hdr->flags & BCP_ZERO_PAD) && skb_padto(skb, ETH_ZLEN))
+		return 0;
+
+	/* Parse the ethernet header.  Because of the increased
+	 * hard_header_len, eth_type_trans() skips too much, so push
+	 * some back afterward.
+	 */
+	skb->protocol = eth_type_trans(skb, dev);
+	skb_push(skb, dev->hard_header_len - ETH_HLEN);
+
+	return skb;
+
+ drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+/* Decapsulate an IEEE 802.1 (D or G) PDU. */
+static struct sk_buff *bpdu_ieee_decap(struct sk_buff *skb)
+{
+	struct net_device *const dev = skb->dev;
+	struct ethhdr *eth;
+
+	if (skb_cow_head(skb, ETH_HLEN + sizeof(ieee_8021d_8023_hdr))) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	/* Prepend the 802.3 SAP and control byte. */
+	memcpy(skb_push(skb, sizeof(ieee_8021d_8023_hdr)),
+	       ieee_8021d_8023_hdr, sizeof(ieee_8021d_8023_hdr));
+
+	/* Prepend an ethernet header. */
+	eth = skb_push(skb, ETH_HLEN);
+	memcpy(eth->h_dest, ieee_8021d_dstaddr, ETH_ALEN);
+	memset(eth->h_source, 0, ETH_ALEN);
+	eth->h_proto = htons(skb->len - ETH_HLEN);
+
+	/* Parse the ethernet header.  Because of the increased
+	 * hard_header_len, eth_type_trans() skips too much, so push
+	 * some back afterward. */
+	skb->protocol = eth_type_trans(skb, dev);
+	skb_push(skb, dev->hard_header_len - ETH_HLEN);
+
+	return skb;
+}
+#endif
+
 static void
 ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
 {
@@ -1734,6 +1852,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp,
 
 	} else {
 		/* network protocol frame - give it to the kernel */
+		struct net_device *rxdev;
 
 #ifdef CONFIG_PPP_FILTER
 		/* check if the packet passes the pass and active filters */
@@ -1763,13 +1882,44 @@ ppp_receive_nonmp_frame(struct ppp *ppp,
 #endif /* CONFIG_PPP_FILTER */
 			ppp->last_recv = jiffies;
 
-		if ((ppp->dev->flags & IFF_UP) == 0 ||
-		    ppp->npmode[npi] != NPMODE_PASS) {
-			kfree_skb(skb);
-		} else {
-			/* chop off protocol */
-			skb_pull_rcsum(skb, 2);
-			skb->dev = ppp->dev;
+#ifdef CONFIG_PPP_BCP
+		if (npi == NP_BRIDGE || npi == NP_BPDU_IEEE)
+			rxdev = ppp->bcp;
+		else
+#endif
+			rxdev = ppp->dev;
+
+		if (ppp->npmode[npi] != NPMODE_PASS ||
+		    !rxdev || !(rxdev->flags & IFF_UP)) {
+  			kfree_skb(skb);
+			return;
+		}
+
+		/* chop off protocol */
+		skb_pull_rcsum(skb, 2);
+		skb->dev = rxdev;
+
+		switch (npi) {
+#ifdef CONFIG_PPP_BCP
+		case NP_BRIDGE:
+			skb = bcp_decap(skb);
+			if (!skb) {
+				++ppp->bcp->stats.rx_dropped;
+				goto dropped;
+			}
+			++ppp->bcp->stats.rx_packets;
+			break;
+
+		case NP_BPDU_IEEE:
+			skb = bpdu_ieee_decap(skb);
+			if (!skb) {
+				++ppp->bcp->stats.rx_dropped;
+				goto dropped;
+			}
+			++ppp->bcp->stats.rx_packets;
+			break;
+#endif
+		default:
 			skb->protocol = htons(npindex_to_ethertype[npi]);
 			skb_reset_mac_header(skb);
 			netif_rx(skb);
@@ -2538,6 +2688,8 @@ ppp_create_interface(struct net *net, in
 	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
 	for (i = 0; i < NUM_NP; ++i)
 		ppp->npmode[i] = NPMODE_PASS;
+	ppp->npmode[NP_BRIDGE] = NPMODE_DROP;
+	ppp->npmode[NP_BPDU_IEEE] = NPMODE_DROP;
 	INIT_LIST_HEAD(&ppp->channels);
 	spin_lock_init(&ppp->rlock);
 	spin_lock_init(&ppp->wlock);
@@ -2880,6 +3032,189 @@ static void *unit_find(struct idr *p, in
 	return idr_find(p, n);
 }
 
+#ifdef CONFIG_PPP_BCP
+static const struct net_device_ops bcp_netdev_ops = {
+	.ndo_start_xmit = bcp_start_xmit,
+	.ndo_change_mtu = bcp_net_change_mtu,
+	.ndo_set_mac_addr = eth_mac_addr,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
+/*
+ * Create interface for bridging.
+ */
+static int ppp_create_bcp(struct ppp *ppp)
+{
+	struct net_device *dev;
+	int ret = -ENOMEM;
+
+	/* If it already exists, ignore the request. */
+	if (ppp->bcp)
+		return 0;
+
+	/* create a new BCP dev */
+	dev = alloc_etherdev(0);
+	if (!dev)
+		goto err;
+
+	dev->hard_header_len = ppp->dev->hard_header_len
+		+ BCP_802_3_HDRLEN + ETH_HLEN;
+
+	/* ETH_FCS_LEN is not subtracted from the PPP MTU here because
+	 * bcp_start_xmit() never adds the FCS. */
+	dev->mtu = ppp->dev->mtu - (BCP_802_3_HDRLEN + ETH_HLEN);
+
+	if (dev->mtu > ETH_DATA_LEN)
+		dev->mtu = ETH_DATA_LEN;
+
+	dev->netdev_ops = &bcp_netdev_ops;
+	dev->tx_queue_len = 0; /* let PPP device queue packets */
+
+	sprintf(dev->name, "bcp%d", ppp->file.index);
+
+	rtnl_lock();
+	ret = register_netdevice(dev);
+	if (ret == 0)
+		ppp->bcp = dev;
+	rtnl_unlock();
+
+	if (ret) {
+		pr_err("PPP: couldn't register device %s (%d)\n",
+		       dev->name, ret);
+		free_netdev(dev);
+	}
+ err:
+	return ret;
+}
+
+/*
+ * Take down a bcp interface.
+ */
+static void ppp_shutdown_bcp(struct ppp *ppp)
+{
+	struct net_device *bcp;
+
+	bcp = ppp->bcp;
+	if (bcp) {
+		unregister_netdev(bcp);
+		ppp->bcp = 0;
+		free_netdev(bcp);
+	}
+}
+
+static int
+bcp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+bcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* MTU is negotiated by the PPP daemon and should not be changed. */
+	return -EOPNOTSUPP;
+}
+
+/* input:  ethernet frame in non-shared skbuff
+ * output: bcp-encapsulated frame in non-shared and non-cloned skbuff
+ */
+static struct sk_buff *bcp_encap(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bcp_hdr *bhdr;
+	int pad_len;
+
+	/* @todo Calculate FCS?  NB: If you add this, be sure to
+	 * change the MTU calculation in ppp_create_bcp() to account
+	 * for it. */
+
+
+	/* Add a BCP header and pad to minimum frame size.
+	 *
+	 * Observations:
+	 *   - Headroom is usually adequate, because the kernel usually
+	 *     checks dev->hard_header_len; however, it is possible to
+	 *     be given a buffer that was originally allocated for another
+	 *     device.  (I have not seen it during testing.)
+	 *   - It is not possible for a buffer to be shared, because
+	 *     bcp_start_xmit() calls skb_share_check().
+	 *   - I do not know when a buffer might be cloned; perhaps it
+	 *     is possible in a bridging application where the same
+	 *     packet needs to be transmitted to multiple interfaces.
+	 */
+	if (skb_cow_head(skb, dev->hard_header_len)) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	bhdr = skb_push(skb, BCP_802_3_HDRLEN);
+	bhdr->flags = 0;		/* no LAN FCS, not a tinygram */
+	bhdr->mactype = BCP_MAC_802_3;	/* 802.3 / Ethernet */
+
+	/* There is currently no communication from pppd regarding the
+	 * peer's Tinygram-Compression option.  Therefore, we always
+	 * pad short frames to minimum Ethernet size in case the peer
+	 * does not support Tinygrams.
+	 */
+	if (skb_padto(skb, ETH_ZLEN))
+		return 0;
+
+	return skb;
+}
+
+/* input:  BPDU ethernet frame in non-shared skbuff
+ * output: naked BPDU in non-shared and non-cloned skbuff
+ */
+static struct sk_buff *bpdu_ieee_encap(struct sk_buff *skb)
+{
+	/* pull off the link header */
+	skb_pull(skb, ETH_HLEN + sizeof(ieee_8021d_8023_hdr));
+
+	return skb_unshare(skb, GFP_ATOMIC);
+}
+
+static int
+bcp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bcp_device *const bcp = dev_to_bcp(dev);
+	struct ppp *const ppp = bcp_to_ppp(bcp);
+	int npi;
+
+	/* make sure we can push/pull without side effects */
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		goto dropped;
+
+	/* When configured to encapsulate 802.1D bridge PDUs in the
+	 * obsolete manner of RFC 1638, do it.  Otherwise, send it
+	 * like any other packet.
+	 */
+	if ((ppp->npmode[NP_BPDU_IEEE] == NPMODE_PASS) &&
+	    pskb_may_pull(skb, ETH_HLEN + sizeof(ieee_8021d_8023_hdr)) &&
+	    compare_ether_addr(skb->data, ieee_8021d_dstaddr) == 0 &&
+	    memcmp(skb->data + ETH_HLEN, ieee_8021d_8023_hdr,
+		   sizeof(ieee_8021d_8023_hdr)) == 0) {
+		skb = bpdu_ieee_encap(skb, dev);
+		npi = NP_BPDU_IEEE;
+	} else {
+		skb = bcp_encap(skb, dev);
+		npi = NP_BRIDGE;
+	}
+
+	if (!skb)
+		goto dropped;
+
+	/* send packet through the PPP interface */
+	skb->dev = ppp->dev;
+	++bcp->stats.tx_packets;
+
+	return ppp_common_start_xmit(npi, skb, skb->dev);
+
+ dropped:
+	++bcp->stats.tx_dropped;
+	return 0;
+}
+#endif
+
 /* Module/initialization stuff */
 
 module_init(ppp_init);
--- a/drivers/net/Kconfig	2010-02-19 08:14:26.161558356 -0800
+++ b/drivers/net/Kconfig	2010-03-01 14:50:10.977353125 -0800
@@ -3166,6 +3166,13 @@ config PPPOL2TP
 	  and session setup). One such daemon is OpenL2TP
 	  (http://openl2tp.sourceforge.net/).
 
+config PPP_BCP
+        tristate "PPP over Bridge"
+	depends on EXPERIMENTAL && PPP && BRIDGE
+	help
+	  Support for PPP over Ethernet Bridge by using the
+	  Bridge Control Protocol (BCP) as defined in RFC 3185.
+
 config SLIP
 	tristate "SLIP (serial line) support"
 	---help---

^ permalink raw reply

* [PATCH 0/5] ARC vmac ethernet driver.
From: Andreas Fenkart @ 2010-03-01 23:18 UTC (permalink / raw)
  To: netdev; +Cc: amit.bhor, sameer.dhavale
In-Reply-To: <20100222.154010.149123575.davem@davemloft.net>

This is a resend of previous submission. It contains the following
changes:

* Removed arcvmac_fifo.h, moved content to arcvmac.h

* Replaced BUG_ON with WARN_ON

* Added missing Kconfig entry

^ permalink raw reply

* [PATCH 1/1] ARC vmac ethernet driver.
From: Andreas Fenkart @ 2010-03-01 23:18 UTC (permalink / raw)
  To: netdev; +Cc: amit.bhor, sameer.dhavale, Andreas Fenkart
In-Reply-To: <1267485483-15298-1-git-send-email-andreas.fenkart@streamunlimited.com>


Signed-off-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com>
---
 drivers/net/Kconfig   |    6 +
 drivers/net/Makefile  |    1 +
 drivers/net/arcvmac.c | 1439 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/arcvmac.h |  268 +++++++++
 4 files changed, 1714 insertions(+), 0 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index dd9a09c..7972d4d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -236,6 +236,12 @@ config AX88796_93CX6
 	help
 	  Select this if your platform comes with an external 93CX6 eeprom.
 
+config ARCVMAC
+	tristate "ARC VMAC ethernet support"
+	select MII
+	help
+	  MAC present on Zoran Quatro43XX
+
 config MACE
 	tristate "MACE (Power Mac ethernet) support"
 	depends on PPC_PMAC && PPC32
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2aff98c..0095022 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -134,6 +134,7 @@ obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
 obj-$(CONFIG_E2100) += e2100.o 8390.o
 obj-$(CONFIG_ES3210) += es3210.o 8390.o
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
+obj-$(CONFIG_ARCVMAC) += arcvmac.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_B44) += b44.o
diff --git a/drivers/net/arcvmac.c b/drivers/net/arcvmac.c
new file mode 100644
index 0000000..280d92b
--- /dev/null
+++ b/drivers/net/arcvmac.c
@@ -0,0 +1,1439 @@
+/*
+ * linux/arch/arc/drivers/arcvmac.c
+ *
+ * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port
+ * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port
+ * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI
+ * Copyright (C) 2009 Sagem Communications, Andreas Fenkart
+ * All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * external PHY support based on dnet.c
+ * ring management based on bcm63xx_enet.c
+ *
+ * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com
+ */
+
+#undef DEBUG
+
+#include <linux/clk.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "arcvmac.h"
+
+static char *mac_addr;
+module_param(mac_addr, charp, 0644);
+MODULE_PARM_DESC(mac_addr, "MAC address as colon separated hexadecimals");
+
+static void parse_mac_addr_param(struct net_device *dev,
+		char *module_param)
+{
+	struct sockaddr saddr;
+	unsigned char *hwaddr = saddr.sa_data;
+
+	sscanf(module_param, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+			&hwaddr[0],
+			&hwaddr[1],
+			&hwaddr[2],
+			&hwaddr[3],
+			&hwaddr[4],
+			&hwaddr[5]);
+
+	eth_mac_addr(dev, &saddr);
+}
+
+/* Register access macros */
+#define vmac_writel(port, value, reg)	\
+	writel((value), (port)->regs + reg##_OFFSET)
+#define vmac_readl(port, reg)	readl((port)->regs + reg##_OFFSET)
+
+static unsigned char *read_mac_reg(struct net_device *dev,
+		unsigned char hwaddr[ETH_ALEN])
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned mac_lo, mac_hi;
+
+	WARN_ON(!hwaddr);
+	mac_lo = vmac_readl(ap, ADDRL);
+	mac_hi = vmac_readl(ap, ADDRH);
+
+	hwaddr[0] = (mac_lo >> 0) & 0xff;
+	hwaddr[1] = (mac_lo >> 8) & 0xff;
+	hwaddr[2] = (mac_lo >> 16) & 0xff;
+	hwaddr[3] = (mac_lo >> 24) & 0xff;
+	hwaddr[4] = (mac_hi >> 0) & 0xff;
+	hwaddr[5] = (mac_hi >> 8) & 0xff;
+	return hwaddr;
+}
+
+static void write_mac_reg(struct net_device *dev, unsigned char* hwaddr)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned mac_lo, mac_hi;
+
+	mac_lo = hwaddr[3] << 24 | hwaddr[2] << 16 | hwaddr[1] << 8 | hwaddr[0];
+	mac_hi = hwaddr[5] << 8 | hwaddr[4];
+
+	vmac_writel(ap, mac_lo, ADDRL);
+	vmac_writel(ap, mac_hi, ADDRH);
+}
+
+static void vmac_mdio_xmit(struct vmac_priv *ap, unsigned val)
+{
+	init_completion(&ap->mdio_complete);
+	vmac_writel(ap, val, MDIO_DATA);
+	wait_for_completion(&ap->mdio_complete);
+}
+
+static int vmac_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+	struct vmac_priv *vmac = bus->priv;
+	unsigned int val;
+	/* only 5 bits allowed for phy-addr and reg_offset */
+	WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f);
+
+	val = MDIO_BASE | MDIO_OP_READ;
+	val |= phy_id << 23 | phy_reg << 18;
+	vmac_mdio_xmit(vmac, val);
+
+	val = vmac_readl(vmac, MDIO_DATA);
+	return val & MDIO_DATA_MASK;
+}
+
+static int vmac_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
+			 u16 value)
+{
+	struct vmac_priv *vmac = bus->priv;
+	unsigned int val;
+	/* only 5 bits allowed for phy-addr and reg_offset */
+	WARN_ON(phy_id & ~0x1f || phy_reg & ~0x1f);
+
+	val = MDIO_BASE | MDIO_OP_WRITE;
+	val |= phy_id << 23 | phy_reg << 18;
+	val |= (value & MDIO_DATA_MASK);
+	vmac_mdio_xmit(vmac, val);
+	return 0;
+}
+
+static void vmac_handle_link_change(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+	unsigned long flags;
+	int report_change = 0;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	if (phydev->duplex != ap->duplex) {
+		unsigned tmp;
+
+		tmp = vmac_readl(ap, ENABLE);
+
+		if (phydev->duplex)
+			tmp |= ENFL_MASK;
+		else
+			tmp &= ~ENFL_MASK;
+
+		vmac_writel(ap, tmp, ENABLE);
+
+		ap->duplex = phydev->duplex;
+		report_change = 1;
+	}
+
+	if (phydev->speed != ap->speed) {
+		ap->speed = phydev->speed;
+		report_change = 1;
+	}
+
+	if (phydev->link != ap->link) {
+		ap->link = phydev->link;
+		report_change = 1;
+	}
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	if (report_change)
+		phy_print_status(ap->phy_dev);
+}
+
+static int __devinit vmac_mii_probe(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+	struct clk *sys_clk;
+	unsigned long clock_rate;
+	int phy_addr, err;
+
+	/* find the first phy */
+	for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+		if (ap->mii_bus->phy_map[phy_addr]) {
+			phydev = ap->mii_bus->phy_map[phy_addr];
+			break;
+		}
+	}
+
+	if (!phydev) {
+		dev_err(&dev->dev, "no PHY found\n");
+		return -ENODEV;
+	}
+
+	/* FIXME: add pin_irq, if avail */
+
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
+			&vmac_handle_link_change, 0,
+			PHY_INTERFACE_MODE_MII);
+
+	if (IS_ERR(phydev)) {
+		err = PTR_ERR(phydev);
+		dev_err(&dev->dev, "could not attach to PHY %d\n", err);
+		goto err_out;
+	}
+
+	phydev->supported &= PHY_BASIC_FEATURES;
+	phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
+
+	sys_clk = clk_get(&ap->pdev->dev, "arcvmac");
+	if (IS_ERR(sys_clk)) {
+		err = PTR_ERR(sys_clk);
+		goto err_disconnect;
+	}
+
+	clock_rate = clk_get_rate(sys_clk);
+	clk_put(sys_clk);
+
+	dev_dbg(&ap->pdev->dev, "clk_get: dev_name : %s %lu\n",
+			dev_name(&ap->pdev->dev),
+			clock_rate);
+
+	if (clock_rate < 25000000)
+		phydev->supported &= ~(SUPPORTED_100baseT_Half |
+				SUPPORTED_100baseT_Full);
+
+	phydev->advertising = phydev->supported;
+
+	ap->link = 0;
+	ap->speed = 0;
+	ap->duplex = -1;
+	ap->phy_dev = phydev;
+
+	return 0;
+
+err_disconnect:
+	phy_disconnect(phydev);
+err_out:
+	return err;
+}
+
+static int __devinit vmac_mii_init(struct vmac_priv *ap)
+{
+	int err, i;
+
+	ap->mii_bus = mdiobus_alloc();
+	if (ap->mii_bus == NULL)
+		return -ENOMEM;
+
+	ap->mii_bus->name = "vmac_mii_bus";
+	ap->mii_bus->read = &vmac_mdio_read;
+	ap->mii_bus->write = &vmac_mdio_write;
+
+	snprintf(ap->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+
+	ap->mii_bus->priv = ap;
+
+	err = -ENOMEM;
+	ap->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!ap->mii_bus->irq)
+		goto err_out;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		ap->mii_bus->irq[i] = PHY_POLL;
+
+#if 0
+	/* FIXME: what is it used for? */
+	platform_set_drvdata(ap->dev, ap->mii_bus);
+#endif
+
+	err = mdiobus_register(ap->mii_bus);
+	if (err)
+		goto err_out_free_mdio_irq;
+
+	err = vmac_mii_probe(ap->dev);
+	if (err)
+		goto err_out_unregister_bus;
+
+	return 0;
+
+err_out_unregister_bus:
+	mdiobus_unregister(ap->mii_bus);
+err_out_free_mdio_irq:
+	kfree(ap->mii_bus->irq);
+err_out:
+	mdiobus_free(ap->mii_bus);
+	return err;
+}
+
+static void vmac_mii_exit(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	if (ap->phy_dev)
+		phy_disconnect(ap->phy_dev);
+
+	mdiobus_unregister(ap->mii_bus);
+	kfree(ap->mii_bus->irq);
+	mdiobus_free(ap->mii_bus);
+}
+
+static int vmacether_get_settings(struct net_device *dev,
+    struct ethtool_cmd *cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_gset(phydev, cmd);
+}
+
+static int vmacether_set_settings(struct net_device *dev,
+    struct ethtool_cmd *cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_sset(phydev, cmd);
+}
+
+static int vmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev = ap->phy_dev;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+}
+
+static void vmacether_get_drvinfo(struct net_device *dev,
+    struct ethtool_drvinfo *info)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	snprintf(info->bus_info, sizeof(info->bus_info),
+			"platform 0x%x", ap->mem_base);
+}
+
+static int update_error_counters(struct net_device *dev, int status)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	dev_dbg(&ap->pdev->dev, "rx error counter overrun. status = 0x%x\n",
+			status);
+
+	/* programming error */
+	WARN_ON(status & TXCH_MASK);
+	WARN_ON(!(status & (MSER_MASK | RXCR_MASK | RXFR_MASK | RXFL_MASK)));
+
+	if (status & MSER_MASK)
+		ap->stats.rx_over_errors += 256; /* ran out of BD */
+	if (status & RXCR_MASK)
+		ap->stats.rx_crc_errors += 256;
+	if (status & RXFR_MASK)
+		ap->stats.rx_frame_errors += 256;
+	if (status & RXFL_MASK)
+		ap->stats.rx_fifo_errors += 256;
+
+	return 0;
+}
+
+static void update_tx_errors(struct net_device *dev, int status)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	if (status & UFLO)
+		ap->stats.tx_fifo_errors++;
+
+	if (ap->duplex)
+		return;
+
+	/* half duplex flags */
+	if (status & LTCL)
+		ap->stats.tx_window_errors++;
+	if (status & RETRY_CT)
+		ap->stats.collisions += (status & RETRY_CT) >> 24;
+	if (status & DROP)  /* too many retries */
+		ap->stats.tx_aborted_errors++;
+	if (status & DEFER)
+		dev_vdbg(&ap->pdev->dev, "\"defer to traffic\"\n");
+	if (status & CARLOSS)
+		ap->stats.tx_carrier_errors++;
+}
+
+static int vmac_rx_reclaim_force(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int ct;
+
+	ct = 0;
+
+	dev_dbg(&ap->pdev->dev, "%s need to release %d rx sk_buff\n",
+	    __func__, fifo_used(&ap->rx_ring));
+
+	while (!fifo_empty(&ap->rx_ring) && ct++ < ap->rx_ring.size) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		int desc_idx;
+
+		desc_idx = ap->rx_ring.tail;
+		desc = &ap->rxbd[desc_idx];
+		fifo_inc_tail(&ap->rx_ring);
+
+		if (!ap->rx_skbuff[desc_idx]) {
+			dev_err(&ap->pdev->dev, "non-populated rx_skbuff found %d\n",
+					desc_idx);
+			continue;
+		}
+
+		skb = ap->rx_skbuff[desc_idx];
+		ap->rx_skbuff[desc_idx] = NULL;
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, skb->len,
+		    DMA_TO_DEVICE);
+
+		dev_kfree_skb(skb);
+	}
+
+	if (!fifo_empty(&ap->rx_ring)) {
+		dev_err(&ap->pdev->dev, "failed to reclaim %d rx sk_buff\n",
+				fifo_used(&ap->rx_ring));
+	}
+
+	return 0;
+}
+
+static int vmac_rx_refill(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	WARN_ON(fifo_full(&ap->rx_ring));
+
+	while (!fifo_full(&ap->rx_ring)) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		dma_addr_t p;
+		int desc_idx;
+
+		desc_idx = ap->rx_ring.head;
+		desc = &ap->rxbd[desc_idx];
+
+		/* make sure we read the actual descriptor status */
+		rmb();
+
+		if (ap->rx_skbuff[desc_idx]) {
+			/* dropped packet / buffer chaining */
+			fifo_inc_head(&ap->rx_ring);
+
+			/* return to DMA */
+			wmb();
+			desc->info = OWN_MASK | ap->rx_skb_size;
+			continue;
+		}
+
+		skb = netdev_alloc_skb(dev, ap->rx_skb_size + 2);
+		if (!skb) {
+			dev_info(&ap->pdev->dev, "failed to allocate rx_skb, skb's left %d\n",
+					fifo_used(&ap->rx_ring));
+			break;
+		}
+
+		/* IP header Alignment (14 byte Ethernet header) */
+		skb_reserve(skb, 2);
+		WARN_ON(skb->len != 0); /* nothing received yet */
+
+		ap->rx_skbuff[desc_idx] = skb;
+
+		/* TODO +2 okay with alignment? */
+		p = dma_map_single(&ap->pdev->dev, skb->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		desc->data = p;
+
+		wmb();
+		desc->info = OWN_MASK | ap->rx_skb_size;
+
+		fifo_inc_head(&ap->rx_ring);
+	}
+
+	/* If rx ring is still empty, set a timer to try allocating
+	 * again at a later time. */
+	if (fifo_empty(&ap->rx_ring) && netif_running(dev)) {
+		dev_warn(&ap->pdev->dev, "unable to refill rx ring\n");
+		ap->rx_timeout.expires = jiffies + HZ;
+		add_timer(&ap->rx_timeout);
+	}
+
+	return 0;
+}
+
+/*
+ * timer callback to defer refill rx queue in case we're OOM
+ */
+static void vmac_refill_rx_timer(unsigned long data)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+
+	dev = (struct net_device *)data;
+	ap = netdev_priv(dev);
+
+	spin_lock(&ap->rx_lock);
+	vmac_rx_refill(dev);
+	spin_unlock(&ap->rx_lock);
+}
+
+/* merge buffer chaining  */
+struct sk_buff *vmac_merge_rx_buffers(struct net_device *dev,
+		struct vmac_buffer_desc *after,
+		int pkt_len) /* data */
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct sk_buff *merge_skb, *cur_skb;
+	struct dma_fifo *rx_ring;
+	struct vmac_buffer_desc *desc;
+
+	rx_ring = &ap->rx_ring;
+	desc = &ap->rxbd[rx_ring->tail];
+
+	WARN_ON(desc == after);
+
+	/* strip FCS */
+	pkt_len -= 4;
+
+	/* IP header Alignment (14 byte Ethernet header) */
+	merge_skb = netdev_alloc_skb(dev, pkt_len + 2);
+	if (!merge_skb) {
+		dev_err(&ap->pdev->dev, "failed to allocate merged rx_skb, rx skb's left %d\n",
+				fifo_used(rx_ring));
+
+		return NULL;
+	}
+
+	skb_reserve(merge_skb, 2);
+
+	while (desc != after && pkt_len) {
+		struct vmac_buffer_desc *desc;
+		int buf_len, valid;
+
+		/* desc needs wrapping */
+		desc = &ap->rxbd[rx_ring->tail];
+		cur_skb = ap->rx_skbuff[rx_ring->tail];
+		WARN_ON(!cur_skb);
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, ap->rx_skb_size,
+				DMA_FROM_DEVICE);
+
+		/* do not copy FCS */
+		buf_len = desc->info & LEN_MASK;
+		valid = min(pkt_len, buf_len);
+		pkt_len -= valid;
+
+		memcpy(skb_put(merge_skb, valid), cur_skb->data, valid);
+
+		fifo_inc_tail(rx_ring);
+	}
+
+	/* merging_pressure++ */
+
+#ifdef DEBUG
+	if (pkt_len != 0)
+		dev_err(&ap->pdev->dev, "buffer chaining bytes missing %d\n", pkt_len);
+#endif
+
+	WARN_ON(desc != after);
+
+	return merge_skb;
+}
+
+int vmac_rx_receive(struct net_device *dev, int budget)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct vmac_buffer_desc *first;
+	int processed, pkt_len, pkt_err;
+	struct dma_fifo lookahead;
+
+	processed = 0;
+
+	first = NULL;
+	pkt_err = pkt_len = 0;
+
+	/* look ahead, till packet complete */
+	lookahead = ap->rx_ring;
+
+	do {
+		struct vmac_buffer_desc *desc; /* cur_ */
+		int desc_idx; /* cur_ */
+		struct sk_buff *skb; /* pkt_ */
+
+		desc_idx = lookahead.tail;
+		desc = &ap->rxbd[desc_idx];
+
+		/* make sure we read the actual descriptor status */
+		rmb();
+
+		/* break if dma ownership belongs to hw */
+		if (desc->info & OWN_MASK) {
+			ap->mac_rxring_head = vmac_readl(ap, MAC_RXRING_HEAD);
+			break;
+		}
+
+		if (desc->info & FRST_MASK) {
+			pkt_len = 0;
+			pkt_err = 0;
+
+			/* don't free current */
+			ap->rx_ring.tail = lookahead.tail;
+			first = desc;
+		}
+
+		fifo_inc_tail(&lookahead);
+
+		/* check bd */
+
+		pkt_len += desc->info & LEN_MASK;
+		pkt_err |= (desc->info & BUFF);
+
+		if (!(desc->info & LAST_MASK))
+			continue;
+
+		/* received complete packet */
+
+		if (unlikely(pkt_err || !first)) {
+			/* recycle buffers */
+			ap->rx_ring.tail = lookahead.tail;
+			continue;
+		}
+
+#ifdef DEBUG
+		WARN_ON(!(first->info & FRST_MASK) ||
+		    !(desc->info & LAST_MASK));
+		WARN_ON(pkt_err);
+#endif
+
+		/* -- valid packet -- */
+
+		if (first != desc) {
+			skb = vmac_merge_rx_buffers(dev, desc, pkt_len);
+
+			if (!skb) {
+				/* kill packet */
+				ap->rx_ring.tail = lookahead.tail;
+				ap->rx_merge_error++;
+				continue;
+			}
+		} else {
+			dma_unmap_single(&ap->pdev->dev, desc->data,
+					ap->rx_skb_size, DMA_FROM_DEVICE);
+
+			skb = ap->rx_skbuff[desc_idx];
+			ap->rx_skbuff[desc_idx] = NULL;
+			/* desc->data != skb->data => desc->data DMA mapped */
+
+			/* strip FCS */
+			skb_put(skb, pkt_len - 4);
+		}
+
+		/* free buffers */
+		ap->rx_ring.tail = lookahead.tail;
+
+#ifdef DEBUG
+		WARN_ON(skb->len != pkt_len - 4);
+#endif
+		processed++;
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		ap->stats.rx_packets++;
+		ap->stats.rx_bytes += skb->len;
+		dev->last_rx = jiffies;
+		netif_rx(skb);
+
+	} while (!fifo_empty(&lookahead) && (processed < budget));
+
+	dev_vdbg(&ap->pdev->dev, "processed pkt %d, remaining rx buff %d\n",
+			processed,
+			fifo_used(&ap->rx_ring));
+
+	if (processed || fifo_empty(&ap->rx_ring))
+		vmac_rx_refill(dev);
+
+	return processed;
+}
+
+static void vmac_toggle_irqmask(struct net_device *dev, int enable, int mask)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long tmp;
+
+	tmp = vmac_readl(ap, ENABLE);
+	if (enable)
+		tmp |= mask;
+	else
+		tmp &= ~mask;
+	vmac_writel(ap, tmp, ENABLE);
+}
+
+static void vmac_toggle_txint(struct net_device *dev, int enable)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+	vmac_toggle_irqmask(dev, enable, TXINT_MASK);
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static void vmac_toggle_rxint(struct net_device *dev, int enable)
+{
+	vmac_toggle_irqmask(dev, enable, RXINT_MASK);
+}
+
+static int vmac_poll(struct napi_struct *napi, int budget)
+{
+	struct vmac_priv *ap;
+	struct net_device *dev;
+	int rx_work_done;
+	unsigned long flags;
+
+	ap = container_of(napi, struct vmac_priv, napi);
+	dev = ap->dev;
+
+	/* ack interrupt */
+	vmac_writel(ap, RXINT_MASK, STAT);
+
+	spin_lock(&ap->rx_lock);
+	rx_work_done = vmac_rx_receive(dev, budget);
+	spin_unlock(&ap->rx_lock);
+
+	if (0 && printk_ratelimit()) {
+		dev_dbg(&ap->pdev->dev, "poll budget %d receive rx_work_done %d\n",
+				budget,
+				rx_work_done);
+	}
+
+	if (rx_work_done >= budget) {
+		/* rx queue is not yet empty/clean */
+		return rx_work_done;
+	}
+
+	/* no more packet in rx/tx queue, remove device from poll
+	 * queue */
+	spin_lock_irqsave(&ap->lock, flags);
+	napi_complete(napi);
+	vmac_toggle_rxint(dev, 1);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	return rx_work_done;
+}
+
+static int vmac_tx_reclaim(struct net_device *dev, int force);
+
+static irqreturn_t vmac_intr(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int status;
+
+	spin_lock(&ap->lock);
+
+	status = vmac_readl(ap, STAT);
+	vmac_writel(ap, status, STAT);
+
+#ifdef DEBUG
+	if (unlikely(ap->shutdown))
+		dev_err(&ap->pdev->dev, "ISR during close\n");
+
+	if (unlikely(!status & (RXINT_MASK|MDIO_MASK|ERR_MASK)))
+		dev_err(&ap->pdev->dev, "No source of IRQ found\n");
+#endif
+
+	if ((status & RXINT_MASK) &&
+			(ap->mac_rxring_head !=
+			 vmac_readl(ap, MAC_RXRING_HEAD))) {
+		vmac_toggle_rxint(dev, 0);
+		napi_schedule(&ap->napi);
+	}
+
+	if (unlikely(netif_queue_stopped(dev) && (status & TXINT_MASK)))
+		vmac_tx_reclaim(dev, 0);
+
+	if (status & MDIO_MASK)
+		complete(&ap->mdio_complete);
+
+	if (unlikely(status & ERR_MASK))
+		update_error_counters(dev, status);
+
+	spin_unlock(&ap->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int vmac_tx_reclaim(struct net_device *dev, int force)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int released = 0;
+
+	/* buffer chaining not used, see vmac_start_xmit */
+
+	while (!fifo_empty(&ap->tx_ring)) {
+		struct vmac_buffer_desc *desc;
+		struct sk_buff *skb;
+		int desc_idx;
+
+		desc_idx = ap->tx_ring.tail;
+		desc = &ap->txbd[desc_idx];
+
+		/* ensure other field of the descriptor were not read
+		 * before we checked ownership */
+		rmb();
+
+		if ((desc->info & OWN_MASK) && !force)
+			break;
+
+		if (desc->info & ERR_MSK_TX) {
+			update_tx_errors(dev, desc->info);
+			/* recycle packet, let upper level deal with it */
+		}
+
+		skb = ap->tx_skbuff[desc_idx];
+		ap->tx_skbuff[desc_idx] = NULL;
+		WARN_ON(!skb);
+
+		dma_unmap_single(&ap->pdev->dev, desc->data, skb->len,
+				DMA_TO_DEVICE);
+
+		dev_kfree_skb_any(skb);
+
+		released++;
+		fifo_inc_tail(&ap->tx_ring);
+	}
+
+	if (netif_queue_stopped(dev) && released) {
+		netif_wake_queue(dev);
+		vmac_toggle_txint(dev, 0);
+	}
+
+	if (unlikely(force && !fifo_empty(&ap->tx_ring))) {
+		dev_err(&ap->pdev->dev, "failed to reclaim %d tx sk_buff\n",
+				fifo_used(&ap->tx_ring));
+	}
+
+	return released;
+}
+
+int vmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct vmac_buffer_desc *desc;
+	unsigned int tmp;
+
+	/* running under xmit lock */
+
+	/* no scatter/gatter see features below */
+	WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+	WARN_ON(skb->len > MAX_TX_BUFFER_LEN);
+
+	if (unlikely(fifo_full(&ap->tx_ring))) {
+		netif_stop_queue(dev);
+		vmac_toggle_txint(dev, 1);
+		dev_err(&ap->pdev->dev, "xmit called with no tx desc available\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	if (unlikely(skb->len < ETH_ZLEN)) {
+		struct sk_buff *short_skb;
+		short_skb = netdev_alloc_skb(dev, ETH_ZLEN);
+		if (!short_skb)
+			return NETDEV_TX_LOCKED;
+
+		memset(short_skb->data, 0, ETH_ZLEN);
+		memcpy(skb_put(short_skb, ETH_ZLEN), skb->data, skb->len);
+		dev_kfree_skb(skb);
+		skb = short_skb;
+	}
+
+	/* fill descriptor */
+	ap->tx_skbuff[ap->tx_ring.head] = skb;
+
+	desc = &ap->txbd[ap->tx_ring.head];
+	desc->data = dma_map_single(&ap->pdev->dev, skb->data, skb->len,
+			DMA_TO_DEVICE);
+
+	/* dma might already be polling */
+	wmb();
+	desc->info = OWN_MASK | FRST_MASK | LAST_MASK | skb->len;
+	wmb();
+
+	/* kick tx dma */
+	tmp = vmac_readl(ap, STAT);
+	vmac_writel(ap, tmp | TXPL_MASK, STAT);
+
+	ap->stats.tx_packets++;
+	ap->stats.tx_bytes += skb->len;
+	dev->trans_start = jiffies;
+	fifo_inc_head(&ap->tx_ring);
+
+	/* vmac_tx_reclaim independent of vmac_tx_timeout */
+	if (fifo_used(&ap->tx_ring) > 8)
+		vmac_tx_reclaim(dev, 0);
+
+	/* stop queue if no more desc available */
+	if (fifo_full(&ap->tx_ring)) {
+		netif_stop_queue(dev);
+		vmac_toggle_txint(dev, 1);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+static int alloc_buffers(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	int err = -ENOMEM;
+	int size;
+
+	fifo_init(&ap->rx_ring, RX_BDT_LEN);
+	fifo_init(&ap->tx_ring, TX_BDT_LEN);
+
+	/* initialize skb list */
+	memset(ap->rx_skbuff, 0, sizeof(ap->rx_skbuff));
+	memset(ap->tx_skbuff, 0, sizeof(ap->tx_skbuff));
+
+	/* allocate DMA received descriptors */
+	size = sizeof(*ap->rxbd) * ap->rx_ring.size;
+	ap->rxbd = dma_alloc_coherent(&ap->pdev->dev, size,
+			&ap->rxbd_dma,
+			GFP_KERNEL);
+	if (ap->rxbd == NULL)
+		goto err_out;
+
+	/* allocate DMA transmit descriptors */
+	size = sizeof(*ap->txbd) * ap->tx_ring.size;
+	ap->txbd = dma_alloc_coherent(&ap->pdev->dev, size,
+			&ap->txbd_dma,
+			GFP_KERNEL);
+	if (ap->txbd == NULL)
+		goto err_free_rxbd;
+
+	/* ensure 8-byte aligned */
+	WARN_ON(((int)ap->txbd & 0x7) || ((int)ap->rxbd & 0x7));
+
+	memset(ap->txbd, 0, sizeof(*ap->txbd) * ap->tx_ring.size);
+	memset(ap->rxbd, 0, sizeof(*ap->rxbd) * ap->rx_ring.size);
+
+	/* allocate rx skb */
+	err = vmac_rx_refill(dev);
+	if (err)
+		goto err_free_txbd;
+
+	return 0;
+
+err_free_txbd:
+	dma_free_coherent(&ap->pdev->dev, sizeof(*ap->txbd) * ap->tx_ring.size,
+			ap->txbd, ap->txbd_dma);
+err_free_rxbd:
+	dma_free_coherent(&ap->pdev->dev, sizeof(*ap->rxbd) * ap->rx_ring.size,
+			ap->rxbd, ap->rxbd_dma);
+err_out:
+	return err;
+}
+
+static int free_buffers(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+
+	/* free skbuff */
+	vmac_tx_reclaim(dev, 1);
+	vmac_rx_reclaim_force(dev);
+
+	/* free DMA ring */
+	dma_free_coherent(&ap->pdev->dev, sizeof(ap->txbd) * ap->tx_ring.size,
+			ap->txbd, ap->txbd_dma);
+	dma_free_coherent(&ap->pdev->dev, sizeof(ap->rxbd) * ap->rx_ring.size,
+			ap->rxbd, ap->rxbd_dma);
+
+	return 0;
+}
+
+static int vmac_hw_init(struct net_device *dev)
+{
+	struct vmac_priv *priv = netdev_priv(dev);
+
+	/* clear IRQ mask */
+	vmac_writel(priv, 0, ENABLE);
+
+	/* clear pending IRQ */
+	vmac_writel(priv, 0xffffffff, STAT);
+
+	/* Initialize logical address filter */
+	vmac_writel(priv, 0x0, LAFL);
+	vmac_writel(priv, 0x0, LAFH);
+
+	return 0;
+}
+
+int vmac_open(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	struct phy_device *phydev;
+	unsigned int temp;
+	int err = 0;
+
+	if (ap == NULL)
+		return -ENODEV;
+
+	ap->shutdown = 0;
+
+	vmac_hw_init(dev);
+
+	/* mac address changed? */
+	write_mac_reg(dev, dev->dev_addr);
+
+	err = alloc_buffers(dev);
+	if (err)
+		goto err_out;
+
+	err = request_irq(dev->irq, &vmac_intr, 0, dev->name, dev);
+	if (err) {
+		dev_err(&ap->pdev->dev, "Unable to request IRQ %d (error %d)\n",
+				dev->irq, err);
+		goto err_free_buffers;
+	}
+
+	/* install DMA ring pointers */
+	vmac_writel(ap, ap->rxbd_dma, RXRINGPTR);
+	vmac_writel(ap, ap->txbd_dma, TXRINGPTR);
+
+	/* set poll rate to 1 ms */
+	vmac_writel(ap, POLLRATE_TIME, POLLRATE);
+
+	/* make sure we enable napi before rx interrupt  */
+	napi_enable(&ap->napi);
+
+	/* IRQ mask */
+	temp = RXINT_MASK | ERR_MASK | TXCH_MASK | MDIO_MASK;
+	vmac_writel(ap, temp, ENABLE);
+
+	/* Set control */
+	temp = (RX_BDT_LEN << 24) | (TX_BDT_LEN << 16) | TXRN_MASK | RXRN_MASK;
+	vmac_writel(ap, temp, CONTROL);
+
+	/* enable, after all other bits are set */
+	vmac_writel(ap, temp | EN_MASK, CONTROL);
+
+	netif_start_queue(dev);
+	netif_carrier_off(dev);
+
+	/* register the PHY board fixup, if needed */
+	err = vmac_mii_init(ap);
+	if (err)
+		goto err_free_irq;
+
+	/* schedule a link state check */
+	phy_start(ap->phy_dev);
+
+	phydev = ap->phy_dev;
+	dev_info(&ap->pdev->dev, "PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+	       phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_free_buffers:
+	free_buffers(dev);
+err_out:
+	return err;
+}
+
+int vmac_close(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int temp;
+
+	netif_stop_queue(dev);
+	napi_disable(&ap->napi);
+
+	/* stop running transfers */
+	temp = vmac_readl(ap, CONTROL);
+	temp &= ~(TXRN_MASK | RXRN_MASK);
+	vmac_writel(ap, temp, CONTROL);
+
+	del_timer_sync(&ap->rx_timeout);
+
+	/* disable phy */
+	phy_stop(ap->phy_dev);
+	vmac_mii_exit(dev);
+	netif_carrier_off(dev);
+
+	/* disable interrupts */
+	vmac_writel(ap, 0, ENABLE);
+	free_irq(dev->irq, dev);
+
+	/* turn off vmac */
+	vmac_writel(ap, 0, CONTROL);
+	/* vmac_reset_hw(vmac) */
+
+	ap->shutdown = 1;
+	wmb();
+
+	free_buffers(dev);
+	return 0;
+}
+
+void vmac_update_stats(struct vmac_priv *ap)
+{
+	struct net_device_stats *_stats = &ap->stats;
+	unsigned long miss, rxerr;
+	unsigned long rxfram, rxcrc, rxoflow;
+
+	/* compare with /proc/net/dev,
+	 * see net/core/dev.c:dev_seq_printf_stats */
+
+	/* rx stats */
+	rxerr = vmac_readl(ap, RXERR);
+	miss = vmac_readl(ap, MISS);
+
+	rxcrc = (rxerr & RXERR_CRC);
+	rxfram = (rxerr & RXERR_FRM) >> 8;
+	rxoflow = (rxerr & RXERR_OFLO) >> 16;
+
+	_stats->rx_length_errors = 0;
+	_stats->rx_over_errors += miss;
+	_stats->rx_crc_errors += rxcrc;
+	_stats->rx_frame_errors += rxfram;
+	_stats->rx_fifo_errors += rxoflow;
+	_stats->rx_missed_errors = 0;
+
+	/* TODO check rx_dropped/rx_errors/tx_dropped/tx_errors have not
+	 * been updated elsewhere */
+	_stats->rx_dropped = _stats->rx_over_errors +
+		_stats->rx_fifo_errors +
+		ap->rx_merge_error;
+
+	_stats->rx_errors = _stats->rx_length_errors + _stats->rx_crc_errors +
+		_stats->rx_frame_errors +
+		_stats->rx_missed_errors +
+		_stats->rx_dropped;
+
+	/* tx stats */
+	_stats->tx_dropped = 0; /* otherwise queue stopped */
+
+	_stats->tx_errors = _stats->tx_aborted_errors +
+		_stats->tx_carrier_errors +
+		_stats->tx_fifo_errors +
+		_stats->tx_heartbeat_errors +
+		_stats->tx_window_errors +
+		_stats->tx_dropped +
+		ap->tx_timeout_error;
+}
+
+struct net_device_stats *vmac_stats(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+	vmac_update_stats(ap);
+	spin_unlock_irqrestore(&ap->lock, flags);
+
+	return &ap->stats;
+}
+
+void vmac_tx_timeout(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned int status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	/* queue did not progress for timeo jiffies */
+	WARN_ON(!netif_queue_stopped(dev));
+	WARN_ON(!fifo_full(&ap->tx_ring));
+
+	/* TX IRQ lost? */
+	status = vmac_readl(ap, STAT);
+	if (status & TXINT_MASK) {
+		dev_err(&ap->pdev->dev, "lost tx interrupt, IRQ mask %x\n",
+				vmac_readl(ap, ENABLE));
+		vmac_writel(ap, TXINT_MASK, STAT);
+	}
+
+	/* TODO RX/MDIO/ERR as well? */
+
+	vmac_tx_reclaim(dev, 0);
+	if (fifo_full(&ap->tx_ring))
+		dev_err(&ap->pdev->dev, "DMA state machine not active\n");
+
+	/* We can accept TX packets again */
+	ap->tx_timeout_error++;
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static void create_multicast_filter(struct net_device *dev,
+	unsigned long *bitmask)
+{
+	struct dev_mc_list *mc_ptr;
+	unsigned long crc;
+	char *addrs;
+
+	WARN_ON(dev->mc_count == 0);
+	WARN_ON(dev->flags & IFF_ALLMULTI);
+
+	bitmask[0] = bitmask[1] = 0;
+	for (mc_ptr = dev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+		addrs = mc_ptr->dmi_addr;
+
+		/* skip non-multicast addresses */
+		if (!(*addrs & 1))
+			continue;
+
+		crc = ether_crc_le(ETH_ALEN, addrs);
+		set_bit(crc >> 26, bitmask);
+	}
+}
+
+static void vmac_set_multicast_list(struct net_device *dev)
+{
+	struct vmac_priv *ap = netdev_priv(dev);
+	unsigned long flags, bitmask[2];
+	int promisc, reg;
+
+	spin_lock_irqsave(&ap->lock, flags);
+
+	promisc = !!(dev->flags & IFF_PROMISC);
+	reg = vmac_readl(ap, ENABLE);
+	if (promisc != !!(reg & PROM_MASK)) {
+		reg ^= PROM_MASK;
+		vmac_writel(ap, reg, ENABLE);
+	}
+
+	if (dev->flags & IFF_ALLMULTI)
+		memset(bitmask, 1, sizeof(bitmask));
+	else if (dev->mc_count == 0)
+		memset(bitmask, 0, sizeof(bitmask));
+	else
+		create_multicast_filter(dev, bitmask);
+
+	vmac_writel(ap, bitmask[0], LAFL);
+	vmac_writel(ap, bitmask[1], LAFH);
+
+	spin_unlock_irqrestore(&ap->lock, flags);
+}
+
+static struct ethtool_ops vmac_ethtool_ops = {
+	.get_settings		= vmacether_get_settings,
+	.set_settings		= vmacether_set_settings,
+	.get_drvinfo		= vmacether_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
+
+static const struct net_device_ops vmac_netdev_ops = {
+	.ndo_open		= vmac_open,
+	.ndo_stop		= vmac_close,
+	.ndo_get_stats		= vmac_stats,
+	.ndo_start_xmit		= vmac_start_xmit,
+	.ndo_do_ioctl		= vmac_ioctl,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_tx_timeout		= vmac_tx_timeout,
+	.ndo_set_multicast_list = vmac_set_multicast_list,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+};
+
+static int __devinit vmac_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+	struct resource *res;
+	unsigned int mem_base, mem_size, irq;
+	int err;
+
+	dev = alloc_etherdev(sizeof(*ap));
+	if (!dev) {
+		dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
+		return -ENOMEM;
+	}
+
+	ap = netdev_priv(dev);
+
+	err = -ENODEV;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mmio resource defined\n");
+		goto err_out;
+	}
+	mem_base = res->start;
+	mem_size = resource_size(res);
+	irq = platform_get_irq(pdev, 0);
+
+	err = -EBUSY;
+	if (!request_mem_region(mem_base, mem_size, DRV_NAME)) {
+		dev_err(&pdev->dev, "no memory region available\n");
+		goto err_out;
+	}
+
+	err = -ENOMEM;
+	ap->regs = ioremap(mem_base, mem_size);
+	if (!ap->regs) {
+		dev_err(&pdev->dev, "failed to map registers, aborting.\n");
+		goto err_out_release_mem;
+	}
+
+	/* no checksum support, hence no scatter/gather */
+	dev->features |= NETIF_F_HIGHDMA;
+
+	spin_lock_init(&ap->lock);
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	ap->dev = dev;
+	ap->pdev = pdev;
+
+	/* init rx timeout (used for oom) */
+	init_timer(&ap->rx_timeout);
+	ap->rx_timeout.function = vmac_refill_rx_timer;
+	ap->rx_timeout.data = (unsigned long)dev;
+
+	netif_napi_add(dev, &ap->napi, vmac_poll, 2);
+	dev->netdev_ops = &vmac_netdev_ops;
+	dev->ethtool_ops = &vmac_ethtool_ops;
+	dev->irq = irq;
+
+	dev->flags |= IFF_MULTICAST;
+
+	dev->base_addr = (unsigned long)ap->regs;
+	ap->mem_base = mem_base;
+
+	/* prevent buffer chaining, favor speed over space */
+	ap->rx_skb_size = ETH_FRAME_LEN + VMAC_BUFFER_PAD;
+
+	/* private struct functional */
+
+	/* mac address intialize, set vmac_open  */
+	read_mac_reg(dev, dev->dev_addr);
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		random_ether_addr(dev->dev_addr);
+	if (mac_addr != NULL) {
+		/* overridde mac address by module parameter */
+		parse_mac_addr_param(dev, mac_addr);
+	}
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	dev_info(&pdev->dev, "ARC VMAC at 0x%08x irq %d %pM\n", mem_base,
+	    dev->irq, dev->dev_addr);
+	platform_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_out_iounmap:
+	iounmap(ap->regs);
+err_out_release_mem:
+	release_mem_region(mem_base, mem_size);
+err_out:
+	free_netdev(dev);
+	return err;
+}
+
+static int __devexit vmac_remove(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct vmac_priv *ap;
+	struct resource *res;
+
+	dev = platform_get_drvdata(pdev);
+	if (!dev) {
+		dev_err(&pdev->dev, "%s no valid dev found\n", __func__);
+		return 0;
+	}
+
+	ap = netdev_priv(dev);
+
+	/* MAC */
+	unregister_netdev(dev);
+	iounmap(ap->regs);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	platform_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+	return 0;
+}
+
+static struct platform_driver arcvmac_driver = {
+	.probe		= vmac_probe,
+	.remove		= __devexit_p(vmac_remove),
+	.driver		= {
+		.name		= "arcvmac",
+	},
+};
+
+static int __init vmac_init(void)
+{
+	return platform_driver_register(&arcvmac_driver);
+}
+
+static void __exit vmac_exit(void)
+{
+	platform_driver_unregister(&arcvmac_driver);
+}
+
+module_init(vmac_init);
+module_exit(vmac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ARC VMAC Ethernet driver");
+MODULE_AUTHOR("amit.bhor@celunite.com, sameer.dhavale@celunite.com");
diff --git a/drivers/net/arcvmac.h b/drivers/net/arcvmac.h
new file mode 100644
index 0000000..44c0587
--- /dev/null
+++ b/drivers/net/arcvmac.h
@@ -0,0 +1,268 @@
+/*
+ * linux/arch/arc/drivers/arcvmac.h
+ *
+ * Copyright (C) 2003-2006 Codito Technologies, for linux-2.4 port
+ * Copyright (C) 2006-2007 Celunite Inc, for linux-2.6 port
+ * Copyright (C) 2007-2008 Sagem Communications, Fehmi HAFSI
+ * Copyright (C) 2009 Sagem Communications, Andreas Fenkart
+ * All Rights Reserved.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: amit.bhor@celunite.com, sameer.dhavale@celunite.com
+ */
+
+#ifndef _ARCVMAC_H
+#define _ARCVMAC_H
+
+#define DRV_NAME		"arcvmac"
+#define DRV_VERSION		"1.0"
+
+/* Buffer descriptors */
+#define TX_BDT_LEN		16    /* Number of receive BD's */
+#define RX_BDT_LEN		256   /* Number of transmit BD's */
+
+/* BD poll rate, in 1024 cycles. @100Mhz: x * 1024 cy * 10ns = 1ms */
+#define POLLRATE_TIME		200
+
+/* next power of two, bigger than ETH_FRAME_LEN + VLAN  */
+#define MAX_RX_BUFFER_LEN	0x800	/* 2^11 = 2048 = 0x800 */
+#define MAX_TX_BUFFER_LEN	0x800	/* 2^11 = 2048 = 0x800 */
+
+/* 14 bytes of ethernet header, 4 bytes VLAN, FCS,
+ * plus extra pad to prevent buffer chaining of
+ * maximum sized ethernet packets (1514 bytes) */
+#define	VMAC_BUFFER_PAD		(ETH_HLEN + 4 + ETH_FCS_LEN + 4)
+
+/* VMAC register definitions, offsets in the ref manual are in bytes */
+#define ID_OFFSET		(0x00/0x4)
+#define STAT_OFFSET		(0x04/0x4)
+#define ENABLE_OFFSET		(0x08/0x4)
+#define CONTROL_OFFSET		(0x0c/0x4)
+#define POLLRATE_OFFSET		(0x10/0x4)
+#define RXERR_OFFSET		(0x14/0x4)
+#define MISS_OFFSET		(0x18/0x4)
+#define TXRINGPTR_OFFSET	(0x1c/0x4)
+#define RXRINGPTR_OFFSET	(0x20/0x4)
+#define ADDRL_OFFSET		(0x24/0x4)
+#define ADDRH_OFFSET		(0x28/0x4)
+#define LAFL_OFFSET		(0x2c/0x4)
+#define LAFH_OFFSET		(0x30/0x4)
+#define MDIO_DATA_OFFSET	(0x34/0x4)
+#define MAC_TXRING_HEAD_OFFSET	(0x38/0x4)
+#define MAC_RXRING_HEAD_OFFSET	(0x3C/0x4)
+
+/* STATUS and ENABLE register bit masks */
+#define TXINT_MASK		(1<<0)	/* Transmit interrupt */
+#define RXINT_MASK		(1<<1)	/* Receive interrupt */
+#define ERR_MASK		(1<<2)	/* Error interrupt */
+#define TXCH_MASK		(1<<3)	/* Transmit chaining error interrupt */
+#define MSER_MASK		(1<<4)	/* Missed packet counter error */
+#define RXCR_MASK		(1<<8)	/* RXCRCERR counter rolled over	 */
+#define RXFR_MASK		(1<<9)	/* RXFRAMEERR counter rolled over */
+#define RXFL_MASK		(1<<10)	/* RXOFLOWERR counter rolled over */
+#define MDIO_MASK		(1<<12)	/* MDIO complete */
+#define TXPL_MASK		(1<<31)	/* TXPOLL */
+
+/* CONTROL register bitmasks */
+#define EN_MASK			(1<<0)	/* VMAC enable */
+#define TXRN_MASK		(1<<3)	/* TX enable */
+#define RXRN_MASK		(1<<4)	/* RX enable */
+#define DSBC_MASK		(1<<8)	/* Disable receive broadcast */
+#define ENFL_MASK		(1<<10)	/* Enable Full Duplex */
+#define PROM_MASK		(1<<11)	/* Promiscuous mode */
+
+/* RXERR register bitmasks */
+#define RXERR_CRC		0x000000ff
+#define RXERR_FRM		0x0000ff00
+#define RXERR_OFLO		0x00ff0000 /* fifo overflow */
+
+/* MDIO data register bit masks */
+#define MDIO_SFD		0xC0000000
+#define MDIO_OP			0x30000000
+#define MDIO_ID_MASK		0x0F800000
+#define MDIO_REG_MASK		0x007C0000
+#define MDIO_TA			0x00030000
+#define MDIO_DATA_MASK		0x0000FFFF
+
+#define MDIO_BASE		0x40020000
+#define MDIO_OP_READ		0x20000000
+#define MDIO_OP_WRITE		0x10000000
+
+/* Buffer descriptor INFO bit masks */
+#define OWN_MASK		(1<<31)	/* ownership of buffer, 0 CPU, 1 DMA */
+#define BUFF			(1<<30) /* buffer invalid, rx */
+#define UFLO			(1<<29) /* underflow, tx */
+#define LTCL			(1<<28) /* late collision, tx  */
+#define RETRY_CT		(0xf<<24)  /* tx */
+#define DROP			(1<<23) /* drop, more than 16 retries, tx */
+#define DEFER			(1<<22) /* traffic on the wire, tx */
+#define CARLOSS			(1<<21) /* carrier loss while transmission, tx, rx? */
+/* 20:19 reserved */
+#define ADCR			(1<<18) /* add crc, ignored if not disaddcrc */
+#define LAST_MASK		(1<<17)	/* Last buffer in chain */
+#define FRST_MASK		(1<<16)	/* First buffer in chain */
+/* 15:11 reserved */
+#define LEN_MASK		0x000007FF
+
+#define ERR_MSK_TX		0x3fe00000 /* UFLO | LTCL | RTRY | DROP | DEFER | CRLS */
+
+
+/* arcvmac private data structures */
+struct vmac_buffer_desc {
+	unsigned int info;
+	dma_addr_t data;
+};
+
+struct dma_fifo {
+	int head; /* head */
+	int tail; /* tail */
+	int size;
+};
+
+struct	vmac_priv {
+	struct net_device *dev;
+	struct platform_device *pdev;
+	struct net_device_stats stats;
+
+	spinlock_t lock; /* TODO revisit */
+	struct completion mdio_complete;
+
+	/* base address of register set */
+	int *regs;
+	unsigned int mem_base;
+
+	/* DMA ring buffers */
+	struct vmac_buffer_desc *rxbd;
+	dma_addr_t rxbd_dma;
+
+	struct vmac_buffer_desc *txbd;
+	dma_addr_t txbd_dma;
+
+	/* socket buffers */
+	struct sk_buff *rx_skbuff[RX_BDT_LEN];
+	struct sk_buff *tx_skbuff[TX_BDT_LEN];
+	int rx_skb_size;
+
+	/* skb / dma desc managing */
+	struct dma_fifo rx_ring;
+	struct dma_fifo tx_ring;
+
+	/* descriptor last polled/processed by the VMAC */
+	unsigned long mac_rxring_head;
+	/* used when rx skb allocation failed, so we defer rx queue
+	 * refill */
+	struct timer_list rx_timeout;
+
+	/* lock rx_timeout against rx normal operation */
+	spinlock_t rx_lock;
+
+	struct napi_struct napi;
+
+	/* rx buffer chaining */
+	int rx_merge_error;
+	int tx_timeout_error;
+
+	/* PHY stuff */
+	struct mii_bus *mii_bus;
+	struct phy_device *phy_dev;
+
+	int link;
+	int speed;
+	int duplex;
+
+	/* debug */
+	int shutdown;
+};
+
+/* DMA ring management */
+
+/* for a fifo with size n,
+ * - [0..n] fill levels are n + 1 states
+ * - there are only n different deltas (head - tail) values
+ * => not all fill levels can be represented with head, tail
+ *    pointers only
+ * we give up the n fill level, aka fifo full */
+
+/* sacrifice one elt as a sentinel */
+static inline int fifo_used(struct dma_fifo *f);
+static inline int fifo_inc_ct(int ct, int size);
+static inline void fifo_dump(struct dma_fifo *fifo);
+
+static inline int fifo_empty(struct dma_fifo *f)
+{
+	return (f->head == f->tail);
+}
+
+static inline int fifo_free(struct dma_fifo *f)
+{
+	int free;
+
+	free = f->tail - f->head;
+	if (free <= 0)
+		free += f->size;
+
+	return free;
+}
+
+static inline int fifo_used(struct dma_fifo *f)
+{
+	int used;
+
+	used = f->head - f->tail;
+	if (used < 0)
+		used += f->size;
+
+	return used;
+}
+
+static inline int fifo_full(struct dma_fifo *f)
+{
+	return (fifo_used(f) + 1) == f->size;
+}
+
+/* manipulate */
+static inline void fifo_init(struct dma_fifo *fifo, int size)
+{
+	fifo->size = size;
+	fifo->head = fifo->tail = 0; /* empty */
+}
+
+static inline void fifo_inc_head(struct dma_fifo *fifo)
+{
+	BUG_ON(fifo_full(fifo));
+	fifo->head = fifo_inc_ct(fifo->head, fifo->size);
+}
+
+static inline void fifo_inc_tail(struct dma_fifo *fifo)
+{
+	BUG_ON(fifo_empty(fifo));
+	fifo->tail = fifo_inc_ct(fifo->tail, fifo->size);
+}
+
+/* internal funcs */
+static inline void fifo_dump(struct dma_fifo *fifo)
+{
+	printk(KERN_INFO "fifo: head %d, tail %d, size %d\n", fifo->head,
+			fifo->tail,
+			fifo->size);
+}
+
+static inline int fifo_inc_ct(int ct, int size)
+{
+	return (++ct == size) ? 0 : ct;
+}
+
+#endif	  /* _ARCVMAC_H */
-- 
1.6.6.1


^ permalink raw reply related

* [PATCH]  bridge: per-cpu packet statistics
From: Stephen Hemminger @ 2010-03-02  0:16 UTC (permalink / raw)
  To: David Miller, netdev, bridge

The shared packet statistics are a potential source of slow down
on bridged traffic. Convert to per-cpu array, but only keep those
statistics which change per-packet.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---

 net/bridge/br_device.c  |   43 ++++++++++++++++++++++++++++++++++++++-----
 net/bridge/br_if.c      |    6 ++++++
 net/bridge/br_input.c   |    5 +++--
 net/bridge/br_private.h |    8 ++++++++
 4 files changed, 55 insertions(+), 7 deletions(-)

--- a/net/bridge/br_device.c	2010-03-01 08:22:23.476657998 -0800
+++ b/net/bridge/br_device.c	2010-03-01 15:31:36.737227465 -0800
@@ -26,11 +26,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
 	const unsigned char *dest = skb->data;
 	struct net_bridge_fdb_entry *dst;
 	struct net_bridge_mdb_entry *mdst;
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	BR_INPUT_SKB_CB(skb)->brdev = dev;
+	brstats->tx_packets++;
+	brstats->tx_bytes += skb->len;
 
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += skb->len;
+	BR_INPUT_SKB_CB(skb)->brdev = dev;
 
 	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
@@ -81,6 +82,28 @@ static int br_dev_stop(struct net_device
 	return 0;
 }
 
+static struct net_device_stats *br_get_stats(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	unsigned int cpu;
+
+	stats->tx_bytes = stats->tx_packets = 0;
+	stats->rx_bytes = stats->rx_packets = 0;
+
+	for_each_online_cpu(cpu) {
+		const struct br_cpu_netstats *bstats
+			= per_cpu_ptr(br->stats, cpu);
+
+		stats->tx_bytes   += bstats->tx_bytes;
+		stats->tx_packets += bstats->tx_packets;
+		stats->rx_bytes   += bstats->rx_bytes;
+		stats->rx_packets += bstats->rx_packets;
+	}
+
+	return stats;
+}
+
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct net_bridge *br = netdev_priv(dev);
@@ -180,19 +203,27 @@ static const struct net_device_ops br_ne
 	.ndo_open		 = br_dev_open,
 	.ndo_stop		 = br_dev_stop,
 	.ndo_start_xmit		 = br_dev_xmit,
+	.ndo_get_stats		 = br_get_stats,
 	.ndo_set_mac_address	 = br_set_mac_address,
 	.ndo_set_multicast_list	 = br_dev_set_multicast_list,
 	.ndo_change_mtu		 = br_change_mtu,
 	.ndo_do_ioctl		 = br_dev_ioctl,
 };
 
+static void br_dev_free(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+
+	free_percpu(br->stats);
+}
+
 void br_dev_setup(struct net_device *dev)
 {
 	random_ether_addr(dev->dev_addr);
 	ether_setup(dev);
 
 	dev->netdev_ops = &br_netdev_ops;
-	dev->destructor = free_netdev;
+	dev->destructor = br_dev_free;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	dev->tx_queue_len = 0;
 	dev->priv_flags = IFF_EBRIDGE;
--- a/net/bridge/br_if.c	2010-03-01 08:22:23.476657998 -0800
+++ b/net/bridge/br_if.c	2010-03-01 15:30:47.733227819 -0800
@@ -185,6 +185,12 @@ static struct net_device *new_bridge_dev
 	br = netdev_priv(dev);
 	br->dev = dev;
 
+	br->stats = alloc_percpu(sizeof(struct br_cpu_netstats));
+	if (!br->stats) {
+		free_netdev(dev);
+		return NULL;
+	}
+
 	spin_lock_init(&br->lock);
 	INIT_LIST_HEAD(&br->port_list);
 	spin_lock_init(&br->hash_lock);
--- a/net/bridge/br_input.c	2010-03-01 08:22:23.476657998 -0800
+++ b/net/bridge/br_input.c	2010-03-01 15:32:45.882471626 -0800
@@ -23,9 +23,11 @@ const u8 br_group_address[ETH_ALEN] = { 
 static int br_pass_frame_up(struct sk_buff *skb)
 {
 	struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
+	struct net_bridge *br = netdev_priv(brdev);
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	brdev->stats.rx_packets++;
-	brdev->stats.rx_bytes += skb->len;
+	brstats->rx_packets++;
+	brstats->rx_bytes += skb->len;
 
 	indev = skb->dev;
 	skb->dev = brdev;
--- a/net/bridge/br_private.h	2010-03-01 08:22:23.476657998 -0800
+++ b/net/bridge/br_private.h	2010-03-01 15:31:03.437228864 -0800
@@ -135,6 +135,14 @@ struct net_bridge
 	spinlock_t			lock;
 	struct list_head		port_list;
 	struct net_device		*dev;
+
+	struct br_cpu_netstats __percpu {
+		unsigned long	rx_packets;
+		unsigned long	tx_packets;
+		unsigned long	rx_bytes;
+		unsigned long	tx_bytes;
+	} *stats;
+
 	spinlock_t			hash_lock;
 	struct hlist_head		hash[BR_HASH_SIZE];
 	unsigned long			feature_mask;

^ permalink raw reply

* Re: [net-next-2.6 PATCH 1/3] ixgbe: Fix DMA mapping/unmapping issues when HWRSC is enabled on IOMMU enabled kernels
From: Simon Horman @ 2010-03-02  0:29 UTC (permalink / raw)
  To: Jeff Kirsher; +Cc: davem, netdev, gospo, Mallikarjuna R Chilakala
In-Reply-To: <20100226091318.19796.70225.stgit@localhost.localdomain>

On Fri, Feb 26, 2010 at 01:14:37AM -0800, Jeff Kirsher wrote:
> From: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
> 
> Work around 82599 HW issue when HWRSC is enabled on IOMMU enabled
> kernels. 82599 HW is updating the header information after setting the
> descriptor to done, resulting DMA mapping/unmapping issues on IOMMU
> enabled systems. To work around the issue delay unmapping of first packet
> that carries the header information until end of packet is reached.
> 
> Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> ---
> 
>  drivers/net/ixgbe/ixgbe_main.c |   32 +++++++++++++++++++++++++++++---
>  1 files changed, 29 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
> index 3308790..4a01022 100644
> --- a/drivers/net/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ixgbe/ixgbe_main.c
> @@ -818,6 +818,12 @@ static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
>  	return skb;
>  }
>  
> +struct ixgbe_rsc_cb {
> +	dma_addr_t dma;
> +};
> +
> +#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
> +
>  static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>                                 struct ixgbe_ring *rx_ring,
>                                 int *work_done, int work_to_do)
> @@ -867,9 +873,21 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>  		rx_buffer_info->skb = NULL;
>  
>  		if (rx_buffer_info->dma) {
> -			pci_unmap_single(pdev, rx_buffer_info->dma,
> -			                 rx_ring->rx_buf_len,
> -			                 PCI_DMA_FROMDEVICE);
> +			if ((adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
> +			    (!(staterr & IXGBE_RXD_STAT_EOP)) &&
> +				 (!(skb->prev)))
> +				/*
> +				 * When HWRSC is enabled, delay unmapping
> +				 * of the first packet. It carries the
> +				 * header information, HW may still
> +				 * access the header after the writeback.
> +				 * Only unmap it when EOP is reached
> +				 */
> +				IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
> +			else
> +				pci_unmap_single(pdev, rx_buffer_info->dma,
> +				                 rx_ring->rx_buf_len,
> +				                 PCI_DMA_FROMDEVICE);
>  			rx_buffer_info->dma = 0;
>  			skb_put(skb, len);
>  		}
> @@ -917,6 +935,10 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>  			if (skb->prev)
>  				skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));
>  			if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
> +				if (IXGBE_RSC_CB(skb)->dma)
> +					pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma,
> +					                 rx_ring->rx_buf_len,
> +					                 PCI_DMA_FROMDEVICE);

Does IXGBE_RSC_CB(skb)->dma need to be set to NULL here
to avoid a double-free in ixgbe_clean_rx_ring() ?

>  				if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
>  					rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;
>  				else
> @@ -3104,6 +3126,10 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
>  			rx_buffer_info->skb = NULL;
>  			do {
>  				struct sk_buff *this = skb;
> +				if (IXGBE_RSC_CB(this)->dma)
> +					pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma,
> +					                 rx_ring->rx_buf_len,
> +					                 PCI_DMA_FROMDEVICE);
>  				skb = skb->prev;
>  				dev_kfree_skb(this);
>  			} while (skb);
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH net-next-2.6] bridge: Fix build error when IGMP_SNOOPING is not enabled
From: Herbert Xu @ 2010-03-02  0:46 UTC (permalink / raw)
  To: Sridhar Samudrala; +Cc: David Miller, netdev
In-Reply-To: <1267473184.31728.7.camel@w-sridhar.beaverton.ibm.com>

On Mon, Mar 01, 2010 at 11:53:04AM -0800, Sridhar Samudrala wrote:
> Fix the following build error when IGMP_SNOOPING is not enabled.
> In file included from net/bridge/br.c:24:
> net/bridge/br_private.h: In function 'br_multicast_is_router':
> net/bridge/br_private.h:361: error: 'struct net_bridge' has no member named 'multicast_router'
> net/bridge/br_private.h:362: error: 'struct net_bridge' has no member named 'multicast_router'
> net/bridge/br_private.h:363: error: 'struct net_bridge' has no member named 'multicast_router_timer'
> 
> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>

Thanks for the fix.

Acked-by: Herbert Xu <herbert@gondor.apana.org.au>

I'd originally left the struct data outside ifdefs and then added
the ifdefs without testing.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* RE: [net-next-2.6 PATCH 1/3] ixgbe: Fix DMA mapping/unmapping issues when HWRSC is enabled on IOMMU enabled kernels
From: Chilakala, Mallikarjuna @ 2010-03-02  1:09 UTC (permalink / raw)
  To: Simon Horman, Kirsher, Jeffrey T
  Cc: davem@davemloft.net, netdev@vger.kernel.org, gospo@redhat.com
In-Reply-To: <20100302002912.GB19929@verge.net.au>

>-----Original Message-----
>From: Simon Horman [mailto:horms@verge.net.au]
>Sent: Monday, March 01, 2010 4:29 PM
>To: Kirsher, Jeffrey T
>Cc: davem@davemloft.net; netdev@vger.kernel.org; gospo@redhat.com;
>Chilakala, Mallikarjuna
>Subject: Re: [net-next-2.6 PATCH 1/3] ixgbe: Fix DMA mapping/unmapping
>issues when HWRSC is enabled on IOMMU enabled kernels
>
>On Fri, Feb 26, 2010 at 01:14:37AM -0800, Jeff Kirsher wrote:
>> From: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
>>
>> Work around 82599 HW issue when HWRSC is enabled on IOMMU enabled
>> kernels. 82599 HW is updating the header information after setting the
>> descriptor to done, resulting DMA mapping/unmapping issues on IOMMU
>> enabled systems. To work around the issue delay unmapping of first packet
>> that carries the header information until end of packet is reached.
>>
>> Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
>> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
>> ---
>>
>>  drivers/net/ixgbe/ixgbe_main.c |   32 +++++++++++++++++++++++++++++---
>>  1 files changed, 29 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/ixgbe/ixgbe_main.c
>b/drivers/net/ixgbe/ixgbe_main.c
>> index 3308790..4a01022 100644
>> --- a/drivers/net/ixgbe/ixgbe_main.c
>> +++ b/drivers/net/ixgbe/ixgbe_main.c
>> @@ -818,6 +818,12 @@ static inline struct sk_buff
>*ixgbe_transform_rsc_queue(struct sk_buff *skb,
>>  	return skb;
>>  }
>>
>> +struct ixgbe_rsc_cb {
>> +	dma_addr_t dma;
>> +};
>> +
>> +#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
>> +
>>  static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
>>                                 struct ixgbe_ring *rx_ring,
>>                                 int *work_done, int work_to_do)
>> @@ -867,9 +873,21 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector
>*q_vector,
>>  		rx_buffer_info->skb = NULL;
>>
>>  		if (rx_buffer_info->dma) {
>> -			pci_unmap_single(pdev, rx_buffer_info->dma,
>> -			                 rx_ring->rx_buf_len,
>> -			                 PCI_DMA_FROMDEVICE);
>> +			if ((adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
>> +			    (!(staterr & IXGBE_RXD_STAT_EOP)) &&
>> +				 (!(skb->prev)))
>> +				/*
>> +				 * When HWRSC is enabled, delay unmapping
>> +				 * of the first packet. It carries the
>> +				 * header information, HW may still
>> +				 * access the header after the writeback.
>> +				 * Only unmap it when EOP is reached
>> +				 */
>> +				IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
>> +			else
>> +				pci_unmap_single(pdev, rx_buffer_info->dma,
>> +				                 rx_ring->rx_buf_len,
>> +				                 PCI_DMA_FROMDEVICE);
>>  			rx_buffer_info->dma = 0;
>>  			skb_put(skb, len);
>>  		}
>> @@ -917,6 +935,10 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector
>*q_vector,
>>  			if (skb->prev)
>>  				skb = ixgbe_transform_rsc_queue(skb, &(rx_ring-
>>rsc_count));
>>  			if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
>> +				if (IXGBE_RSC_CB(skb)->dma)
>> +					pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma,
>> +					                 rx_ring->rx_buf_len,
>> +					                 PCI_DMA_FROMDEVICE);
>

>Does IXGBE_RSC_CB(skb)->dma need to be set to NULL here
>to avoid a double-free in ixgbe_clean_rx_ring() ?

It shouldn't happen, but it is good to set it to NULL.
I'll send out a patch to fix this issue.
Thanks for your review Horman.

>
>>  				if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
>>  					rx_ring->rsc_count += skb_shinfo(skb)-
>>nr_frags;
>>  				else
>> @@ -3104,6 +3126,10 @@ static void ixgbe_clean_rx_ring(struct
>ixgbe_adapter *adapter,
>>  			rx_buffer_info->skb = NULL;
>>  			do {
>>  				struct sk_buff *this = skb;
>> +				if (IXGBE_RSC_CB(this)->dma)
>> +					pci_unmap_single(pdev, IXGBE_RSC_CB(this)-
>>dma,
>> +					                 rx_ring->rx_buf_len,
>> +					                 PCI_DMA_FROMDEVICE);
>>  				skb = skb->prev;
>>  				dev_kfree_skb(this);
>>  			} while (skb);
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe netdev" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: linux-next: Tree for March 1 (bluetooth/hci_sysfs)
From: Stephen Rothwell @ 2010-03-02  1:15 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: linux-next, LKML, Marcel Holtmann, linux-bluetooth, Netdev
In-Reply-To: <4B8C2CC5.8000603@oracle.com>

[-- Attachment #1: Type: text/plain, Size: 588 bytes --]

Hi Randy,

On Mon, 01 Mar 2010 13:08:21 -0800 Randy Dunlap <randy.dunlap@oracle.com> wrote:
>
> static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
> 						size_t count, loff_t *ppos)
> {
> 	struct hci_dev *hdev = file->private_data;
> 	struct inquiry_cache *cache = &hdev->inq_cache;
> 	struct inquiry_entry *e;
> 	char buf[4096]; // <<<<<<<<<<<<<<<<<<<<<<<<<<< huh? don't do that on stack.
> 	int n = 0;

Dave Miller is following up on that.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: BNX2: Kernel crashes with 2.6.31 and 2.6.31.9
From: Benjamin Li @ 2010-03-02  1:26 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: NetDEV, Michael Chan, Linux-Kernel
In-Reply-To: <20100223131508.4c6cb866@neptune.home>

Hi Bruno,

On Tue, 2010-02-23 at 04:15 -0800, Bruno Prémont wrote:
> Hi Benjamin,
> 
> On Fri, 19 February 2010 "Benjamin Li" <benli@broadcom.com> wrote:
> > >From your logs it looks like the device came up using MSI, but in the
> > MSI-X poll routine was being called:
> > 
> > [    9.836673] bnx2: eth0: using MSI
> > ...
> > 
> > [  134.643459]  [<ffffffffa004019e>] bnx2_poll_msix+0x3e/0xd0 [bnx2]
> > [  134.643465]  [<ffffffff8135bcd1>] netpoll_poll+0xe1/0x3c0
> > 
> > which is incorrect.  If we are in MSI mode, the bnx2_poll() routine
> > should be used.
> > 
> > I think what is going on here is that during the bnx2x driver
> > initialization the current bnx2 driver adds all possible NAPI
> > structures that map to all the hardware vectors (BNX2_MAX_MSIX_VEC=9)
> > to the NAPI list in the net_device structure regardless if they are
> > used or not (Seen in drivers/net/bnx2.c:bnx2_init_napi()).  This can
> > cause uninitialized NAPI structures to be placed on the napi_list.
> > Because this device is in MSI mode, only 1 vector is initialized.
> > Now, the problem is triggered when net/core/netpoll.c:poll_napi() is
> > called. This is because this routine will run through the entire
> > napi_list calling all the poll routines.  In your particular case, it
> > is calling the poll routine on an uninitialized vector causing the
> > kernel panic.
> > 
> > Please try the patch below to see if it solves your problem.  Note,
> > this only have been compile tested and tested against basic traffic
> > runs. Unfortunately, I could not reproduce the kernel panic with the
> > instructions below to verify the patch.
> > 
> > Thanks again for all your help in helping us track this down.
> 
> I applied the patch today and tried to reproduce with my showcases.
> 
> Seems that it's harder to trigger now but I still end up being able to
> crash the box. Don't know if it's the same cause or not (could also
> be the tcp-retransmit ghost)...
> 
> This time I had to run a few paralell scp's (8Mb/s each) to the box and 
> 'echo t > /proc/sysrq-trigger' multiple times via ssh session for it to
> happen. It didn't trigger with by netbomb though I will try some more
> and see)
> 
> I don't know if it's the same reason or not (hopefully something
> reached disk as serial console is dead and pings are not
> answered anymore.
> It's probably some printk/bug/warn that triggers in network stack and
> deadlocks with netconsole.

Thanks for trying the patch.  I still haven't been able to reproduce
what you are seeing here.  I am able to run scp and 'echo t
> /proc/sysrq-trigger' multiple times.  I was wondering if you had any
success reproducing the problem with a stack trace?

Thanks again.

-Ben

> 
> Regards,
> Bruno
> 

^ permalink raw reply

* Re: NETIF_F_FRAGLIST and NETIF_F_SG difference
From: David Miller @ 2010-03-02  1:40 UTC (permalink / raw)
  To: bhutchings; +Cc: mekaviraj, netdev
In-Reply-To: <1267448321.2819.15.camel@localhost>

From: Ben Hutchings <bhutchings@solarflare.com>
Date: Mon, 01 Mar 2010 12:58:41 +0000

> (I don't know why there are two ways of adding extra data.  The latter
> does not seem to be used often.)

It's the most efficient way to handle IPv4/IPv6 fragmentation and
reassembly.

^ permalink raw reply

* Re: [PATCH net-next-2.6] bridge: Fix build error when IGMP_SNOOPING is not enabled
From: David Miller @ 2010-03-02  2:14 UTC (permalink / raw)
  To: herbert; +Cc: sri, netdev
In-Reply-To: <20100302004626.GA28274@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 2 Mar 2010 08:46:26 +0800

> On Mon, Mar 01, 2010 at 11:53:04AM -0800, Sridhar Samudrala wrote:
>> Fix the following build error when IGMP_SNOOPING is not enabled.
>> In file included from net/bridge/br.c:24:
>> net/bridge/br_private.h: In function 'br_multicast_is_router':
>> net/bridge/br_private.h:361: error: 'struct net_bridge' has no member named 'multicast_router'
>> net/bridge/br_private.h:362: error: 'struct net_bridge' has no member named 'multicast_router'
>> net/bridge/br_private.h:363: error: 'struct net_bridge' has no member named 'multicast_router_timer'
>> 
>> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
> 
> Thanks for the fix.
> 
> Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
> 
> I'd originally left the struct data outside ifdefs and then added
> the ifdefs without testing.

Thanks everyone, I'll apply this.

^ permalink raw reply

* Re: linux-next: Tree for March 1 (bluetooth/hci_sysfs)
From: David Miller @ 2010-03-02  2:14 UTC (permalink / raw)
  To: sfr-3FnU+UHB4dNDw9hX6IcOSA
  Cc: randy.dunlap-QHcLZuEGTsvQT0dZR+AlfA,
	linux-next-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	marcel-kz+m5ild9QBg9hUCZPvPmw,
	linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20100302121526.36a1ea88.sfr-3FnU+UHB4dNDw9hX6IcOSA@public.gmane.org>

From: Stephen Rothwell <sfr-3FnU+UHB4dNDw9hX6IcOSA@public.gmane.org>
Date: Tue, 2 Mar 2010 12:15:26 +1100

> Hi Randy,
> 
> On Mon, 01 Mar 2010 13:08:21 -0800 Randy Dunlap <randy.dunlap-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org> wrote:
>>
>> static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
>> 						size_t count, loff_t *ppos)
>> {
>> 	struct hci_dev *hdev = file->private_data;
>> 	struct inquiry_cache *cache = &hdev->inq_cache;
>> 	struct inquiry_entry *e;
>> 	char buf[4096]; // <<<<<<<<<<<<<<<<<<<<<<<<<<< huh? don't do that on stack.
>> 	int n = 0;
> 
> Dave Miller is following up on that.

This looks like a job for.... SEQ FILE! :-)

I'm testing the following fix.

diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 1a79a6c..f02c2ff 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -3,6 +3,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -405,44 +406,85 @@ static struct device_type bt_host = {
 	.release = bt_host_release,
 };
 
-static int inquiry_cache_open(struct inode *inode, struct file *file)
+static int inquiry_cache_show(struct seq_file *m, void *v)
 {
-	file->private_data = inode->i_private;
+	struct inquiry_entry *e = v;
+	struct inquiry_data *data;
+	bdaddr_t bdaddr;
+
+	data = &e->data;
+	baswap(&bdaddr, &data->bdaddr);
+
+	seq_printf(m, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+		   batostr(&bdaddr),
+		   data->pscan_rep_mode, data->pscan_period_mode,
+		   data->pscan_mode, data->dev_class[2],
+		   data->dev_class[1], data->dev_class[0],
+		   __le16_to_cpu(data->clock_offset),
+		   data->rssi, data->ssp_mode, e->timestamp);
+
 	return 0;
 }
 
-static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
-						size_t count, loff_t *ppos)
+static void *inquiry_cache_get_idx(struct hci_dev *hdev, loff_t pos)
 {
-	struct hci_dev *hdev = file->private_data;
 	struct inquiry_cache *cache = &hdev->inq_cache;
-	struct inquiry_entry *e;
-	char buf[4096];
-	int n = 0;
+	struct inquiry_entry *e = cache->list;
+
+	while (e && pos) {
+		e = e->next;
+		pos--;
+	}
+	return e;
+}
+
+static void *inquiry_cache_start(struct seq_file *m, loff_t *pos)
+{
+	struct hci_dev *hdev = m->private;
 
 	hci_dev_lock_bh(hdev);
 
-	for (e = cache->list; e; e = e->next) {
-		struct inquiry_data *data = &e->data;
-		bdaddr_t bdaddr;
-		baswap(&bdaddr, &data->bdaddr);
-		n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
-				batostr(&bdaddr),
-				data->pscan_rep_mode, data->pscan_period_mode,
-				data->pscan_mode, data->dev_class[2],
-				data->dev_class[1], data->dev_class[0],
-				__le16_to_cpu(data->clock_offset),
-				data->rssi, data->ssp_mode, e->timestamp);
-	}
+	return inquiry_cache_get_idx(hdev, *pos);
+}
+
+static void *inquiry_cache_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct inquiry_entry *e = v;
+
+	++*pos;
+	return e->next;
+}
+
+static void inquiry_cache_stop(struct seq_file *m, void *v)
+{
+	struct hci_dev *hdev = m->private;
 
 	hci_dev_unlock_bh(hdev);
+}
 
-	return simple_read_from_buffer(userbuf, count, ppos, buf, n);
+static const struct seq_operations inquiry_cache_ops = {
+	.start	= inquiry_cache_start,
+	.next	= inquiry_cache_next,
+	.stop	= inquiry_cache_stop,
+	.show	= inquiry_cache_show,
+};
+
+static int inquiry_cache_open(struct inode *inode, struct file *file)
+{
+	int rc = seq_open(file, &inquiry_cache_ops);
+
+	if (rc >= 0) {
+		struct seq_file *m = file->private_data;
+		m->private = inode->i_private;
+	}
+	return rc;
 }
 
 static const struct file_operations inquiry_cache_fops = {
-	.open = inquiry_cache_open,
-	.read = inquiry_cache_read,
+	.open		= inquiry_cache_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 int hci_register_sysfs(struct hci_dev *hdev)

^ permalink raw reply related

* Re: [PATCH V2] net: add accounting for socket backlog
From: Zhu Yi @ 2010-03-02  2:34 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev@vger.kernel.org, David Miller
In-Reply-To: <1267443828.3039.7.camel@edumazet-laptop>

On Mon, 2010-03-01 at 19:43 +0800, Eric Dumazet wrote:
> Thinking again about this, doing this zero initialization at the very
> end of __release_sock() solves the problem of potential infinite loop
> in
> __release_sock(). Since producer will hit the backlog limit.
> 
> Thanks
> 
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 305cba4..544cf4a 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1542,6 +1542,11 @@ static void __release_sock(struct sock *sk)
>  
>                 bh_lock_sock(sk);
>         } while ((skb = sk->sk_backlog.head) != NULL);
> +       /*
> +        * Doing this zeroing at the end of this function guarantee we
> can not
> +        * loop forever while a wild producer attempts to flood us
> +        */
> +       sk->sk_backlog.len = 0;
>  } 

Very good point. I'll add your sob in my next patch.

Thanks,
-yi


^ permalink raw reply

* Re: sparse checking prevented by "net: fix kmemcheck annotations"
From: David Miller @ 2010-03-02  2:39 UTC (permalink / raw)
  To: stefanr; +Cc: eric.dumazet, linux-kernel, netdev
In-Reply-To: <4B8BE8BE.9070505@s5r6.in-berlin.de>

From: Stefan Richter <stefanr@s5r6.in-berlin.de>
Date: Mon, 01 Mar 2010 17:18:06 +0100

> Eric Dumazet wrote:
>> [PATCH] net: fix protocol sk_buff field
>> 
>> Commit e992cd9b72a18 (kmemcheck: make bitfield annotations truly no-ops
>> when disabled) allows us to revert a workaround we did in the past to
>> not add holes in sk_buff structure.
>> 
>> This patch partially reverts commit 14d18a81b5171
>> (net: fix kmemcheck annotations) so that sparse doesnt complain:
>> 
>> include/linux/skbuff.h:357:41: error: invalid bitfield specifier for
>> type restricted __be16.
> 
> Great, very appreciated.

Applied, thanks everyone.

^ permalink raw reply

* Re: NETIF_F_FRAGLIST and NETIF_F_SG difference
From: Ben Hutchings @ 2010-03-02  2:51 UTC (permalink / raw)
  To: David Miller; +Cc: mekaviraj, netdev
In-Reply-To: <20100301.174024.214216263.davem@davemloft.net>

On Mon, 2010-03-01 at 17:40 -0800, David Miller wrote:
> From: Ben Hutchings <bhutchings@solarflare.com>
> Date: Mon, 01 Mar 2010 12:58:41 +0000
> 
> > (I don't know why there are two ways of adding extra data.  The latter
> > does not seem to be used often.)
> 
> It's the most efficient way to handle IPv4/IPv6 fragmentation and
> reassembly.

But fragmentation results in a series of packets to be transmitted
separately (not gathered) and reassembly is only done at endpoints.  So
when would we see a fragment list on the transmit path?

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: NETIF_F_FRAGLIST and NETIF_F_SG difference
From: David Miller @ 2010-03-02  3:01 UTC (permalink / raw)
  To: bhutchings; +Cc: mekaviraj, netdev
In-Reply-To: <1267498318.2819.21.camel@localhost>

From: Ben Hutchings <bhutchings@solarflare.com>
Date: Tue, 02 Mar 2010 02:51:58 +0000

> On Mon, 2010-03-01 at 17:40 -0800, David Miller wrote:
>> From: Ben Hutchings <bhutchings@solarflare.com>
>> Date: Mon, 01 Mar 2010 12:58:41 +0000
>> 
>> > (I don't know why there are two ways of adding extra data.  The latter
>> > does not seem to be used often.)
>> 
>> It's the most efficient way to handle IPv4/IPv6 fragmentation and
>> reassembly.
> 
> But fragmentation results in a series of packets to be transmitted
> separately (not gathered) and reassembly is only done at endpoints.  So
> when would we see a fragment list on the transmit path?

If the device indicates it can take the set of fragments as a bundle,
with only one IP header at the front, instead of individual fully
header'd IP frames.

This was the original intention of what this net device feature flag
was to be used for.

The device does all of the IP header creation for the individual
frames, bumping the fragment ID and flags, etc.  Just like it does
for TSO.

Some broadcom chips can do this, if I recall correctly.

But that never materialized.  Instead it now simply means that
the frag list based linkage is supported, and the packet is an
entire fully formed frame.

GSO/GRO makes use of the current interpretation so that the it's
bundles can be passed around efficiently from RX to TX.  Mostly the
feature bit is set by layered and virtualization devices.

^ permalink raw reply

* Re: [RFC] ppp: Bridge Control Protocol
From: Paul Mackerras @ 2010-03-02  3:39 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: David, "Miller <davem", linux-ppp, bridge, netdev,
	dane
In-Reply-To: <20100301145915.2ecaac89@nehalam>

On Mon, Mar 01, 2010 at 02:59:15PM -0800, Stephen Hemminger wrote:

> This is a port of an old patch to provide BCP support.
> BCP allows bridging PPP tunnels, it useful to do bridging between
> virtualized environments. Original patch was done by
> Dan Eble but was for 2.4.21.
> 
> Note: still needs testing. Does anyone have hardware to make
> sure this interoperates with other implementations?

Is there a corresponding pppd patch to handle the control protocol?

Paul.

^ permalink raw reply

* Re: [PATCH] net: TCP_MSS_DEFAULT, TCP_MSS_DESIRED
From: Simon Horman @ 2010-03-02  4:16 UTC (permalink / raw)
  To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AF9C436.8060403@gmail.com>

On Tue, Nov 10, 2009 at 02:51:18PM -0500, William Allen Simpson wrote:
> Define two symbols needed in both kernel and user space.
> 
> Remove old (somewhat incorrect) kernel variant that wasn't used in
> most cases.  Default should apply to both RMSS and SMSS (RFC2581).

The name was somewhat incorrect in the sense that it was named
differently in the RFCs?

> Replace numeric constants with defined symbols.

That bit sounds very reasonable.

> Stand-alone patch, originally developed for TCPCT.
> 
> Signed-off-by: William.Allen.Simpson@gmail.com
> Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
>   include/linux/tcp.h      |    6 ++++++
>   include/net/tcp.h        |    3 ---
>   net/ipv4/tcp_input.c     |    4 ++--
>   net/ipv4/tcp_ipv4.c      |    6 +++---
>   net/ipv4/tcp_minisocks.c |    2 +-
>   net/ipv6/tcp_ipv6.c      |    2 +-
>   6 files changed, 13 insertions(+), 10 deletions(-)

> diff --git a/include/linux/tcp.h b/include/linux/tcp.h
> index eeecb85..32d7d77 100644
> --- a/include/linux/tcp.h
> +++ b/include/linux/tcp.h
> @@ -81,6 +81,12 @@ enum {
>  	TCP_DATA_OFFSET = __cpu_to_be32(0xF0000000)
>  }; 
>  
> +/*
> + * TCP general constants
> + */
> +#define TCP_MSS_DEFAULT		 536U	/* IPv4 (RFC1122, RFC2581) */
> +#define TCP_MSS_DESIRED		1220U	/* IPv6 (tunneled), EDNS0 (RFC3226) */

Are you planing to use TCP_MSS_DESIRED anywhere?

> +
>  /* TCP socket options */
>  #define TCP_NODELAY		1	/* Turn off Nagle's algorithm. */
>  #define TCP_MAXSEG		2	/* Limit MSS */
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 25bf3ba..a413e9f 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -62,9 +62,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
>  /* Minimal accepted MSS. It is (60+60+8) - (20+20). */
>  #define TCP_MIN_MSS		88U
>  
> -/* Minimal RCV_MSS. */
> -#define TCP_MIN_RCVMSS		536U
> -
>  /* The least MTU to use for probing */
>  #define TCP_BASE_MSS		512
>  
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index be0c5bf..cc306ac 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -140,7 +140,7 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
>  		 * "len" is invariant segment length, including TCP header.
>  		 */
>  		len += skb->data - skb_transport_header(skb);
> -		if (len >= TCP_MIN_RCVMSS + sizeof(struct tcphdr) ||
> +		if (len >= TCP_MSS_DEFAULT + sizeof(struct tcphdr) ||
>  		    /* If PSH is not set, packet should be
>  		     * full sized, provided peer TCP is not badly broken.
>  		     * This observation (if it is correct 8)) allows
> @@ -411,7 +411,7 @@ void tcp_initialize_rcv_mss(struct sock *sk)
>  	unsigned int hint = min_t(unsigned int, tp->advmss, tp->mss_cache);
>  
>  	hint = min(hint, tp->rcv_wnd / 2);
> -	hint = min(hint, TCP_MIN_RCVMSS);
> +	hint = min(hint, TCP_MSS_DEFAULT);
>  	hint = max(hint, TCP_MIN_MSS);
>  
>  	inet_csk(sk)->icsk_ack.rcv_mss = hint;
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index f83ac91..0718fde 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -217,7 +217,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
>  	if (inet->opt)
>  		inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
>  
> -	tp->rx_opt.mss_clamp = 536;
> +	tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;
>  
>  	/* Socket identity is still unknown (sport may be zero).
>  	 * However we set state to SYN-SENT and not releasing socket
> @@ -1270,7 +1270,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
>  		goto drop_and_free;
>  
>  	tcp_clear_options(&tmp_opt);
> -	tmp_opt.mss_clamp = 536;
> +	tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
>  	tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss;
>  
>  	tcp_parse_options(skb, &tmp_opt, 0, dst);
> @@ -1818,7 +1818,7 @@ static int tcp_v4_init_sock(struct sock *sk)
>  	 */
>  	tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
>  	tp->snd_cwnd_clamp = ~0;
> -	tp->mss_cache = 536;
> +	tp->mss_cache = TCP_MSS_DEFAULT;
>  
>  	tp->reordering = sysctl_tcp_reordering;
>  	icsk->icsk_ca_ops = &tcp_init_congestion_ops;
> diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
> index fb68bab..7a42990 100644
> --- a/net/ipv4/tcp_minisocks.c
> +++ b/net/ipv4/tcp_minisocks.c
> @@ -476,7 +476,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
>  		if (newtp->af_specific->md5_lookup(sk, newsk))
>  			newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED;
>  #endif
> -		if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len)
> +		if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)
>  			newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
>  		newtp->rx_opt.mss_clamp = req->mss;
>  		TCP_ECN_openreq_child(newtp, req);
> diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
> index 6951827..b528f75 100644
> --- a/net/ipv6/tcp_ipv6.c
> +++ b/net/ipv6/tcp_ipv6.c
> @@ -1849,7 +1849,7 @@ static int tcp_v6_init_sock(struct sock *sk)
>  	 */
>  	tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
>  	tp->snd_cwnd_clamp = ~0;
> -	tp->mss_cache = 536;
> +	tp->mss_cache = TCP_MSS_DEFAULT;
>  
>  	tp->reordering = sysctl_tcp_reordering;
>  
> -- 
> 1.6.3.3
> 


^ permalink raw reply

* Re: Was:  Re: [RFC PATCH] fix problems with NETIF_F_HIGHDMA in networking, Now: SWIOTLB dynamic allocation
From: FUJITA Tomonori @ 2010-03-02  4:40 UTC (permalink / raw)
  To: konrad.wilk
  Cc: davem, fujita.tomonori, hancockrwd, bzolnier, linux-kernel,
	netdev, linux-usb
In-Reply-To: <20100301163437.GE7881@phenom.dumpdata.com>

On Mon, 1 Mar 2010 11:34:37 -0500
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:

> On Sun, Feb 28, 2010 at 12:16:28AM -0800, David Miller wrote:
> > From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
> > Date: Sun, 28 Feb 2010 03:38:19 +0900
> > 
> > > When I proposed such approach (always use swiotlb) before, IIRC,
> > > the objections were:
> > > 
> > > - better to make allocation respect dma_mask. (I don't think that this
> > >   approach is possible since we don't know which device handles data
> > >   later when we allocate memory).
> > 
> > And such objects might end up being processed by multiple devices with
> > different DMA restrictions.
> > 
> > > - swiotlb is not good for small systems since it allocates too much
> > >   memory (we can fix this though).
> > 
> > Indeed.
> 
> What would be a good mechanism for this? Enumerating all of the PCI
> devices to find out which ones are 32-bit and then allocate some chunk
> of memory based on the amount of them? say, 1MB per card?
> 
> Or maybe a simpler one - figure out how many pages we have an allocate
> based on some sliding rule (say, 8MB for under 512MB, 16MB between 512MB
> and 2GB, and 32MB for 2GB to 4GB, and after that the full 64MB?)

Hmm, have you read the above objection from embedded system people ? :)

We can't pre-allocate such lots of memory (several MB). And we don't
need to.

We have to pre-allocate some for the block layer (we have to guarantee
that we can handle one request at least), however we don't need to
pre-allocate for the rest (including the network stack).

This guarantee is a bit difficult since the dma_map_* doesn't know who
is at the upper layer; the dma_map_* cannot know if it needs to
allocate from the pre-allocated pool or not. I thought about adding
'dma attribute flag' to struct device (to be exact, struct
device_dma_parameters).

^ 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