Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH linux-next v4 2/2] ixgbe: Example usage of the new IRQ affinity_hint callback
From: Thomas Gleixner @ 2010-04-30 21:47 UTC (permalink / raw)
  To: Peter P Waskiewicz Jr; +Cc: davem, arjan, bhutchings, netdev, linux-kernel
In-Reply-To: <20100430214517.3992.92545.stgit@ppwaskie-hc2.jf.intel.com>

On Fri, 30 Apr 2010, Peter P Waskiewicz Jr wrote:
> +	for (i = 0; i < num_q_vectors; i++) {
> +		struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
> +		/* release the CPU mask memory */
> +		free_cpumask_var(q_vector->affinity_mask);
> +		/* clear the affinity_mask in the IRQ descriptor */
> +		irq_set_affinity_hint(adapter->msix_entries[i].vector, NULL);

Freeing the mask _AFTER_ clearing the hint might be a worthwhile
exercise :)

Thanks,

	tglx

^ permalink raw reply

* [patch 11/13] KS8851: Update ks8851.h header from ks8851_mll.c
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-reduce-header-duplication2.patch --]
[-- Type: text/plain, Size: 4272 bytes --]

Move more useful definitions from ks8851_mll.c into ks8851.h and include
a brief copyright update from the mll source file. Also mop up a few
definitions that got missed in the first patch.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---

---
 drivers/net/ks8851.h     |   27 +++++++++++++++++++++++++++
 drivers/net/ks8851_mll.c |   40 +---------------------------------------
 2 files changed, 28 insertions(+), 39 deletions(-)

Index: b/drivers/net/ks8851.h
===================================================================
--- a/drivers/net/ks8851.h	2010-04-20 18:38:38.000000000 +0100
+++ b/drivers/net/ks8851.h	2010-04-20 18:39:02.000000000 +0100
@@ -3,6 +3,9 @@
  * Copyright 2009 Simtec Electronics
  *      Ben Dooks <ben@simtec.co.uk>
  *
+ * portions from drivers/net/ks8851_mll.c,
+ *	Copyright (c) 2009 Micrel Inc.
+ *
  * KS8851 register definitions
  *
  * This program is free software; you can redistribute it and/or modify
@@ -13,6 +16,10 @@
 #define KS_CCR					0x08
 #define CCR_EEPROM				(1 << 9)
 #define CCR_SPI					(1 << 8)
+#define CCR_8BIT				(1 << 7)
+#define CCR_16BIT				(1 << 6)
+#define CCR_32BIT				(1 << 5)
+#define CCR_SHARED				(1 << 4)
 #define CCR_32PIN				(1 << 0)
 
 /* MAC address registers */
@@ -250,7 +257,13 @@
 
 /* Standard MII PHY data */
 #define KS_P1MBCR				0xE4
+#define P1MBCR_FORCE_FDX			(1 << 8)
+
 #define KS_P1MBSR				0xE6
+#define P1MBSR_AN_COMPLETE			(1 << 5)
+#define P1MBSR_AN_CAPABLE			(1 << 3)
+#define P1MBSR_LINK_UP				(1 << 2)
+
 #define KS_PHY1ILR				0xE8
 #define KS_PHY1IHR				0xEA
 #define KS_P1ANAR				0xEC
@@ -285,6 +298,20 @@
 #define P1CR_PNTR_10BT_FDX			(1 << 1)
 #define P1CR_PNTR_10BT_HDX			(1 << 0)
 
+#define KS_P1SR					0xF8
+#define P1SR_HP_MDIX				(1 << 15)
+#define P1SR_REV_POL				(1 << 13)
+#define P1SR_OP_100M				(1 << 10)
+#define P1SR_OP_FDX				(1 << 9)
+#define P1SR_OP_MDI				(1 << 7)
+#define P1SR_AN_DONE				(1 << 6)
+#define P1SR_LINK_GOOD				(1 << 5)
+#define P1SR_PNTR_FLOW				(1 << 4)
+#define P1SR_PNTR_100BT_FDX			(1 << 3)
+#define P1SR_PNTR_100BT_HDX			(1 << 2)
+#define P1SR_PNTR_10BT_FDX			(1 << 1)
+#define P1SR_PNTR_10BT_HDX			(1 << 0)
+
 /* TX Frame control */
 
 #define TXFR_TXIC				(1 << 15)
Index: b/drivers/net/ks8851_mll.c
===================================================================
--- a/drivers/net/ks8851_mll.c	2010-04-20 18:38:42.000000000 +0100
+++ b/drivers/net/ks8851_mll.c	2010-04-20 18:39:02.000000000 +0100
@@ -43,13 +43,6 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
 #define TX_BUF_SIZE			2000
 #define RX_BUF_SIZE			2000
 
-#define CCR_8BIT			(1 << 7)
-#define CCR_16BIT			(1 << 6)
-#define CCR_32BIT			(1 << 5)
-#define CCR_SHARED			(1 << 4)
-
-#define OBCR_ODS_16MA			(1 << 6)
-
 #define RXCR1_FILTER_MASK    		(RXCR1_RXINVF | RXCR1_RXAE | \
 					 RXCR1_RXMAFMA | RXCR1_RXPAFMA)
 
@@ -65,41 +58,10 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
 
 #define RXQCR_CMD_CNTL                	(RXQCR_RXFCTE|RXQCR_ADRFE)
 
-#define KS_TXFDPR			0x84
-#define TXFDPR_TXFPAI			(1 << 14)
-#define TXFDPR_TXFP_MASK		(0x7ff << 0)
-#define TXFDPR_TXFP_SHIFT		(0)
-
-#define KS_RXFDPR			0x86
-#define RXFDPR_RXFPAI			(1 << 14)
-
 #define RXFCTR_THRESHOLD_MASK     	0x00FF
 
-#define P1MBCR_FORCE_FDX		(1 << 8)
-
-#define P1MBSR_AN_COMPLETE		(1 << 5)
-#define P1MBSR_AN_CAPABLE		(1 << 3)
-#define P1MBSR_LINK_UP			(1 << 2)
-
 /* TX Frame control */
 
-#define TXFR_TXIC			(1 << 15)
-#define TXFR_TXFID_MASK			(0x3f << 0)
-#define TXFR_TXFID_SHIFT		(0)
-
-#define KS_P1SR				0xF8
-#define P1SR_HP_MDIX			(1 << 15)
-#define P1SR_REV_POL			(1 << 13)
-#define P1SR_OP_100M			(1 << 10)
-#define P1SR_OP_FDX			(1 << 9)
-#define P1SR_OP_MDI			(1 << 7)
-#define P1SR_AN_DONE			(1 << 6)
-#define P1SR_LINK_GOOD			(1 << 5)
-#define P1SR_PNTR_FLOW			(1 << 4)
-#define P1SR_PNTR_100BT_FDX		(1 << 3)
-#define P1SR_PNTR_100BT_HDX		(1 << 2)
-#define P1SR_PNTR_10BT_FDX		(1 << 1)
-#define P1SR_PNTR_10BT_HDX		(1 << 0)
 
 #define	ENUM_BUS_NONE			0
 #define	ENUM_BUS_8BIT			1
@@ -1362,7 +1324,7 @@ static int __devinit ks8851_probe(struct
 	memcpy(netdev->dev_addr, ks->mac_addr, 6);
 
 	data = ks_rdreg16(ks, KS_OBCR);
-	ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16MA);
+	ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16mA);
 
 	/**
 	 * If you want to use the default MAC addr,


^ permalink raw reply

* [patch 05/13] KSZ8851-SNL: Add support for EEPROM MAC address
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-mac-from-eeprom.patch --]
[-- Type: text/plain, Size: 3404 bytes --]

Add support for reading the MAC address from the system registers if there
is an EEPROM present. This involves caching the KS_CCR register for later
use (will also be useful for ETHTOOL support) and adding a print to say
that there is an EEPROM present.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---

---
 drivers/net/ks8851.c |   46 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 39 insertions(+), 7 deletions(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 00:51:12.489525834 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 00:52:02.377026762 +0900
@@ -76,6 +76,7 @@ union ks8851_tx_hdr {
  * @msg_enable: The message flags controlling driver output (see ethtool).
  * @fid: Incrementing frame id tag.
  * @rc_ier: Cached copy of KS_IER.
+ * @rc_ccr: Cached copy of KS_CCR.
  * @rc_rxqcr: Cached copy of KS_RXQCR.
  *
  * The @lock ensures that the chip is protected when certain operations are
@@ -107,6 +108,7 @@ struct ks8851_net {
 
 	u16			rc_ier;
 	u16			rc_rxqcr;
+	u16			rc_ccr;
 
 	struct mii_if_info	mii;
 	struct ks8851_rxctrl	rxctrl;
@@ -367,21 +369,47 @@ static int ks8851_write_mac_addr(struct 
 }
 
 /**
+ * ks8851_read_mac_addr - read mac address from device registers
+ * @dev: The network device
+ *
+ * Update our copy of the KS8851 MAC address from the registers of @dev.
+*/
+static void ks8851_read_mac_addr(struct net_device *dev)
+{
+	struct ks8851_net *ks = netdev_priv(dev);
+	int i;
+
+	mutex_lock(&ks->lock);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		dev->dev_addr[i] = ks8851_rdreg8(ks, KS_MAR(i));
+
+	mutex_unlock(&ks->lock);
+}
+
+/**
  * ks8851_init_mac - initialise the mac address
  * @ks: The device structure
  *
  * Get or create the initial mac address for the device and then set that
- * into the station address register. Currently we assume that the device
- * does not have a valid mac address in it, and so we use random_ether_addr()
+ * into the station address register. If there is an EEPROM present, then
+ * we try that. If no valid mac address is found we use random_ether_addr()
  * to create a new one.
- *
- * In future, the driver should check to see if the device has an EEPROM
- * attached and whether that has a valid ethernet address in it.
  */
 static void ks8851_init_mac(struct ks8851_net *ks)
 {
 	struct net_device *dev = ks->netdev;
 
+	/* first, try reading what we've got already */
+	if (ks->rc_ccr & CCR_EEPROM) {
+		ks8851_read_mac_addr(dev);
+		if (is_valid_ether_addr(dev->dev_addr))
+			return;
+
+		ks_err(ks, "invalid mac address read %pM\n",
+			dev->dev_addr);
+	}
+
 	random_ether_addr(dev->dev_addr);
 	ks8851_write_mac_addr(dev);
 }
@@ -1288,6 +1316,9 @@ static int __devinit ks8851_probe(struct
 		goto err_id;
 	}
 
+  	/* cache the contents of the CCR register for EEPROM, etc. */
+  	ks->rc_ccr = ks8851_rdreg16(ks, KS_CCR);
+
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
 	ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
@@ -1305,9 +1336,10 @@ static int __devinit ks8851_probe(struct
 		goto err_netdev;
 	}
 
-	dev_info(&spi->dev, "revision %d, MAC %pM, IRQ %d\n",
+	dev_info(&spi->dev, "revision %d, MAC %pM, IRQ %d, %s EEPROM\n",
 		 CIDER_REV_GET(ks8851_rdreg16(ks, KS_CIDER)),
-		 ndev->dev_addr, ndev->irq);
+		 ndev->dev_addr, ndev->irq,
+		 ks->rc_ccr & CCR_EEPROM ? "has" : "no");
 
 	return 0;
 


^ permalink raw reply

* [patch 13/13] KSZ8851-SNL: Add platform data to specific IRQ trigger type.
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-add-platform-data.patch --]
[-- Type: text/plain, Size: 3786 bytes --]

Add platform data to allow the board registering the SPI device to
pass what IRQ trigger type it needs to the driver. The default of
low-level trigger is used if no data is specified, or the field is
zero.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---
 drivers/net/ks8851.c   |   27 +++++++++++++++++++++++----
 include/linux/ks8851.h |   23 +++++++++++++++++++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:28:32.719525804 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:28:37.229527494 +0900
@@ -20,6 +20,7 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/eeprom_93cx6.h>
+#include <linux/ks8851.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -70,6 +71,7 @@ struct ks8851_rxctrl {
  * @rc_ccr: Cached copy of KS_CCR.
  * @rc_rxqcr: Cached copy of KS_RXQCR.
  * @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
+ * @irq_flags: The IRQ flags passed to request_irq().
  *
  * The @lock ensures that the chip is protected when certain operations are
  * in progress. When the read or write packet transfer is in progress, most
@@ -439,6 +441,15 @@ static void ks8851_init_mac(struct ks885
 }
 
 /**
+ * is_level_irq() - return if the given IRQ flags are level triggered
+ * @flags: The flags passed to request_irq().
+*/
+static bool is_level_irq(unsigned flags)
+{
+	return flags & (IRQF_TIRGGER_LOW | IRQF_TRIGGER_HIGH);
+}
+
+/**
  * ks8851_irq - device interrupt handler
  * @irq: Interrupt number passed from the IRQ hnalder.
  * @pw: The private word passed to register_irq(), our struct ks8851_net.
@@ -450,7 +461,9 @@ static irqreturn_t ks8851_irq(int irq, v
 {
 	struct ks8851_net *ks = pw;
 
-	disable_irq_nosync(irq);
+	if (is_level_irq(ks->irq_flags))
+		disable_irq_nosync(irq);
+
 	schedule_work(&ks->irq_work);
 	return IRQ_HANDLED;
 }
@@ -674,7 +687,8 @@ static void ks8851_irq_work(struct work_
 
 	mutex_unlock(&ks->lock);
 
-	enable_irq(ks->netdev->irq);
+	if (is_level_irq(ks->irq_flags))
+		enable_irq(ks->netdev->irq);
 }
 
 /**
@@ -1493,6 +1507,7 @@ static void __devexit ks8851_delete_debu
 
 static int __devinit ks8851_probe(struct spi_device *spi)
 {
+	struct ks8851_pdata *pd = spi->dev.platform_data;
 	struct net_device *ndev;
 	struct ks8851_net *ks;
 	int ret;
@@ -1578,8 +1593,12 @@ static int __devinit ks8851_probe(struct
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
 
-	ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
-			  ndev->name, ks);
+	if (pd && pd->irq_flags)
+		ks->irq_flags = pd->irq_flags;
+	else
+		ks->irq_flags = IRQF_TRIGGER_LOW;
+
+	ret = request_irq(spi->irq, ks8851_irq, ks->irq_flags, ndev->name, ks);
 	if (ret < 0) {
 		dev_err(&spi->dev, "failed to get irq\n");
 		goto err_irq;
Index: b/include/linux/ks8851.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/include/linux/ks8851.h	2010-04-29 01:28:37.000000000 +0900
@@ -0,0 +1,23 @@
+/* include/linux/ks8851.h
+ *
+ * Platform specific configuration data for KS8851 driver.
+ *
+ * Copyright 2009 Simtec Electronics
+ *	http://www.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/**
+ * struct ks8851_pdata - platform specific configuration data
+ * @irq_flags: The IRQ trigger flags to pass to request_irq().
+ *
+ * Platform specific configuration to be passed from board support
+ * registering the spi device to the driver.
+ */
+struct ks8851_pdata {
+	unsigned	irq_flags;
+};


^ permalink raw reply

* [patch 06/13] KSZ8851-SNL: Fix MAC address change problem
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Tristram Ha
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: thirdparty/micrel/ksz8851-fix-mac.patch --]
[-- Type: text/plain, Size: 2946 bytes --]

From: Tristram Ha <Tristram.Ha@micrel.com>

When device is off it is under power saving mode. Changing the MAC address
in that situation will result in the device not communicating as the first
write to the MAC address register is not executed.

Signed-off-by: Tristram Ha <Tristram.Ha@micrel.com>
[ben@simtec.co.uk: cleaned up header]
Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---
---
 drivers/net/ks8851.c |   30 ++++++++++++++++++++++++++++--
 drivers/net/ks8851.h |    2 +-
 2 files changed, 29 insertions(+), 3 deletions(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:00:15.519525666 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:01:31.118391091 +0900
@@ -345,6 +345,26 @@ static void ks8851_soft_reset(struct ks8
 }
 
 /**
+ * ks8851_set_powermode - set power mode of the device
+ * @ks: The device state
+ * @pwrmode: The power mode value to write to KS_PMECR.
+ *
+ * Change the power mode of the chip.
+ */
+static void ks8851_set_powermode(struct ks8851_net *ks, unsigned pwrmode)
+{
+	unsigned pmecr;
+
+	netif_dbg(ks, hw, ks->netdev, "setting power mode %d\n", pwrmode);
+
+	pmecr = ks8851_rdreg16(ks, KS_PMECR);
+	pmecr &= ~PMECR_PM_MASK;
+	pmecr |= pwrmode;
+
+	ks8851_wrreg16(ks, KS_PMECR, pmecr);
+}
+
+/**
  * ks8851_write_mac_addr - write mac address to device registers
  * @dev: The network device
  *
@@ -360,8 +380,15 @@ static int ks8851_write_mac_addr(struct 
 
 	mutex_lock(&ks->lock);
 
+	/*
+	 * Wake up chip in case it was powered off when stopped; otherwise,
+	 * the first write to the MAC address does not take effect.
+	 */
+	ks8851_set_powermode(ks, PMECR_PM_NORMAL);
 	for (i = 0; i < ETH_ALEN; i++)
 		ks8851_wrreg8(ks, KS_MAR(i), dev->dev_addr[i]);
+	if (!netif_running(dev))
+		ks8851_set_powermode(ks, PMECR_PM_SOFTDOWN);
 
 	mutex_unlock(&ks->lock);
 
@@ -1260,7 +1287,6 @@ static int __devinit ks8851_probe(struct
 
 	ks->netdev = ndev;
 	ks->spidev = spi;
-	ks->tx_space = 6144;
 
 	mutex_init(&ks->lock);
 	spin_lock_init(&ks->statelock);
@@ -1318,10 +1344,10 @@ static int __devinit ks8851_probe(struct
 
   	/* cache the contents of the CCR register for EEPROM, etc. */
   	ks->rc_ccr = ks8851_rdreg16(ks, KS_CCR);
+	ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
 
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
-	ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
 
 	ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
 			  ndev->name, ks);
Index: b/drivers/net/ks8851.h
===================================================================
--- a/drivers/net/ks8851.h	2010-04-28 23:24:20.647026644 +0900
+++ b/drivers/net/ks8851.h	2010-04-29 01:00:35.029526937 +0900
@@ -16,7 +16,7 @@
 #define CCR_32PIN				(1 << 0)
 
 /* MAC address registers */
-#define KS_MAR(_m)				0x15 - (_m)
+#define KS_MAR(_m)				(0x15 - (_m))
 #define KS_MARL					0x10
 #define KS_MARM					0x12
 #define KS_MARH					0x14


^ permalink raw reply

* [patch 02/13] KSZ8851-SNL: Fix receive interrupt problem.
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Tristram Ha
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: thirdparty/micrel/ks8851-rx-fixeml.txt --]
[-- Type: text/plain, Size: 1438 bytes --]

From: Tristram Ha <Tristram.Ha@micrel.com>

This fixes a receive problem of the ks8851 snl network driver.

Under heavy TCP traffic the device will stop operating correctly. First
the receive interrupt is not triggered anymore.  After then the driver
cannot retrieve the correct packets from the device.  A workaround for
this problem is to disable the transmit done interrupt.

Signed-off-by: Tristram Ha <Tristram.Ha@micrel.com>
[ben@simtec.co.uk: cleaned up header]
Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---
---
 drivers/net/ks8851.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-28 23:24:20.737026841 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 00:51:12.489525834 +0900
@@ -553,6 +553,13 @@ static void ks8851_irq_work(struct work_
 
 	mutex_lock(&ks->lock);
 
+	/*
+	 * Turn off hardware interrupt during receive processing.  This fixes
+	 * the receive problem under heavy TCP traffic while transmit done
+	 * is enabled.
+	 */
+	ks8851_wrreg16(ks, KS_IER, 0);
+
 	status = ks8851_rdreg16(ks, KS_ISR);
 
 	if (netif_msg_intr(ks))
@@ -610,6 +617,9 @@ static void ks8851_irq_work(struct work_
 		ks8851_wrreg16(ks, KS_RXCR1, rxc->rxcr1);
 	}
 
+	/* Re-enable hardware interrupt. */
+	ks8851_wrreg16(ks, KS_IER, ks->rc_ier);
+
 	mutex_unlock(&ks->lock);
 
 	enable_irq(ks->netdev->irq);


^ permalink raw reply

* [patch 00/13] Micrel KSZ8851 updates and fixes
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support

Please consider this set for the next merge window.

Included 93CX^ driver as didn't find anywhere better to send it.

-- 
Ben (ben@fluff.org, http://www.fluff.org/)

  'a smiley only costs 4 bytes'

^ permalink raw reply

* [patch 09/13] KSZ8851-SNL: Add debugfs export for driver state
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-add-debugfs.patch --]
[-- Type: text/plain, Size: 3868 bytes --]

Add the ability to export the state of each network chip via debugfs
to show the cached register state and some of the network device state
information.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---
 drivers/net/ks8851.c |   94 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:22:47.779528264 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:25:54.217027162 +0900
@@ -21,6 +21,9 @@
 #include <linux/mii.h>
 #include <linux/eeprom_93cx6.h>
 
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
 #include <linux/spi/spi.h>
 
 #include "ks8851.h"
@@ -128,6 +131,9 @@ struct ks8851_net {
 	struct spi_transfer	spi_xfer1;
 	struct spi_transfer	spi_xfer2[2];
 
+	struct dentry		*debug_root;
+	struct dentry		*debug_file;
+
 	struct eeprom_93cx6	eeprom;
 };
 
@@ -1411,6 +1417,91 @@ static int ks8851_read_selftest(struct k
 	return 0;
 }
 
+/* debugfs code */
+static int state_show(struct seq_file *seq, void *v)
+{
+	struct ks8851_net *ks = seq->private;
+	struct net_device *ndev = ks->netdev;
+
+	seq_printf(seq, "Register cache:\n");
+	seq_printf(seq, "IEQ\t 0x%04x\n", ks->rc_ier);
+	seq_printf(seq, "RXQCR\t 0x%04x\n", ks->rc_rxqcr);
+	seq_printf(seq, "CCR\t 0x%04x\n", ks->rc_ccr);
+	seq_printf(seq, "RXCR1\t 0x%04x\n", ks->rxctrl.rxcr1);
+	seq_printf(seq, "RXCR2\t 0x%04x\n", ks->rxctrl.rxcr2);
+	seq_printf(seq, "MCHASH\t 0=0x%04x, 1=%04x, 2=0x%04x, 3=0x%04x\n",
+		   ks->rxctrl.mchash[0], ks->rxctrl.mchash[1],
+		   ks->rxctrl.mchash[2], ks->rxctrl.mchash[3]);
+
+	seq_printf(seq, "\n");
+
+	seq_printf(seq, "tx_space = 0x%04x\n", ks->tx_space);
+	seq_printf(seq, "tx fid\t= 0x%02x\n", ks->fid);
+
+	seq_printf(seq, "\n");
+
+	if (ndev->flags & IFF_MULTICAST) {
+		struct dev_mc_list *mcptr = ndev->mc_list;
+		int i;
+
+		seq_printf(seq, "MC list is %d entries\n", ndev->mc_count);
+
+		for (i = 0; i < ndev->mc_count; i++) {
+			seq_printf(seq, "\t%d: %pM\n", i, mcptr->dmi_addr);
+			mcptr = mcptr->next;
+		}
+	} else
+		seq_printf(seq, "No multicast list set\n");
+
+	return 0;
+}
+
+static int state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, state_show, inode->i_private);
+}
+
+static const struct file_operations state_fops = {
+	.owner	= THIS_MODULE,
+	.open	= state_open,
+	.read	= seq_read,
+	.llseek	= seq_lseek,
+	.release = single_release,
+};
+
+/**
+ * ks8851_create_debugfs - create debugfs directory and files
+ * @ks: The driver state
+ *
+ * Create the debugfs entries for the specific device.
+ */
+static void __devinit ks8851_create_debugfs(struct ks8851_net *ks)
+{
+	struct dentry *root;
+	char root_name[32];
+
+	snprintf(root_name, sizeof(root_name), "ks8851_%s",
+		 dev_name(&ks->spidev->dev));
+
+	root = debugfs_create_dir(root_name, NULL);
+	if (IS_ERR(root)) {
+		ks_err(ks, "cannot create debugfs root\n");
+		return;
+	}
+
+	ks->debug_root = root;
+	ks->debug_file = debugfs_create_file("state", 0444, root,
+					     ks, &state_fops);
+	if (IS_ERR(ks->debug_file))
+		ks_err(ks, "cannot create debugfs state file\n");
+}
+
+static void __devexit ks8851_delete_debugfs(struct ks8851_net *ks)
+{
+	debugfs_remove(ks->debug_file);
+	debugfs_remove(ks->debug_root);
+}
+
 /* driver bus management functions */
 
 static int __devinit ks8851_probe(struct spi_device *spi)
@@ -1518,6 +1609,8 @@ static int __devinit ks8851_probe(struct
 		 ndev->dev_addr, ndev->irq,
 		 ks->rc_ccr & CCR_EEPROM ? "has" : "no");
 
+	ks8851_create_debugfs(ks);
+
 	return 0;
 
 
@@ -1537,6 +1630,7 @@ static int __devexit ks8851_remove(struc
 	if (netif_msg_drv(priv))
 		dev_info(&spi->dev, "remove");
 
+	ks8851_delete_debugfs(priv);
 	unregister_netdev(priv->netdev);
 	free_irq(spi->irq, priv);
 	free_netdev(priv->netdev);


^ permalink raw reply

* [patch 08/13] KSZ8851-SNL: Fix EEPROM access problem
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Tristram Ha
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: thirdparty/micrel/ksz8851-fix-eeprom.patch --]
[-- Type: text/plain, Size: 1304 bytes --]

From: Tristram Ha <Tristram.Ha@micrel.com>

Accessing the EEPROM when the device is receiving sometimes hangs the
system as the hardware is not locked down.

Signed-off-by: Tristram Ha <Tristram.Ha@micrel.com>
[ben@simtec.co.uk: fix description text]
Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---
---
 drivers/net/ks8851.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:22:42.667052653 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:22:47.779528264 +0900
@@ -1181,7 +1181,6 @@ static void ks8851_eeprom_regwrite(struc
 	if (ee->reg_chip_select)
 		val |= EEPCR_EECS;
 
-	printk(KERN_INFO "%s: wr %04x\n", __func__, val);
 	ks8851_wrreg16(ks, KS_EEPCR, val);
 }
 
@@ -1197,6 +1196,8 @@ static int ks8851_eeprom_claim(struct ks
 	if (!(ks->rc_ccr & CCR_EEPROM))
 		return -ENOENT;
 
+	mutex_lock(&ks->lock);
+
 	/* start with clock low, cs high */
 	ks8851_wrreg16(ks, KS_EEPCR, EEPCR_EESA | EEPCR_EECS);
 	return 0;
@@ -1213,6 +1214,7 @@ static void ks8851_eeprom_release(struct
 	unsigned val = ks8851_rdreg16(ks,KS_EEPCR);
 
 	ks8851_wrreg16(ks, KS_EEPCR, val & ~EEPCR_EESA);
+	mutex_unlock(&ks->lock);
 }
 
 #define KS_EEPROM_MAGIC (0x00008851)


^ permalink raw reply

* [patch 07/13] KSZ8851-SNL: Add ethtool support for EEPROM
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Simtec Linux Team
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-add-eeprom-ethtool.patch --]
[-- Type: text/plain, Size: 6382 bytes --]

Add ethtool EEPROM read/write support for the KS8851 driver.

Depends on eeprom_93cx6 driver getting EEPROM write support.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>
Signed-off-by: Simtec Linux Team <linux@simtec.co.uk>

---
 drivers/net/Kconfig  |    1 
 drivers/net/ks8851.c |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ks8851.h |    1 
 3 files changed, 151 insertions(+)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:01:31.118391091 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:22:42.667052653 +0900
@@ -19,6 +19,7 @@
 #include <linux/cache.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
+#include <linux/eeprom_93cx6.h>
 
 #include <linux/spi/spi.h>
 
@@ -78,6 +79,7 @@ union ks8851_tx_hdr {
  * @rc_ier: Cached copy of KS_IER.
  * @rc_ccr: Cached copy of KS_CCR.
  * @rc_rxqcr: Cached copy of KS_RXQCR.
+ * @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
  *
  * The @lock ensures that the chip is protected when certain operations are
  * in progress. When the read or write packet transfer is in progress, most
@@ -125,6 +127,8 @@ struct ks8851_net {
 	struct spi_message	spi_msg2;
 	struct spi_transfer	spi_xfer1;
 	struct spi_transfer	spi_xfer2[2];
+
+	struct eeprom_93cx6	eeprom;
 };
 
 static int msg_enable;
@@ -1149,6 +1153,141 @@ static int ks8851_nway_reset(struct net_
 	return mii_nway_restart(&ks->mii);
 }
 
+/* EEPROM support */
+
+static void ks8851_eeprom_regread(struct eeprom_93cx6 *ee)
+{
+	struct ks8851_net *ks = ee->data;
+	unsigned val;
+
+	val = ks8851_rdreg16(ks, KS_EEPCR);
+
+	ee->reg_data_out = (val & EEPCR_EESB) ? 1 : 0;
+	ee->reg_data_clock = (val & EEPCR_EESCK) ? 1 : 0;
+	ee->reg_chip_select = (val & EEPCR_EECS) ? 1 : 0;
+}
+
+static void ks8851_eeprom_regwrite(struct eeprom_93cx6 *ee)
+{
+	struct ks8851_net *ks = ee->data;
+	unsigned val = EEPCR_EESA;	/* default - eeprom access on */
+
+	if (ee->drive_data)
+		val |= EEPRC_EESRW;
+	if (ee->reg_data_in)
+		val |= EEPCR_EEDO;
+	if (ee->reg_data_clock)
+		val |= EEPCR_EESCK;
+	if (ee->reg_chip_select)
+		val |= EEPCR_EECS;
+
+	printk(KERN_INFO "%s: wr %04x\n", __func__, val);
+	ks8851_wrreg16(ks, KS_EEPCR, val);
+}
+
+/**
+ * ks8851_eeprom_claim - claim device EEPROM and activate the interface
+ * @ks: The network deice state.
+ *
+ * Check for the presence of an EEPROM, and then activate software access
+ * to the device.
+ */
+static int ks8851_eeprom_claim(struct ks8851_net *ks)
+{
+	if (!(ks->rc_ccr & CCR_EEPROM))
+		return -ENOENT;
+
+	/* start with clock low, cs high */
+	ks8851_wrreg16(ks, KS_EEPCR, EEPCR_EESA | EEPCR_EECS);
+	return 0;
+}
+
+/**
+ * ks8851_eeprom_release - release the EEPROM interface
+ * @ks: The device state
+ *
+ * Release the software access to the device EEPROM
+ */
+static void ks8851_eeprom_release(struct ks8851_net *ks)
+{
+	unsigned val = ks8851_rdreg16(ks,KS_EEPCR);
+
+	ks8851_wrreg16(ks, KS_EEPCR, val & ~EEPCR_EESA);
+}
+
+#define KS_EEPROM_MAGIC (0x00008851)
+
+static int ks8851_set_eeprom(struct net_device *dev,
+			     struct ethtool_eeprom *ee, u8 *data)
+{
+	struct ks8851_net *ks = netdev_priv(dev);
+	int offset = ee->offset;
+	int len = ee->len;
+	u16 tmp;
+
+	/* currently only support byte writing */
+	if (len != 1)
+		return -EINVAL;
+
+	if (ee->magic != KS_EEPROM_MAGIC)
+		return -EINVAL;
+
+	if (ks8851_eeprom_claim(ks))
+		return -ENOENT;
+
+	eeprom_93cx6_wren(&ks->eeprom, true);
+
+	/* ethtool currently only supports writing bytes, which means
+	 * we have to read/modify/write our 16bit EEPROMs */
+
+	eeprom_93cx6_read(&ks->eeprom, offset/2, &tmp);
+
+	if (offset & 1) {
+		tmp &= 0xff;
+		tmp |= *data << 8;
+	} else {
+		tmp &= 0xff00;
+		tmp |= *data;
+	}
+
+	eeprom_93cx6_write(&ks->eeprom, offset/2, tmp);
+	eeprom_93cx6_wren(&ks->eeprom, false);
+
+	ks8851_eeprom_release(ks);
+
+	return 0;
+}
+
+static int ks8851_get_eeprom(struct net_device *dev,
+			     struct ethtool_eeprom *ee, u8 *data)
+{
+	struct ks8851_net *ks = netdev_priv(dev);
+	int offset = ee->offset;
+	int len = ee->len;
+
+	/* must be 2 byte aligned */
+	if (len & 1 || offset & 1)
+		return -EINVAL;
+
+	if (ks8851_eeprom_claim(ks))
+		return -ENOENT;
+
+	ee->magic = KS_EEPROM_MAGIC;
+
+	eeprom_93cx6_multiread(&ks->eeprom, offset/2, (__le16 *)data, len/2);
+	ks8851_eeprom_release(ks);
+
+	return 0;
+}
+
+static int ks8851_get_eeprom_len(struct net_device *dev)
+{
+	struct ks8851_net *ks = netdev_priv(dev);
+
+	/* currently, we assume it is an 93C46 attached, so return 128 */
+	return ks->rc_ccr & CCR_EEPROM ? 128 : 0;
+}
+
 static const struct ethtool_ops ks8851_ethtool_ops = {
 	.get_drvinfo	= ks8851_get_drvinfo,
 	.get_msglevel	= ks8851_get_msglevel,
@@ -1157,6 +1296,9 @@ static const struct ethtool_ops ks8851_e
 	.set_settings	= ks8851_set_settings,
 	.get_link	= ks8851_get_link,
 	.nway_reset	= ks8851_nway_reset,
+	.get_eeprom_len = ks8851_get_eeprom_len,
+	.get_eeprom	= ks8851_get_eeprom,
+	.set_eeprom	= ks8851_set_eeprom,
 };
 
 /* MII interface controls */
@@ -1305,6 +1447,13 @@ static int __devinit ks8851_probe(struct
 	spi_message_add_tail(&ks->spi_xfer2[0], &ks->spi_msg2);
 	spi_message_add_tail(&ks->spi_xfer2[1], &ks->spi_msg2);
 
+	/* setup EEPROM state */
+
+	ks->eeprom.data = ks;
+	ks->eeprom.width = PCI_EEPROM_WIDTH_93C46;
+	ks->eeprom.register_read = ks8851_eeprom_regread;
+	ks->eeprom.register_write = ks8851_eeprom_regwrite;
+
 	/* setup mii state */
 	ks->mii.dev		= ndev;
 	ks->mii.phy_id		= 1,
Index: b/drivers/net/Kconfig
===================================================================
--- a/drivers/net/Kconfig	2010-04-28 23:24:20.657052849 +0900
+++ b/drivers/net/Kconfig	2010-04-29 01:22:42.667052653 +0900
@@ -1766,6 +1766,7 @@ config KS8851
        depends on SPI
        select MII
 	select CRC32
+	select EEPROM_93CX6
        help
          SPI driver for Micrel KS8851 SPI attached network chip.
 
Index: b/drivers/net/ks8851.h
===================================================================
--- a/drivers/net/ks8851.h	2010-04-29 01:00:35.029526937 +0900
+++ b/drivers/net/ks8851.h	2010-04-29 01:22:42.667052653 +0900
@@ -25,6 +25,7 @@
 #define OBCR_ODS_16mA				(1 << 6)
 
 #define KS_EEPCR				0x22
+#define EEPRC_EESRW				(1 << 5)
 #define EEPCR_EESA				(1 << 4)
 #define EEPCR_EESB				(1 << 3)
 #define EEPCR_EEDO				(1 << 2)


^ permalink raw reply

* [patch 10/13] KS8851: ks8851_mll.c: Use the ks8851.h header for device register defines
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Ben Dooks
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-reduce-header-duplication.patch --]
[-- Type: text/plain, Size: 9414 bytes --]

From: Ben Dooks <ben-linux@fluff.org>

The ks8851_mll.c file uses an almost identical copy of ks8851.h included
directly into the source code, baring some identation changes. This patch
removes the commone defines from ks8851_mll.c and includes ks8851.h.

As a note, we did not merge anything that is specific in ks8851_mll.c into
ks8851.h yet.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>

---
 drivers/net/ks8851_mll.c |  263 -----------------------------------------------
 1 file changed, 5 insertions(+), 258 deletions(-)

Index: b/drivers/net/ks8851_mll.c
===================================================================
--- a/drivers/net/ks8851_mll.c	2010-04-28 23:24:20.427026692 +0900
+++ b/drivers/net/ks8851_mll.c	2010-04-29 01:26:00.397035869 +0900
@@ -33,6 +33,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 
+#include "ks8851.h"
+
 #define	DRV_NAME	"ks8851_mll"
 
 static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x86, 0x95, 0x11 };
@@ -41,165 +43,26 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
 #define TX_BUF_SIZE			2000
 #define RX_BUF_SIZE			2000
 
-#define KS_CCR				0x08
-#define CCR_EEPROM			(1 << 9)
-#define CCR_SPI				(1 << 8)
 #define CCR_8BIT			(1 << 7)
 #define CCR_16BIT			(1 << 6)
 #define CCR_32BIT			(1 << 5)
 #define CCR_SHARED			(1 << 4)
-#define CCR_32PIN			(1 << 0)
-
-/* MAC address registers */
-#define KS_MARL				0x10
-#define KS_MARM				0x12
-#define KS_MARH				0x14
 
-#define KS_OBCR				0x20
 #define OBCR_ODS_16MA			(1 << 6)
 
-#define KS_EEPCR			0x22
-#define EEPCR_EESA			(1 << 4)
-#define EEPCR_EESB			(1 << 3)
-#define EEPCR_EEDO			(1 << 2)
-#define EEPCR_EESCK			(1 << 1)
-#define EEPCR_EECS			(1 << 0)
-
-#define KS_MBIR				0x24
-#define MBIR_TXMBF			(1 << 12)
-#define MBIR_TXMBFA			(1 << 11)
-#define MBIR_RXMBF			(1 << 4)
-#define MBIR_RXMBFA			(1 << 3)
-
-#define KS_GRR				0x26
-#define GRR_QMU				(1 << 1)
-#define GRR_GSR				(1 << 0)
-
-#define KS_WFCR				0x2A
-#define WFCR_MPRXE			(1 << 7)
-#define WFCR_WF3E			(1 << 3)
-#define WFCR_WF2E			(1 << 2)
-#define WFCR_WF1E			(1 << 1)
-#define WFCR_WF0E			(1 << 0)
-
-#define KS_WF0CRC0			0x30
-#define KS_WF0CRC1			0x32
-#define KS_WF0BM0			0x34
-#define KS_WF0BM1			0x36
-#define KS_WF0BM2			0x38
-#define KS_WF0BM3			0x3A
-
-#define KS_WF1CRC0			0x40
-#define KS_WF1CRC1			0x42
-#define KS_WF1BM0			0x44
-#define KS_WF1BM1			0x46
-#define KS_WF1BM2			0x48
-#define KS_WF1BM3			0x4A
-
-#define KS_WF2CRC0			0x50
-#define KS_WF2CRC1			0x52
-#define KS_WF2BM0			0x54
-#define KS_WF2BM1			0x56
-#define KS_WF2BM2			0x58
-#define KS_WF2BM3			0x5A
-
-#define KS_WF3CRC0			0x60
-#define KS_WF3CRC1			0x62
-#define KS_WF3BM0			0x64
-#define KS_WF3BM1			0x66
-#define KS_WF3BM2			0x68
-#define KS_WF3BM3			0x6A
-
-#define KS_TXCR				0x70
-#define TXCR_TCGICMP			(1 << 8)
-#define TXCR_TCGUDP			(1 << 7)
-#define TXCR_TCGTCP			(1 << 6)
-#define TXCR_TCGIP			(1 << 5)
-#define TXCR_FTXQ			(1 << 4)
-#define TXCR_TXFCE			(1 << 3)
-#define TXCR_TXPE			(1 << 2)
-#define TXCR_TXCRC			(1 << 1)
-#define TXCR_TXE			(1 << 0)
-
-#define KS_TXSR				0x72
-#define TXSR_TXLC			(1 << 13)
-#define TXSR_TXMC			(1 << 12)
-#define TXSR_TXFID_MASK			(0x3f << 0)
-#define TXSR_TXFID_SHIFT		(0)
-#define TXSR_TXFID_GET(_v)		(((_v) >> 0) & 0x3f)
-
-
-#define KS_RXCR1			0x74
-#define RXCR1_FRXQ			(1 << 15)
-#define RXCR1_RXUDPFCC			(1 << 14)
-#define RXCR1_RXTCPFCC			(1 << 13)
-#define RXCR1_RXIPFCC			(1 << 12)
-#define RXCR1_RXPAFMA			(1 << 11)
-#define RXCR1_RXFCE			(1 << 10)
-#define RXCR1_RXEFE			(1 << 9)
-#define RXCR1_RXMAFMA			(1 << 8)
-#define RXCR1_RXBE			(1 << 7)
-#define RXCR1_RXME			(1 << 6)
-#define RXCR1_RXUE			(1 << 5)
-#define RXCR1_RXAE			(1 << 4)
-#define RXCR1_RXINVF			(1 << 1)
-#define RXCR1_RXE			(1 << 0)
 #define RXCR1_FILTER_MASK    		(RXCR1_RXINVF | RXCR1_RXAE | \
 					 RXCR1_RXMAFMA | RXCR1_RXPAFMA)
 
-#define KS_RXCR2			0x76
-#define RXCR2_SRDBL_MASK		(0x7 << 5)
-#define RXCR2_SRDBL_SHIFT		(5)
-#define RXCR2_SRDBL_4B			(0x0 << 5)
-#define RXCR2_SRDBL_8B			(0x1 << 5)
-#define RXCR2_SRDBL_16B			(0x2 << 5)
-#define RXCR2_SRDBL_32B			(0x3 << 5)
-/* #define RXCR2_SRDBL_FRAME		(0x4 << 5) */
-#define RXCR2_IUFFP			(1 << 4)
-#define RXCR2_RXIUFCEZ			(1 << 3)
-#define RXCR2_UDPLFE			(1 << 2)
-#define RXCR2_RXICMPFCC			(1 << 1)
-#define RXCR2_RXSAF			(1 << 0)
-
-#define KS_TXMIR			0x78
-
-#define KS_RXFHSR			0x7C
-#define RXFSHR_RXFV			(1 << 15)
-#define RXFSHR_RXICMPFCS		(1 << 13)
-#define RXFSHR_RXIPFCS			(1 << 12)
-#define RXFSHR_RXTCPFCS			(1 << 11)
-#define RXFSHR_RXUDPFCS			(1 << 10)
-#define RXFSHR_RXBF			(1 << 7)
-#define RXFSHR_RXMF			(1 << 6)
-#define RXFSHR_RXUF			(1 << 5)
-#define RXFSHR_RXMR			(1 << 4)
-#define RXFSHR_RXFT			(1 << 3)
-#define RXFSHR_RXFTL			(1 << 2)
-#define RXFSHR_RXRF			(1 << 1)
-#define RXFSHR_RXCE			(1 << 0)
+#undef RXCR2_SRDBL_FRAME
+
 #define	RXFSHR_ERR			(RXFSHR_RXCE | RXFSHR_RXRF |\
 					RXFSHR_RXFTL | RXFSHR_RXMR |\
 					RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\
 					RXFSHR_RXTCPFCS)
+
 #define KS_RXFHBCR			0x7E
 #define RXFHBCR_CNT_MASK		0x0FFF
 
-#define KS_TXQCR			0x80
-#define TXQCR_AETFE			(1 << 2)
-#define TXQCR_TXQMAM			(1 << 1)
-#define TXQCR_METFE			(1 << 0)
-
-#define KS_RXQCR			0x82
-#define RXQCR_RXDTTS			(1 << 12)
-#define RXQCR_RXDBCTS			(1 << 11)
-#define RXQCR_RXFCTS			(1 << 10)
-#define RXQCR_RXIPHTOE			(1 << 9)
-#define RXQCR_RXDTTE			(1 << 7)
-#define RXQCR_RXDBCTE			(1 << 6)
-#define RXQCR_RXFCTE			(1 << 5)
-#define RXQCR_ADRFE			(1 << 4)
-#define RXQCR_SDA			(1 << 3)
-#define RXQCR_RRXEF			(1 << 0)
 #define RXQCR_CMD_CNTL                	(RXQCR_RXFCTE|RXQCR_ADRFE)
 
 #define KS_TXFDPR			0x84
@@ -210,130 +73,14 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
 #define KS_RXFDPR			0x86
 #define RXFDPR_RXFPAI			(1 << 14)
 
-#define KS_RXDTTR			0x8C
-#define KS_RXDBCTR			0x8E
-
-#define KS_IER				0x90
-#define KS_ISR				0x92
-#define IRQ_LCI				(1 << 15)
-#define IRQ_TXI				(1 << 14)
-#define IRQ_RXI				(1 << 13)
-#define IRQ_RXOI			(1 << 11)
-#define IRQ_TXPSI			(1 << 9)
-#define IRQ_RXPSI			(1 << 8)
-#define IRQ_TXSAI			(1 << 6)
-#define IRQ_RXWFDI			(1 << 5)
-#define IRQ_RXMPDI			(1 << 4)
-#define IRQ_LDI				(1 << 3)
-#define IRQ_EDI				(1 << 2)
-#define IRQ_SPIBEI			(1 << 1)
-#define IRQ_DEDI			(1 << 0)
-
-#define KS_RXFCTR			0x9C
 #define RXFCTR_THRESHOLD_MASK     	0x00FF
 
-#define KS_RXFC				0x9D
-#define RXFCTR_RXFC_MASK		(0xff << 8)
-#define RXFCTR_RXFC_SHIFT		(8)
-#define RXFCTR_RXFC_GET(_v)		(((_v) >> 8) & 0xff)
-#define RXFCTR_RXFCT_MASK		(0xff << 0)
-#define RXFCTR_RXFCT_SHIFT		(0)
-
-#define KS_TXNTFSR			0x9E
-
-#define KS_MAHTR0			0xA0
-#define KS_MAHTR1			0xA2
-#define KS_MAHTR2			0xA4
-#define KS_MAHTR3			0xA6
-
-#define KS_FCLWR			0xB0
-#define KS_FCHWR			0xB2
-#define KS_FCOWR			0xB4
-
-#define KS_CIDER			0xC0
-#define CIDER_ID			0x8870
-#define CIDER_REV_MASK			(0x7 << 1)
-#define CIDER_REV_SHIFT			(1)
-#define CIDER_REV_GET(_v)		(((_v) >> 1) & 0x7)
-
-#define KS_CGCR				0xC6
-#define KS_IACR				0xC8
-#define IACR_RDEN			(1 << 12)
-#define IACR_TSEL_MASK			(0x3 << 10)
-#define IACR_TSEL_SHIFT			(10)
-#define IACR_TSEL_MIB			(0x3 << 10)
-#define IACR_ADDR_MASK			(0x1f << 0)
-#define IACR_ADDR_SHIFT			(0)
-
-#define KS_IADLR			0xD0
-#define KS_IAHDR			0xD2
-
-#define KS_PMECR			0xD4
-#define PMECR_PME_DELAY			(1 << 14)
-#define PMECR_PME_POL			(1 << 12)
-#define PMECR_WOL_WAKEUP		(1 << 11)
-#define PMECR_WOL_MAGICPKT		(1 << 10)
-#define PMECR_WOL_LINKUP		(1 << 9)
-#define PMECR_WOL_ENERGY		(1 << 8)
-#define PMECR_AUTO_WAKE_EN		(1 << 7)
-#define PMECR_WAKEUP_NORMAL		(1 << 6)
-#define PMECR_WKEVT_MASK		(0xf << 2)
-#define PMECR_WKEVT_SHIFT		(2)
-#define PMECR_WKEVT_GET(_v)		(((_v) >> 2) & 0xf)
-#define PMECR_WKEVT_ENERGY		(0x1 << 2)
-#define PMECR_WKEVT_LINK		(0x2 << 2)
-#define PMECR_WKEVT_MAGICPKT		(0x4 << 2)
-#define PMECR_WKEVT_FRAME		(0x8 << 2)
-#define PMECR_PM_MASK			(0x3 << 0)
-#define PMECR_PM_SHIFT			(0)
-#define PMECR_PM_NORMAL			(0x0 << 0)
-#define PMECR_PM_ENERGY			(0x1 << 0)
-#define PMECR_PM_SOFTDOWN		(0x2 << 0)
-#define PMECR_PM_POWERSAVE		(0x3 << 0)
-
-/* Standard MII PHY data */
-#define KS_P1MBCR			0xE4
 #define P1MBCR_FORCE_FDX		(1 << 8)
 
-#define KS_P1MBSR			0xE6
 #define P1MBSR_AN_COMPLETE		(1 << 5)
 #define P1MBSR_AN_CAPABLE		(1 << 3)
 #define P1MBSR_LINK_UP			(1 << 2)
 
-#define KS_PHY1ILR			0xE8
-#define KS_PHY1IHR			0xEA
-#define KS_P1ANAR			0xEC
-#define KS_P1ANLPR			0xEE
-
-#define KS_P1SCLMD			0xF4
-#define P1SCLMD_LEDOFF			(1 << 15)
-#define P1SCLMD_TXIDS			(1 << 14)
-#define P1SCLMD_RESTARTAN		(1 << 13)
-#define P1SCLMD_DISAUTOMDIX		(1 << 10)
-#define P1SCLMD_FORCEMDIX		(1 << 9)
-#define P1SCLMD_AUTONEGEN		(1 << 7)
-#define P1SCLMD_FORCE100		(1 << 6)
-#define P1SCLMD_FORCEFDX		(1 << 5)
-#define P1SCLMD_ADV_FLOW		(1 << 4)
-#define P1SCLMD_ADV_100BT_FDX		(1 << 3)
-#define P1SCLMD_ADV_100BT_HDX		(1 << 2)
-#define P1SCLMD_ADV_10BT_FDX		(1 << 1)
-#define P1SCLMD_ADV_10BT_HDX		(1 << 0)
-
-#define KS_P1CR				0xF6
-#define P1CR_HP_MDIX			(1 << 15)
-#define P1CR_REV_POL			(1 << 13)
-#define P1CR_OP_100M			(1 << 10)
-#define P1CR_OP_FDX			(1 << 9)
-#define P1CR_OP_MDI			(1 << 7)
-#define P1CR_AN_DONE			(1 << 6)
-#define P1CR_LINK_GOOD			(1 << 5)
-#define P1CR_PNTR_FLOW			(1 << 4)
-#define P1CR_PNTR_100BT_FDX		(1 << 3)
-#define P1CR_PNTR_100BT_HDX		(1 << 2)
-#define P1CR_PNTR_10BT_FDX		(1 << 1)
-#define P1CR_PNTR_10BT_HDX		(1 << 0)
-
 /* TX Frame control */
 
 #define TXFR_TXIC			(1 << 15)


^ permalink raw reply

* [patch 04/13] eeprom_93cx6: Add write support
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Wolfram Sang, Jean Delvare, Linux Kernel
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: 93c-eeprom-add-write.patch --]
[-- Type: text/plain, Size: 3857 bytes --]

Add support for writing data to EEPROM.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>
Cc: Wolfram Sang <w.sang@pengutronix.de>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Linux Kernel <linux-kernel@vger.kernel.org>

---
 drivers/misc/eeprom/eeprom_93cx6.c |   86 +++++++++++++++++++++++++++++++++++++
 include/linux/eeprom_93cx6.h       |    7 +++
 2 files changed, 93 insertions(+)

Index: b/drivers/misc/eeprom/eeprom_93cx6.c
===================================================================
--- a/drivers/misc/eeprom/eeprom_93cx6.c	2009-10-06 15:51:18.000000000 +0100
+++ b/drivers/misc/eeprom/eeprom_93cx6.c	2009-10-06 15:54:36.000000000 +0100
@@ -241,3 +241,89 @@ void eeprom_93cx6_multiread(struct eepro
 }
 EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
 
+
+/**
+ * eeprom_93cx6_wren - set the write enable state
+ * @eeprom: Pointer to eeprom structure
+ * @enable: true to enable writes, otherwise disable writes
+ *
+ * Set the EEPROM write enable state to either allow or deny
+ * writes depending on the @enable value.
+ */
+void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable)
+{
+	u16 command;
+
+	/* start the command */
+	eeprom_93cx6_startup(eeprom);
+
+	/* create command to enable/disable */
+
+	command = enable ? PCI_EEPROM_EWEN_OPCODE : PCI_EEPROM_EWDS_OPCODE;
+	command <<= (eeprom->width - 2);
+
+	eeprom_93cx6_write_bits(eeprom, command,
+				PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+	eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_wren);
+
+/**
+ * eeprom_93cx6_write - write data to the EEPROM
+ * @eeprom: Pointer to eeprom structure
+ * @addr: Address to write data to.
+ * @data: The data to write to address @addr.
+ *
+ * Write the @data to the specified @addr in the EEPROM and
+ * waiting for the device to finish writing.
+ *
+ * Note, since we do not expect large number of write operations
+ * we use msleep() to delay in between parts of the operation to
+ * avoid using excessive amounts of CPU time busy waiting.
+ */
+void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, u8 addr, u16 data)
+{
+	int timeout = 100;
+	u16 command;
+
+	/* start the command */
+	eeprom_93cx6_startup(eeprom);
+
+	command = PCI_EEPROM_WRITE_OPCODE << eeprom->width;
+	command |= addr;
+
+	/* send write command */
+	eeprom_93cx6_write_bits(eeprom, command,
+				PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+	/* send data */
+	eeprom_93cx6_write_bits(eeprom, data, 16);
+
+	/* get ready to check for busy */
+	eeprom->drive_data = 0;
+	eeprom->reg_chip_select = 1;
+	eeprom->register_write(eeprom);
+
+	/* wait at-least 250ns to get DO to be the busy signal */
+	msleep(1);
+
+	/* wait for DO to go high to signify finish */
+
+	while (true) {
+		eeprom->register_read(eeprom);
+
+		if (eeprom->reg_data_out)
+			break;
+
+		msleep(1);
+
+		if (--timeout <= 0) {
+			printk(KERN_ERR "%s: timeout\n", __func__);
+			break;
+		}			
+	}
+
+	eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_write);
Index: b/include/linux/eeprom_93cx6.h
===================================================================
--- a/include/linux/eeprom_93cx6.h	2009-10-06 15:51:18.000000000 +0100
+++ b/include/linux/eeprom_93cx6.h	2009-10-06 15:53:16.000000000 +0100
@@ -32,6 +32,7 @@
 #define PCI_EEPROM_WIDTH_93C66	8
 #define PCI_EEPROM_WIDTH_OPCODE	3
 #define PCI_EEPROM_WRITE_OPCODE	0x05
+#define PCI_EEPROM_ERASE_OPCODE 0x07
 #define PCI_EEPROM_READ_OPCODE	0x06
 #define PCI_EEPROM_EWDS_OPCODE	0x10
 #define PCI_EEPROM_EWEN_OPCODE	0x13
@@ -73,3 +74,9 @@ extern void eeprom_93cx6_read(struct eep
 	const u8 word, u16 *data);
 extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
 	const u8 word, __le16 *data, const u16 words);
+
+extern void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable);
+
+extern void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom,
+			       u8 addr, u16 data);
+


^ permalink raw reply

* [patch 01/13] KS8851: Fix ks8851 snl transmit problem
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support, Tristram Ha
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: thirdparty/micrel/ks8851-tx-fix.patch --]
[-- Type: text/plain, Size: 3873 bytes --]

From: Tristram Ha <Tristram.Ha@micrel.com>

This fixes a transmit problem of the ks8851 snl network driver.

Under heavy TCP traffic the device will stop transmitting. Turning off
the transmit interrupt avoids this issue.  A new workqueue was
implemented to replace the functionality of the transmit interrupt processing.

Signed-off-by: Tristram Ha <Tristram.Ha@micrel.com>

---
---
 drivers/net/ks8851.c |   38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-20 18:13:58.000000000 +0100
+++ b/drivers/net/ks8851.c	2010-04-20 18:38:18.000000000 +0100
@@ -111,11 +111,13 @@ struct ks8851_net {
 	struct mii_if_info	mii;
 	struct ks8851_rxctrl	rxctrl;
 
+	struct work_struct	tx_check;
 	struct work_struct	tx_work;
 	struct work_struct	irq_work;
 	struct work_struct	rxctrl_work;
 
 	struct sk_buff_head	txq;
+	int			tx_len;
 
 	struct spi_message	spi_msg1;
 	struct spi_message	spi_msg2;
@@ -573,19 +575,6 @@ static void ks8851_irq_work(struct work_
 	if (status & IRQ_RXPSI)
 		handled |= IRQ_RXPSI;
 
-	if (status & IRQ_TXI) {
-		handled |= IRQ_TXI;
-
-		/* no lock here, tx queue should have been stopped */
-
-		/* update our idea of how much tx space is available to the
-		 * system */
-		ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
-
-		if (netif_msg_intr(ks))
-			ks_dbg(ks, "%s: txspace %d\n", __func__, ks->tx_space);
-	}
-
 	if (status & IRQ_RXI)
 		handled |= IRQ_RXI;
 
@@ -623,9 +612,6 @@ static void ks8851_irq_work(struct work_
 
 	mutex_unlock(&ks->lock);
 
-	if (status & IRQ_TXI)
-		netif_wake_queue(ks->netdev);
-
 	enable_irq(ks->netdev->irq);
 }
 
@@ -703,6 +689,17 @@ static void ks8851_done_tx(struct ks8851
 	dev_kfree_skb(txb);
 }
 
+static void ks8851_tx_check(struct work_struct *work)
+{
+	struct ks8851_net *ks = container_of(work, struct ks8851_net, tx_check);
+
+	ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
+	if (ks->tx_space > ks->tx_len)
+		netif_wake_queue(ks->netdev);
+	else
+		schedule_work(&ks->tx_check);
+}
+
 /**
  * ks8851_tx_work - process tx packet(s)
  * @work: The work strucutre what was scheduled.
@@ -814,7 +811,6 @@ static int ks8851_net_open(struct net_de
 	/* clear then enable interrupts */
 
 #define STD_IRQ (IRQ_LCI |	/* Link Change */	\
-		 IRQ_TXI |	/* TX done */		\
 		 IRQ_RXI |	/* RX done */		\
 		 IRQ_SPIBEI |	/* SPI bus error */	\
 		 IRQ_TXPSI |	/* TX process stop */	\
@@ -830,6 +826,7 @@ static int ks8851_net_open(struct net_de
 		ks_dbg(ks, "network device %s up\n", dev->name);
 
 	mutex_unlock(&ks->lock);
+	ks8851_write_mac_addr(dev);
 	return 0;
 }
 
@@ -854,6 +851,7 @@ static int ks8851_net_stop(struct net_de
 
 	/* stop any outstanding work */
 	flush_work(&ks->irq_work);
+	flush_work(&ks->tx_check);
 	flush_work(&ks->tx_work);
 	flush_work(&ks->rxctrl_work);
 
@@ -912,14 +910,16 @@ static netdev_tx_t ks8851_start_xmit(str
 
 	if (needed > ks->tx_space) {
 		netif_stop_queue(dev);
+		ks->tx_len = needed;
+		schedule_work(&ks->tx_check);
 		ret = NETDEV_TX_BUSY;
 	} else {
 		ks->tx_space -= needed;
 		skb_queue_tail(&ks->txq, skb);
+		schedule_work(&ks->tx_work);
 	}
 
 	spin_unlock(&ks->statelock);
-	schedule_work(&ks->tx_work);
 
 	return ret;
 }
@@ -1227,6 +1227,7 @@ static int __devinit ks8851_probe(struct
 	mutex_init(&ks->lock);
 	spin_lock_init(&ks->statelock);
 
+	INIT_WORK(&ks->tx_check, ks8851_tx_check);
 	INIT_WORK(&ks->tx_work, ks8851_tx_work);
 	INIT_WORK(&ks->irq_work, ks8851_irq_work);
 	INIT_WORK(&ks->rxctrl_work, ks8851_rxctrl_work);
@@ -1279,6 +1280,7 @@ static int __devinit ks8851_probe(struct
 
 	ks8851_read_selftest(ks);
 	ks8851_init_mac(ks);
+	ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
 
 	ret = request_irq(spi->irq, ks8851_irq, IRQF_TRIGGER_LOW,
 			  ndev->name, ks);


^ permalink raw reply

* [patch 12/13] KS8851: Use the ks8851.h header to hold union ks8851_tx_hdr
From: Ben Dooks @ 2010-04-29 23:16 UTC (permalink / raw)
  To: netdev; +Cc: tristram.ha, support
In-Reply-To: <20100429231621.015936077@fluff.org.uk>

[-- Attachment #1: ks8851-reduce-header-duplication3.patch --]
[-- Type: text/plain, Size: 3035 bytes --]

The union ks8851_tx_hdr turns up in both ks8851.c and ks8851_mll.c in two
different formats, thus making a common version in ks8851.h is going to
save source file usage.

The ks8851_mll.c uses the name ks_tx_hdr instead of ks8851_tx_hdr, so
rename this instance.

Signed-off-by: Ben Dooks <ben@simtec.co.uk>

---

---
 drivers/net/ks8851.c     |   13 -------------
 drivers/net/ks8851.h     |   14 ++++++++++++++
 drivers/net/ks8851_mll.c |   16 +---------------
 3 files changed, 15 insertions(+), 28 deletions(-)

Index: b/drivers/net/ks8851.c
===================================================================
--- a/drivers/net/ks8851.c	2010-04-29 01:25:54.217027162 +0900
+++ b/drivers/net/ks8851.c	2010-04-29 01:28:32.719525804 +0900
@@ -46,19 +46,6 @@ struct ks8851_rxctrl {
 	u16	rxcr2;
 };
 
-/**
- * union ks8851_tx_hdr - tx header data
- * @txb: The header as bytes
- * @txw: The header as 16bit, little-endian words
- *
- * A dual representation of the tx header data to allow
- * access to individual bytes, and to allow 16bit accesses
- * with 16bit alignment.
- */
-union ks8851_tx_hdr {
-	u8	txb[6];
-	__le16	txw[3];
-};
 
 /**
  * struct ks8851_net - KS8851 driver private data
Index: b/drivers/net/ks8851.h
===================================================================
--- a/drivers/net/ks8851.h	2010-04-29 01:26:03.329527219 +0900
+++ b/drivers/net/ks8851.h	2010-04-29 01:26:04.169526711 +0900
@@ -323,3 +323,17 @@
 #define KS_SPIOP_WR				(0x40)
 #define KS_SPIOP_RXFIFO				(0x80)
 #define KS_SPIOP_TXFIFO				(0xC0)
+
+/**
+ * union ks8851_tx_hdr - tx header data
+ * @txb: The header as bytes
+ * @txw: The header as 16bit, little-endian words
+ *
+ * A dual representation of the tx header data to allow
+ * access to individual bytes, and to allow 16bit accesses
+ * with 16bit alignment.
+ */
+union ks8851_tx_hdr {
+	u8	txb[6];
+	__le16	txw[3];
+};
Index: b/drivers/net/ks8851_mll.c
===================================================================
--- a/drivers/net/ks8851_mll.c	2010-04-29 01:26:03.329527219 +0900
+++ b/drivers/net/ks8851_mll.c	2010-04-29 01:26:04.169526711 +0900
@@ -73,20 +73,6 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0
 #define MAC_ADDR_LEN			6
 
 /**
- * union ks_tx_hdr - tx header data
- * @txb: The header as bytes
- * @txw: The header as 16bit, little-endian words
- *
- * A dual representation of the tx header data to allow
- * access to individual bytes, and to allow 16bit accesses
- * with 16bit alignment.
- */
-union ks_tx_hdr {
-	u8      txb[4];
-	__le16  txw[2];
-};
-
-/**
  * struct ks_net - KS8851 driver private data
  * @net_device 	: The network device we're bound to
  * @hw_addr	: start address of data register.
@@ -138,7 +124,7 @@ struct ks_net {
 	struct net_device	*netdev;
 	void __iomem    	*hw_addr;
 	void __iomem    	*hw_addr_cmd;
-	union ks_tx_hdr		txh ____cacheline_aligned;
+	union ks8851_tx_hdr	txh ____cacheline_aligned;
 	struct mutex      	lock; /* spinlock to be interrupt safe */
 	struct platform_device *pdev;
 	struct mii_if_info	mii;


^ permalink raw reply

* Re: [PATCH linux-next v4 2/2] ixgbe: Example usage of the new IRQ affinity_hint callback
From: Peter P Waskiewicz Jr @ 2010-04-30 21:51 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: davem@davemloft.net, arjan@linux.jf.intel.com,
	bhutchings@solarflare.com, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <alpine.LFD.2.00.1004302346030.2951@localhost.localdomain>

On Fri, 30 Apr 2010, Thomas Gleixner wrote:

> On Fri, 30 Apr 2010, Peter P Waskiewicz Jr wrote:
>> +	for (i = 0; i < num_q_vectors; i++) {
>> +		struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
>> +		/* release the CPU mask memory */
>> +		free_cpumask_var(q_vector->affinity_mask);
>> +		/* clear the affinity_mask in the IRQ descriptor */
>> +		irq_set_affinity_hint(adapter->msix_entries[i].vector, NULL);
>
> Freeing the mask _AFTER_ clearing the hint might be a worthwhile
> exercise :)

Crap.  I had it reversed before, then when I dropped the unregister call 
it got swapped.  I'll fix it on the official submission for this one.

This patch is just an example patch, not to be merged just now.  Once the 
IRQ side is merged, and DaveM has that pulled into a tree, I'll send an 
official ixgbe patch using the API.  But I'll be sure to have this fixed 
before sending. :-)

-PJ

^ permalink raw reply

* Re: ixgbe and mac-vlans problem
From: Ben Greear @ 2010-04-30 22:04 UTC (permalink / raw)
  To: Tantilov, Emil S; +Cc: Arnd Bergmann, NetDev, Patrick McHardy
In-Reply-To: <EA929A9653AAE14F841771FB1DE5A1365FE55609F0@rrsmsx501.amr.corp.intel.com>

On 04/30/2010 02:13 PM, Tantilov, Emil S wrote:

>> I will double-check the NIC chipset on the system that showed the
>> problem yesterday.
>
> I ran a quick test in my setup with 82599 and was able to pass traffic
> on all 50 mac-vlans without issues. This is on net-next.

I attempted this on an 82598 system, and it reproduces the problem
for me, so I think that must be what the customer was using as well
(I haven't gotten access to their system again, yet)

I created 50 mac-vlans on eth11, but it does NOT go PROMISC
mode as far as I can tell.  Only 14 of the mac-vlans are
working.  I'm using 64kbps UDP streams, 1k packets (ie, light load).

[root@i7-1qc-1 lanforge]# cat /sys/class/net/eth11/flags
0x1003

[root@i7-1qc-1 lanforge]# ip link show dev eth11
2: eth11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
     link/ether 00:e0:ed:11:25:12 brd ff:ff:ff:ff:ff:ff

I put it into promisc mode and now they all work:

[root@i7-1qc-1 lanforge]# ip link show dev eth11
2: eth11: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
     link/ether 00:e0:ed:11:25:12 brd ff:ff:ff:ff:ff:ff
[root@i7-1qc-1 lanforge]# cat /sys/class/net/eth11/flags
0x1103


This is on a slightly modified 2.6.31.12 kernel.  I haven't had a chance to try
this on a more recent kernel yet.

lspci:
03:00.0 Ethernet controller: Intel Corporation 82598EB 10 Gigabit AF Dual Port Network Connection (rev 01)
03:00.1 Ethernet controller: Intel Corporation 82598EB 10 Gigabit AF Dual Port Network Connection

Please let me know if I can offer any additional information.  It will probably take a few days before I can
get the .34 kernel in testing.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Re: [RFC] BPF program access to transport header
From: Paul LeoNerd Evans @ 2010-04-30 22:10 UTC (permalink / raw)
  To: Patrick McHardy, netdev
In-Reply-To: <4BDB3A4D.5020507@trash.net>

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

On Fri, Apr 30, 2010 at 10:15:09PM +0200, Patrick McHardy wrote:
> > I forsee a number of issues with trying to provide this:
> > 
> >  * How to provide the protocol number (e.g. 6 for TCP, 1 for ICMP) to
> >    the BPF program
> 
> Using one of the registers?

Using, how? What operation would put the numbers in there in the first
place?

I was thinking more of simply providing an ancilliary data area field,
similar to SKF_AD_PROTO and SKF_AD_HATYPE, following along the same
idea.

  LD WORD[SKF_AD_TRANSPROTO]

would then load the A register with the transport protocol number.

> >  * How to obtain the transport offset - AIUI, the skf_transport_offset()
> >    won't actually be set yet by the time the filter program runs.
> 
> For IPv4 its trivial. For IPv6 you could use ipv6_skip_exthdr().
> A slightly more flexible way would be to use something like the
> netfilter ipv6_find_hdr() function to get the offset of any header
> type. The protocol number could be returned in one of the registers
> (the other one would contain the offset).

I sortof meant in general. I really don't think trying to add
IPv4/IPv6-specific code into net/core/filter.c is going to go down well.

On the other hand, I observe from casual experimentation, that on
receipt of a TCP packet in IPv4 over ethernet, the offets are:

  mac=0 network=14 transport=14

This suggests more work needing to be done somewhere, because I'd expect
for an Ethernet/IPv4/TCP packet to get

  mac=0 network=14 transport=34

> >  * What to do if the underlying protocol doesn't support a transport
> >    layer above it - e.g. ARP.
> 
> I'd say simply abort the filter.

That sounds reasonable.

Another question occurs:

 * How to obtain the transport protocol number? I can easily provide it
   in the AD area; say as SKF_AD_TRANSPROTO; but how can
   net/core/filter.c know the value?

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/

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

^ permalink raw reply

* Re: possible off by one error in drivers/isdn/divert/divert_procfs.c
From: Karsten Keil @ 2010-04-30 22:12 UTC (permalink / raw)
  To: d binderman; +Cc: netdev
In-Reply-To: <BLU108-W15F33D55974CB43800BEB59C000@phx.gbl>

On Freitag, 30. April 2010 23:15:17 d binderman wrote:
> Hello there,
> 
> I've just been looking at the Linux kernel linux-2.6.34-rc6.  I notice the
> source code in file drivers/isdn/divert/divert_procfs.c, around line 50 is
> 
>         if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp),
>  GFP_ATOMIC))) return;        /* no memory */
>         strcpy(ib->info_start, cp);     /* set output string */
> 
> 
> Shouldn't that be
> 
>         if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp) + 1,
>  GFP_ATOMIC))) return;        /* no memory */
>         strcpy(ib->info_start, cp);     /* set output string */
> 
> +1 for the zero byte ?
> 

No the struct divert_info already add 2 bytes as size of the info_start field.

So in real it has one byte more as needed.

Same think with the code in drivers/isdn/divert/divert_procfs.c

Karsten

^ permalink raw reply

* Re: [PATCH]PM QOS refresh against next-20100430
From: Rafael J. Wysocki @ 2010-04-30 22:13 UTC (permalink / raw)
  To: mgross
  Cc: Kevin Hilman, aili, dwalker, tiwai, bruce.w.allan, davidb, mcgrof,
	pavel, linux-pm, lkml, NetDev, Johannes Berg,
	ACPI Devel Maling List, Len Brown, John W. Linville
In-Reply-To: <20100430212043.GA30315@linux.intel.com>

On Friday 30 April 2010, mark gross wrote:
> The following is a refresh of the PM_QOS implementation, this patch
> updates some documentation input I got from Randy.
> 
> This patch changes the string based list management to a handle base
> implementation to help with the hot path use of pm-qos, it also renames
> much of the API to use "request" as opposed to "requirement" that was
> used in the initial implementation.  I did this because request more
> accurately represents what it actually does.
> 
> Also, I added a string based ABI for users wanting to use a string
> interface.  So if the user writes 0xDDDDDDDD formatted hex it will be
> accepted by the interface.  (someone asked me for it and I don't think
> it hurts anything.)
> 
> I really would like to get this refresh taken care of.  Its been taking
> me too long to close this.  please review or include it in next.
> 
> Thanks!

Well, I'd take it to suspend-2.6/linux-next, but first, it touches
subsystems whose maintainers were not in the Cc list, like the network
drivers, wireless and ACPI.  The changes are trivial, so I hope they don't
mind.

Second, my tree is based on the Linus' tree rather than linux-next and
the change in net/mac80211/scan.c doesn't seem to match that.  Please tell me
what I'm supposed to do about that.

Thanks,
Rafael

 
> Ooops! forgot the signed off by line!
> 
> Signed-off-by: mark gross <mgross@linux.intel.com>
> 
> From c45d8d86f89ac55fbb9a499fbc754e35258bf818 Mon Sep 17 00:00:00 2001
> From: mgross <mark.gross@gmail.com>
> Date: Sat, 13 Mar 2010 08:18:36 -0800
> Subject: [PATCH 1/2] PM_QOS to use handle based list implementation and exported function name changes to be more descriptive of what is actually happening.
> 
> ---
>  Documentation/power/pm_qos_interface.txt |   48 ++++---
>  drivers/acpi/processor_idle.c            |    2 +-
>  drivers/cpuidle/governors/ladder.c       |    2 +-
>  drivers/cpuidle/governors/menu.c         |    2 +-
>  drivers/net/e1000e/netdev.c              |   22 ++--
>  drivers/net/igbvf/netdev.c               |    6 +-
>  drivers/net/wireless/ipw2x00/ipw2100.c   |   11 +-
>  include/linux/netdevice.h                |    4 +
>  include/linux/pm_qos_params.h            |   14 +-
>  include/sound/pcm.h                      |    3 +-
>  kernel/pm_qos_params.c                   |  214 ++++++++++++++---------------
>  net/mac80211/mlme.c                      |    2 +-
>  net/mac80211/scan.c                      |    2 +-
>  sound/core/pcm.c                         |    3 -
>  sound/core/pcm_native.c                  |   14 +-
>  15 files changed, 177 insertions(+), 172 deletions(-)
> 
> diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
> index c40866e..bfed898 100644
> --- a/Documentation/power/pm_qos_interface.txt
> +++ b/Documentation/power/pm_qos_interface.txt
> @@ -18,44 +18,46 @@ and pm_qos_params.h.  This is done because having the available parameters
>  being runtime configurable or changeable from a driver was seen as too easy to
>  abuse.
>  
> -For each parameter a list of performance requirements is maintained along with
> +For each parameter a list of performance requests is maintained along with
>  an aggregated target value.  The aggregated target value is updated with
> -changes to the requirement list or elements of the list.  Typically the
> -aggregated target value is simply the max or min of the requirement values held
> +changes to the request list or elements of the list.  Typically the
> +aggregated target value is simply the max or min of the request values held
>  in the parameter list elements.
>  
>  From kernel mode the use of this interface is simple:
> -pm_qos_add_requirement(param_id, name, target_value):
> -Will insert a named element in the list for that identified PM_QOS parameter
> -with the target value.  Upon change to this list the new target is recomputed
> -and any registered notifiers are called only if the target value is now
> -different.
>  
> -pm_qos_update_requirement(param_id, name, new_target_value):
> -Will search the list identified by the param_id for the named list element and
> -then update its target value, calling the notification tree if the aggregated
> -target is changed.  with that name is already registered.
> +handle = pm_qos_add_request(param_class, target_value):
> +Will insert an element into the list for that identified PM_QOS class with the
> +target value.  Upon change to this list the new target is recomputed and any
> +registered notifiers are called only if the target value is now different.
> +Clients of pm_qos need to save the returned handle.
>  
> -pm_qos_remove_requirement(param_id, name):
> -Will search the identified list for the named element and remove it, after
> -removal it will update the aggregate target and call the notification tree if
> -the target was changed as a result of removing the named requirement.
> +void pm_qos_update_request(handle, new_target_value):
> +Will update the list element pointed to by the handle with the new target value
> +and recompute the new aggregated target, calling the notification tree if the
> +target is changed.
> +
> +void pm_qos_remove_request(handle):
> +Will remove the element.  After removal it will update the aggregate target and
> +call the notification tree if the target was changed as a result of removing
> +the request.
>  
>  
>  From user mode:
> -Only processes can register a pm_qos requirement.  To provide for automatic
> -cleanup for process the interface requires the process to register its
> -parameter requirements in the following way:
> +Only processes can register a pm_qos request.  To provide for automatic
> +cleanup of a process, the interface requires the process to register its
> +parameter requests in the following way:
>  
>  To register the default pm_qos target for the specific parameter, the process
>  must open one of /dev/[cpu_dma_latency, network_latency, network_throughput]
>  
>  As long as the device node is held open that process has a registered
> -requirement on the parameter.  The name of the requirement is "process_<PID>"
> -derived from the current->pid from within the open system call.
> +request on the parameter.
>  
> -To change the requested target value the process needs to write a s32 value to
> -the open device node.  This translates to a pm_qos_update_requirement call.
> +To change the requested target value the process needs to write an s32 value to
> +the open device node.  Alternatively the user mode program could write a hex
> +string for the value using 10 char long format e.g. "0x12345678".  This
> +translates to a pm_qos_update_request call.
>  
>  To remove the user mode request for a target value simply close the device
>  node.
> diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
> index 5939e7f..c3817e1 100644
> --- a/drivers/acpi/processor_idle.c
> +++ b/drivers/acpi/processor_idle.c
> @@ -698,7 +698,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
>  		   "max_cstate:              C%d\n"
>  		   "maximum allowed latency: %d usec\n",
>  		   pr->power.state ? pr->power.state - pr->power.states : 0,
> -		   max_cstate, pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY));
> +		   max_cstate, pm_qos_request(PM_QOS_CPU_DMA_LATENCY));
>  
>  	seq_puts(seq, "states:\n");
>  
> diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
> index 1c1ceb4..12c9890 100644
> --- a/drivers/cpuidle/governors/ladder.c
> +++ b/drivers/cpuidle/governors/ladder.c
> @@ -67,7 +67,7 @@ static int ladder_select_state(struct cpuidle_device *dev)
>  	struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
>  	struct ladder_device_state *last_state;
>  	int last_residency, last_idx = ldev->last_state_idx;
> -	int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY);
> +	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>  
>  	/* Special case when user has set very strict latency requirement */
>  	if (unlikely(latency_req == 0)) {
> diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
> index 1aea715..61ca939 100644
> --- a/drivers/cpuidle/governors/menu.c
> +++ b/drivers/cpuidle/governors/menu.c
> @@ -183,7 +183,7 @@ static u64 div_round64(u64 dividend, u32 divisor)
>  static int menu_select(struct cpuidle_device *dev)
>  {
>  	struct menu_device *data = &__get_cpu_var(menu_devices);
> -	int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY);
> +	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>  	int i;
>  	int multiplier;
>  
> diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
> index 904bd6b..7550879 100644
> --- a/drivers/net/e1000e/netdev.c
> +++ b/drivers/net/e1000e/netdev.c
> @@ -2882,12 +2882,12 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
>  			 * excessive C-state transition latencies result in
>  			 * dropped transactions.
>  			 */
> -			pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
> -						  adapter->netdev->name, 55);
> +			pm_qos_update_request(
> +				adapter->netdev->pm_qos_req, 55);
>  		} else {
> -			pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY,
> -						  adapter->netdev->name,
> -						  PM_QOS_DEFAULT_VALUE);
> +			pm_qos_update_request(
> +				adapter->netdev->pm_qos_req,
> +				PM_QOS_DEFAULT_VALUE);
>  		}
>  	}
>  
> @@ -3181,8 +3181,8 @@ int e1000e_up(struct e1000_adapter *adapter)
>  
>  	/* DMA latency requirement to workaround early-receive/jumbo issue */
>  	if (adapter->flags & FLAG_HAS_ERT)
> -		pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
> -		                       adapter->netdev->name,
> +		adapter->netdev->pm_qos_req =
> +			pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
>  				       PM_QOS_DEFAULT_VALUE);
>  
>  	/* hardware has been reset, we need to reload some things */
> @@ -3244,9 +3244,11 @@ void e1000e_down(struct e1000_adapter *adapter)
>  	e1000_clean_tx_ring(adapter);
>  	e1000_clean_rx_ring(adapter);
>  
> -	if (adapter->flags & FLAG_HAS_ERT)
> -		pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
> -		                          adapter->netdev->name);
> +	if (adapter->flags & FLAG_HAS_ERT) {
> +		pm_qos_remove_request(
> +			      adapter->netdev->pm_qos_req);
> +		adapter->netdev->pm_qos_req = NULL;
> +	}
>  
>  	/*
>  	 * TODO: for power management, we could drop the link and
> diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
> index 7012e3d..5e2b2a8 100644
> --- a/drivers/net/igbvf/netdev.c
> +++ b/drivers/net/igbvf/netdev.c
> @@ -48,6 +48,7 @@
>  #define DRV_VERSION "1.0.0-k0"
>  char igbvf_driver_name[] = "igbvf";
>  const char igbvf_driver_version[] = DRV_VERSION;
> +struct pm_qos_request_list *igbvf_driver_pm_qos_req;
>  static const char igbvf_driver_string[] =
>  				"Intel(R) Virtual Function Network Driver";
>  static const char igbvf_copyright[] = "Copyright (c) 2009 Intel Corporation.";
> @@ -2901,7 +2902,7 @@ static int __init igbvf_init_module(void)
>  	printk(KERN_INFO "%s\n", igbvf_copyright);
>  
>  	ret = pci_register_driver(&igbvf_driver);
> -	pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name,
> +	igbvf_driver_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
>  	                       PM_QOS_DEFAULT_VALUE);
>  
>  	return ret;
> @@ -2917,7 +2918,8 @@ module_init(igbvf_init_module);
>  static void __exit igbvf_exit_module(void)
>  {
>  	pci_unregister_driver(&igbvf_driver);
> -	pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, igbvf_driver_name);
> +	pm_qos_remove_request(igbvf_driver_pm_qos_req);
> +	igbvf_driver_pm_qos_req = NULL;
>  }
>  module_exit(igbvf_exit_module);
>  
> diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
> index 2088ac0..7040e3b 100644
> --- a/drivers/net/wireless/ipw2x00/ipw2100.c
> +++ b/drivers/net/wireless/ipw2x00/ipw2100.c
> @@ -174,6 +174,8 @@ that only one external action is invoked at a time.
>  #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
>  #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
>  
> +struct pm_qos_request_list *ipw2100_pm_qos_req;
> +
>  /* Debugging stuff */
>  #ifdef CONFIG_IPW2100_DEBUG
>  #define IPW2100_RX_DEBUG	/* Reception debugging */
> @@ -1739,7 +1741,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
>  	/* the ipw2100 hardware really doesn't want power management delays
>  	 * longer than 175usec
>  	 */
> -	pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100", 175);
> +	pm_qos_update_request(ipw2100_pm_qos_req, 175);
>  
>  	/* If the interrupt is enabled, turn it off... */
>  	spin_lock_irqsave(&priv->low_lock, flags);
> @@ -1887,8 +1889,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
>  	ipw2100_disable_interrupts(priv);
>  	spin_unlock_irqrestore(&priv->low_lock, flags);
>  
> -	pm_qos_update_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
> -			PM_QOS_DEFAULT_VALUE);
> +	pm_qos_update_request(ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
>  
>  	/* We have to signal any supplicant if we are disassociating */
>  	if (associated)
> @@ -6669,7 +6670,7 @@ static int __init ipw2100_init(void)
>  	if (ret)
>  		goto out;
>  
> -	pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100",
> +	ipw2100_pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,
>  			PM_QOS_DEFAULT_VALUE);
>  #ifdef CONFIG_IPW2100_DEBUG
>  	ipw2100_debug_level = debug;
> @@ -6692,7 +6693,7 @@ static void __exit ipw2100_exit(void)
>  			   &driver_attr_debug_level);
>  #endif
>  	pci_unregister_driver(&ipw2100_pci_driver);
> -	pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "ipw2100");
> +	pm_qos_remove_request(ipw2100_pm_qos_req);
>  }
>  
>  module_init(ipw2100_init);
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 40d4c20..5dd6d8c 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -31,6 +31,7 @@
>  #include <linux/if_link.h>
>  
>  #ifdef __KERNEL__
> +#include <linux/pm_qos_params.h>
>  #include <linux/timer.h>
>  #include <linux/delay.h>
>  #include <linux/mm.h>
> @@ -778,6 +779,9 @@ struct net_device {
>  	 * the interface.
>  	 */
>  	char			name[IFNAMSIZ];
> +
> +	struct pm_qos_request_list *pm_qos_req;
> +
>  	/* device name hash chain */
>  	struct hlist_node	name_hlist;
>  	/* snmp alias */
> diff --git a/include/linux/pm_qos_params.h b/include/linux/pm_qos_params.h
> index d74f75e..8ba440e 100644
> --- a/include/linux/pm_qos_params.h
> +++ b/include/linux/pm_qos_params.h
> @@ -14,12 +14,14 @@
>  #define PM_QOS_NUM_CLASSES 4
>  #define PM_QOS_DEFAULT_VALUE -1
>  
> -int pm_qos_add_requirement(int qos, char *name, s32 value);
> -int pm_qos_update_requirement(int qos, char *name, s32 new_value);
> -void pm_qos_remove_requirement(int qos, char *name);
> +struct pm_qos_request_list;
>  
> -int pm_qos_requirement(int qos);
> +struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value);
> +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> +		s32 new_value);
> +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req);
>  
> -int pm_qos_add_notifier(int qos, struct notifier_block *notifier);
> -int pm_qos_remove_notifier(int qos, struct notifier_block *notifier);
> +int pm_qos_request(int pm_qos_class);
> +int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
> +int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
>  
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 8b611a5..dd76cde 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -29,6 +29,7 @@
>  #include <linux/poll.h>
>  #include <linux/mm.h>
>  #include <linux/bitops.h>
> +#include <linux/pm_qos_params.h>
>  
>  #define snd_pcm_substream_chip(substream) ((substream)->private_data)
>  #define snd_pcm_chip(pcm) ((pcm)->private_data)
> @@ -365,7 +366,7 @@ struct snd_pcm_substream {
>  	int number;
>  	char name[32];			/* substream name */
>  	int stream;			/* stream (direction) */
> -	char latency_id[20];		/* latency identifier */
> +	struct pm_qos_request_list *latency_pm_qos_req; /* pm_qos request */
>  	size_t buffer_bytes_max;	/* limit ring buffer size */
>  	struct snd_dma_buffer dma_buffer;
>  	unsigned int dma_buf_id;
> diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
> index 3db49b9..a1aea04 100644
> --- a/kernel/pm_qos_params.c
> +++ b/kernel/pm_qos_params.c
> @@ -2,7 +2,7 @@
>   * This module exposes the interface to kernel space for specifying
>   * QoS dependencies.  It provides infrastructure for registration of:
>   *
> - * Dependents on a QoS value : register requirements
> + * Dependents on a QoS value : register requests
>   * Watchers of QoS value : get notified when target QoS value changes
>   *
>   * This QoS design is best effort based.  Dependents register their QoS needs.
> @@ -14,19 +14,21 @@
>   * timeout: usec <-- currently not used.
>   * throughput: kbs (kilo byte / sec)
>   *
> - * There are lists of pm_qos_objects each one wrapping requirements, notifiers
> + * There are lists of pm_qos_objects each one wrapping requests, notifiers
>   *
> - * User mode requirements on a QOS parameter register themselves to the
> + * User mode requests on a QOS parameter register themselves to the
>   * subsystem by opening the device node /dev/... and writing there request to
>   * the node.  As long as the process holds a file handle open to the node the
>   * client continues to be accounted for.  Upon file release the usermode
> - * requirement is removed and a new qos target is computed.  This way when the
> - * requirement that the application has is cleaned up when closes the file
> + * request is removed and a new qos target is computed.  This way when the
> + * request that the application has is cleaned up when closes the file
>   * pointer or exits the pm_qos_object will get an opportunity to clean up.
>   *
>   * Mark Gross <mgross@linux.intel.com>
>   */
>  
> +/*#define DEBUG*/
> +
>  #include <linux/pm_qos_params.h>
>  #include <linux/sched.h>
>  #include <linux/spinlock.h>
> @@ -42,25 +44,25 @@
>  #include <linux/uaccess.h>
>  
>  /*
> - * locking rule: all changes to requirements or notifiers lists
> + * locking rule: all changes to requests or notifiers lists
>   * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
>   * held, taken with _irqsave.  One lock to rule them all
>   */
> -struct requirement_list {
> +struct pm_qos_request_list {
>  	struct list_head list;
>  	union {
>  		s32 value;
>  		s32 usec;
>  		s32 kbps;
>  	};
> -	char *name;
> +	int pm_qos_class;
>  };
>  
>  static s32 max_compare(s32 v1, s32 v2);
>  static s32 min_compare(s32 v1, s32 v2);
>  
>  struct pm_qos_object {
> -	struct requirement_list requirements;
> +	struct pm_qos_request_list requests;
>  	struct blocking_notifier_head *notifiers;
>  	struct miscdevice pm_qos_power_miscdev;
>  	char *name;
> @@ -72,7 +74,7 @@ struct pm_qos_object {
>  static struct pm_qos_object null_pm_qos;
>  static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
>  static struct pm_qos_object cpu_dma_pm_qos = {
> -	.requirements = {LIST_HEAD_INIT(cpu_dma_pm_qos.requirements.list)},
> +	.requests = {LIST_HEAD_INIT(cpu_dma_pm_qos.requests.list)},
>  	.notifiers = &cpu_dma_lat_notifier,
>  	.name = "cpu_dma_latency",
>  	.default_value = 2000 * USEC_PER_SEC,
> @@ -82,7 +84,7 @@ static struct pm_qos_object cpu_dma_pm_qos = {
>  
>  static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
>  static struct pm_qos_object network_lat_pm_qos = {
> -	.requirements = {LIST_HEAD_INIT(network_lat_pm_qos.requirements.list)},
> +	.requests = {LIST_HEAD_INIT(network_lat_pm_qos.requests.list)},
>  	.notifiers = &network_lat_notifier,
>  	.name = "network_latency",
>  	.default_value = 2000 * USEC_PER_SEC,
> @@ -93,8 +95,7 @@ static struct pm_qos_object network_lat_pm_qos = {
>  
>  static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
>  static struct pm_qos_object network_throughput_pm_qos = {
> -	.requirements =
> -		{LIST_HEAD_INIT(network_throughput_pm_qos.requirements.list)},
> +	.requests = {LIST_HEAD_INIT(network_throughput_pm_qos.requests.list)},
>  	.notifiers = &network_throughput_notifier,
>  	.name = "network_throughput",
>  	.default_value = 0,
> @@ -135,31 +136,34 @@ static s32 min_compare(s32 v1, s32 v2)
>  }
>  
>  
> -static void update_target(int target)
> +static void update_target(int pm_qos_class)
>  {
>  	s32 extreme_value;
> -	struct requirement_list *node;
> +	struct pm_qos_request_list *node;
>  	unsigned long flags;
>  	int call_notifier = 0;
>  
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	extreme_value = pm_qos_array[target]->default_value;
> +	extreme_value = pm_qos_array[pm_qos_class]->default_value;
>  	list_for_each_entry(node,
> -			&pm_qos_array[target]->requirements.list, list) {
> -		extreme_value = pm_qos_array[target]->comparitor(
> +			&pm_qos_array[pm_qos_class]->requests.list, list) {
> +		extreme_value = pm_qos_array[pm_qos_class]->comparitor(
>  				extreme_value, node->value);
>  	}
> -	if (atomic_read(&pm_qos_array[target]->target_value) != extreme_value) {
> +	if (atomic_read(&pm_qos_array[pm_qos_class]->target_value) !=
> +			extreme_value) {
>  		call_notifier = 1;
> -		atomic_set(&pm_qos_array[target]->target_value, extreme_value);
> -		pr_debug(KERN_ERR "new target for qos %d is %d\n", target,
> -			atomic_read(&pm_qos_array[target]->target_value));
> +		atomic_set(&pm_qos_array[pm_qos_class]->target_value,
> +				extreme_value);
> +		pr_debug(KERN_ERR "new target for qos %d is %d\n", pm_qos_class,
> +			atomic_read(&pm_qos_array[pm_qos_class]->target_value));
>  	}
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  
>  	if (call_notifier)
> -		blocking_notifier_call_chain(pm_qos_array[target]->notifiers,
> -			(unsigned long) extreme_value, NULL);
> +		blocking_notifier_call_chain(
> +				pm_qos_array[pm_qos_class]->notifiers,
> +					(unsigned long) extreme_value, NULL);
>  }
>  
>  static int register_pm_qos_misc(struct pm_qos_object *qos)
> @@ -185,125 +189,110 @@ static int find_pm_qos_object_by_minor(int minor)
>  }
>  
>  /**
> - * pm_qos_requirement - returns current system wide qos expectation
> + * pm_qos_request - returns current system wide qos expectation
>   * @pm_qos_class: identification of which qos value is requested
>   *
>   * This function returns the current target value in an atomic manner.
>   */
> -int pm_qos_requirement(int pm_qos_class)
> +int pm_qos_request(int pm_qos_class)
>  {
>  	return atomic_read(&pm_qos_array[pm_qos_class]->target_value);
>  }
> -EXPORT_SYMBOL_GPL(pm_qos_requirement);
> +EXPORT_SYMBOL_GPL(pm_qos_request);
>  
>  /**
> - * pm_qos_add_requirement - inserts new qos request into the list
> + * pm_qos_add_request - inserts new qos request into the list
>   * @pm_qos_class: identifies which list of qos request to us
> - * @name: identifies the request
>   * @value: defines the qos request
>   *
>   * This function inserts a new entry in the pm_qos_class list of requested qos
>   * performance characteristics.  It recomputes the aggregate QoS expectations
> - * for the pm_qos_class of parameters.
> + * for the pm_qos_class of parameters, and returns the pm_qos_request list
> + * element as a handle for use in updating and removal.  Call needs to save
> + * this handle for later use.
>   */
> -int pm_qos_add_requirement(int pm_qos_class, char *name, s32 value)
> +struct pm_qos_request_list *pm_qos_add_request(int pm_qos_class, s32 value)
>  {
> -	struct requirement_list *dep;
> +	struct pm_qos_request_list *dep;
>  	unsigned long flags;
>  
> -	dep = kzalloc(sizeof(struct requirement_list), GFP_KERNEL);
> +	dep = kzalloc(sizeof(struct pm_qos_request_list), GFP_KERNEL);
>  	if (dep) {
>  		if (value == PM_QOS_DEFAULT_VALUE)
>  			dep->value = pm_qos_array[pm_qos_class]->default_value;
>  		else
>  			dep->value = value;
> -		dep->name = kstrdup(name, GFP_KERNEL);
> -		if (!dep->name)
> -			goto cleanup;
> +		dep->pm_qos_class = pm_qos_class;
>  
>  		spin_lock_irqsave(&pm_qos_lock, flags);
>  		list_add(&dep->list,
> -			&pm_qos_array[pm_qos_class]->requirements.list);
> +			&pm_qos_array[pm_qos_class]->requests.list);
>  		spin_unlock_irqrestore(&pm_qos_lock, flags);
>  		update_target(pm_qos_class);
> -
> -		return 0;
>  	}
>  
> -cleanup:
> -	kfree(dep);
> -	return -ENOMEM;
> +	return dep;
>  }
> -EXPORT_SYMBOL_GPL(pm_qos_add_requirement);
> +EXPORT_SYMBOL_GPL(pm_qos_add_request);
>  
>  /**
> - * pm_qos_update_requirement - modifies an existing qos request
> - * @pm_qos_class: identifies which list of qos request to us
> - * @name: identifies the request
> + * pm_qos_update_request - modifies an existing qos request
> + * @pm_qos_req : handle to list element holding a pm_qos request to use
>   * @value: defines the qos request
>   *
> - * Updates an existing qos requirement for the pm_qos_class of parameters along
> + * Updates an existing qos request for the pm_qos_class of parameters along
>   * with updating the target pm_qos_class value.
>   *
> - * If the named request isn't in the list then no change is made.
> + * Attempts are made to make this code callable on hot code paths.
>   */
> -int pm_qos_update_requirement(int pm_qos_class, char *name, s32 new_value)
> +void pm_qos_update_request(struct pm_qos_request_list *pm_qos_req,
> +		s32 new_value)
>  {
>  	unsigned long flags;
> -	struct requirement_list *node;
>  	int pending_update = 0;
> +	s32 temp;
>  
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	list_for_each_entry(node,
> -		&pm_qos_array[pm_qos_class]->requirements.list, list) {
> -		if (strcmp(node->name, name) == 0) {
> -			if (new_value == PM_QOS_DEFAULT_VALUE)
> -				node->value =
> -				pm_qos_array[pm_qos_class]->default_value;
> -			else
> -				node->value = new_value;
> -			pending_update = 1;
> -			break;
> -		}
> +	if (new_value == PM_QOS_DEFAULT_VALUE)
> +		temp = pm_qos_array[pm_qos_req->pm_qos_class]->default_value;
> +	else
> +		temp = new_value;
> +
> +	if (temp != pm_qos_req->value) {
> +		pending_update = 1;
> +		pm_qos_req->value = temp;
>  	}
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
>  	if (pending_update)
> -		update_target(pm_qos_class);
> -
> -	return 0;
> +		update_target(pm_qos_req->pm_qos_class);
>  }
> -EXPORT_SYMBOL_GPL(pm_qos_update_requirement);
> +EXPORT_SYMBOL_GPL(pm_qos_update_request);
>  
>  /**
> - * pm_qos_remove_requirement - modifies an existing qos request
> - * @pm_qos_class: identifies which list of qos request to us
> - * @name: identifies the request
> + * pm_qos_remove_request - modifies an existing qos request
> + * @pm_qos_req: handle to request list element
>   *
> - * Will remove named qos request from pm_qos_class list of parameters and
> - * recompute the current target value for the pm_qos_class.
> + * Will remove pm qos request from the list of requests and
> + * recompute the current target value for the pm_qos_class.  Call this
> + * on slow code paths.
>   */
> -void pm_qos_remove_requirement(int pm_qos_class, char *name)
> +void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
>  {
>  	unsigned long flags;
> -	struct requirement_list *node;
> -	int pending_update = 0;
> +	int qos_class;
> +
> +	if (pm_qos_req == NULL)
> +		return;
> +		/* silent return to keep pcm code cleaner */
>  
> +	qos_class = pm_qos_req->pm_qos_class;
>  	spin_lock_irqsave(&pm_qos_lock, flags);
> -	list_for_each_entry(node,
> -		&pm_qos_array[pm_qos_class]->requirements.list, list) {
> -		if (strcmp(node->name, name) == 0) {
> -			kfree(node->name);
> -			list_del(&node->list);
> -			kfree(node);
> -			pending_update = 1;
> -			break;
> -		}
> -	}
> +	list_del(&pm_qos_req->list);
> +	kfree(pm_qos_req);
>  	spin_unlock_irqrestore(&pm_qos_lock, flags);
> -	if (pending_update)
> -		update_target(pm_qos_class);
> +	update_target(qos_class);
>  }
> -EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
> +EXPORT_SYMBOL_GPL(pm_qos_remove_request);
>  
>  /**
>   * pm_qos_add_notifier - sets notification entry for changes to target value
> @@ -313,7 +302,7 @@ EXPORT_SYMBOL_GPL(pm_qos_remove_requirement);
>   * will register the notifier into a notification chain that gets called
>   * upon changes to the pm_qos_class target value.
>   */
> - int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
> +int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
>  {
>  	int retval;
>  
> @@ -343,21 +332,16 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
>  }
>  EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
>  
> -#define PID_NAME_LEN 32
> -
>  static int pm_qos_power_open(struct inode *inode, struct file *filp)
>  {
> -	int ret;
>  	long pm_qos_class;
> -	char name[PID_NAME_LEN];
>  
>  	pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
>  	if (pm_qos_class >= 0) {
> -		filp->private_data = (void *)pm_qos_class;
> -		snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
> -		ret = pm_qos_add_requirement(pm_qos_class, name,
> -					PM_QOS_DEFAULT_VALUE);
> -		if (ret >= 0)
> +		filp->private_data = (void *) pm_qos_add_request(pm_qos_class,
> +				PM_QOS_DEFAULT_VALUE);
> +
> +		if (filp->private_data)
>  			return 0;
>  	}
>  	return -EPERM;
> @@ -365,32 +349,40 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp)
>  
>  static int pm_qos_power_release(struct inode *inode, struct file *filp)
>  {
> -	int pm_qos_class;
> -	char name[PID_NAME_LEN];
> +	struct pm_qos_request_list *req;
>  
> -	pm_qos_class = (long)filp->private_data;
> -	snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
> -	pm_qos_remove_requirement(pm_qos_class, name);
> +	req = (struct pm_qos_request_list *)filp->private_data;
> +	pm_qos_remove_request(req);
>  
>  	return 0;
>  }
>  
> +
>  static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
>  		size_t count, loff_t *f_pos)
>  {
>  	s32 value;
> -	int pm_qos_class;
> -	char name[PID_NAME_LEN];
> -
> -	pm_qos_class = (long)filp->private_data;
> -	if (count != sizeof(s32))
> +	int x;
> +	char ascii_value[11];
> +	struct pm_qos_request_list *pm_qos_req;
> +
> +	if (count == sizeof(s32)) {
> +		if (copy_from_user(&value, buf, sizeof(s32)))
> +			return -EFAULT;
> +	} else if (count == 11) { /* len('0x12345678/0') */
> +		if (copy_from_user(ascii_value, buf, 11))
> +			return -EFAULT;
> +		x = sscanf(ascii_value, "%x", &value);
> +		if (x != 1)
> +			return -EINVAL;
> +		pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value);
> +	} else
>  		return -EINVAL;
> -	if (copy_from_user(&value, buf, sizeof(s32)))
> -		return -EFAULT;
> -	snprintf(name, PID_NAME_LEN, "process_%d", current->pid);
> -	pm_qos_update_requirement(pm_qos_class, name, value);
>  
> -	return  sizeof(s32);
> +	pm_qos_req = (struct pm_qos_request_list *)filp->private_data;
> +	pm_qos_update_request(pm_qos_req, value);
> +
> +	return count;
>  }
>  
>  
> diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
> index 358226f..3deaac3 100644
> --- a/net/mac80211/mlme.c
> +++ b/net/mac80211/mlme.c
> @@ -507,7 +507,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
>  		s32 beaconint_us;
>  
>  		if (latency < 0)
> -			latency = pm_qos_requirement(PM_QOS_NETWORK_LATENCY);
> +			latency = pm_qos_request(PM_QOS_NETWORK_LATENCY);
>  
>  		beaconint_us = ieee80211_tu_to_usec(
>  					found->vif.bss_conf.beacon_int);
> diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
> index 8bc961f..be52bb8 100644
> --- a/net/mac80211/scan.c
> +++ b/net/mac80211/scan.c
> @@ -510,7 +510,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
>  		bad_latency = time_after(jiffies +
>  				ieee80211_scan_get_channel_time(next_chan),
>  				local->leave_oper_channel_time +
> -				usecs_to_jiffies(pm_qos_requirement(PM_QOS_NETWORK_LATENCY)));
> +				usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
>  
>  		listen_int_exceeded = time_after(jiffies +
>  				ieee80211_scan_get_channel_time(next_chan),
> diff --git a/sound/core/pcm.c b/sound/core/pcm.c
> index 0d428d0..cbe815d 100644
> --- a/sound/core/pcm.c
> +++ b/sound/core/pcm.c
> @@ -648,9 +648,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
>  		substream->number = idx;
>  		substream->stream = stream;
>  		sprintf(substream->name, "subdevice #%i", idx);
> -		snprintf(substream->latency_id, sizeof(substream->latency_id),
> -			 "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
> -			 (stream ? 'c' : 'p'), idx);
>  		substream->buffer_bytes_max = UINT_MAX;
>  		if (prev == NULL)
>  			pstr->substream = substream;
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index c22ebb0..1bb0e23 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -481,11 +481,13 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
>  	snd_pcm_timer_resolution_change(substream);
>  	runtime->status->state = SNDRV_PCM_STATE_SETUP;
>  
> -	pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
> -				substream->latency_id);
> +	if (substream->latency_pm_qos_req) {
> +		pm_qos_remove_request(substream->latency_pm_qos_req);
> +		substream->latency_pm_qos_req = NULL;
> +	}
>  	if ((usecs = period_to_usecs(runtime)) >= 0)
> -		pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
> -					substream->latency_id, usecs);
> +		substream->latency_pm_qos_req = pm_qos_add_request(
> +					PM_QOS_CPU_DMA_LATENCY, usecs);
>  	return 0;
>   _error:
>  	/* hardware might be unuseable from this time,
> @@ -540,8 +542,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
>  	if (substream->ops->hw_free)
>  		result = substream->ops->hw_free(substream);
>  	runtime->status->state = SNDRV_PCM_STATE_OPEN;
> -	pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
> -		substream->latency_id);
> +	pm_qos_remove_request(substream->latency_pm_qos_req);
> +	substream->latency_pm_qos_req = NULL;
>  	return result;
>  }
>  
> 


^ permalink raw reply

* Re: ixgbe and mac-vlans problem
From: Ben Greear @ 2010-04-30 22:20 UTC (permalink / raw)
  To: Tantilov, Emil S; +Cc: Arnd Bergmann, NetDev, Patrick McHardy
In-Reply-To: <EA929A9653AAE14F841771FB1DE5A1365FE55609F0@rrsmsx501.amr.corp.intel.com>

On 04/30/2010 02:13 PM, Tantilov, Emil S wrote:
> Ben Greear wrote:
>> On 04/30/2010 11:00 AM, Arnd Bergmann wrote:
>>> On Friday 30 April 2010 00:27:39 Ben Greear wrote:
>>>> Basically, we create 50 mac-vlans, with sequential MAC addresses
>>>> and sequential IP addresses, and set up ip rules properly.
>>>>
>>>> The issue is that only 10 or so of the mac-vlans receive other than
>>>> broadcast packets.  The ixgbe NIC doesn't show PROMISC mode.
>>>
>>> I just took a brief look at the driver and noticed that 82599 should
>>> be able to handle 128 entries before going into promisc mode, while
>>> 82598 (the same driver) does 16.
>>>
>>> Maybe the logic for>16 entries is wrong, so you could try forcing
>>> hw->mac.num_rar_entries to 16 for 82599 as well.
>>
>> I think I was actually on an 825998 system when I saw it yesterday,
>> but I have seen similar issues on 82599, though I didn't take time
>> to debug it fully, so it could have been something else.
>>
>> I will double-check the NIC chipset on the system that showed the
>> problem yesterday.
>
> I ran a quick test in my setup with 82599 and was able to pass traffic
> on all 50 mac-vlans without issues. This is on net-next.

For an 82599 system, I can get 127 mac-vlans working out of 500 created.

That NIC also does not go PROMISC with lots (500) of mac-vlans.

Once I put it in promisc mode manually, it works fine.

So, I think whatever logic is supposed to put the NIC into promisc
mode when it overflows it's lookup tables isn't working for ixgbe
in 2.6.31.12.

Thanks,
Ben

>
> Thanks,
> Emil


-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* [patch] ipv6: cleanup: remove unneeded null check
From: Dan Carpenter @ 2010-04-29 14:30 UTC (permalink / raw)
  To: netdev
  Cc: Alexey Kuznetsov, Pekka Savola (ipv6), James Morris,
	Hideaki YOSHIFUJI, Patrick McHardy, Eric Dumazet,
	Sridhar Samudrala, Herbert Xu, Emil S Tantilov, David S. Miller,
	kernel-janitors

We dereference "sk" unconditionally elsewhere in the function.  

This was left over from:  b30bd282 "ip6_xmit: remove unnecessary NULL
ptr check".  According to that commit message, "the sk argument to 
ip6_xmit is never NULL nowadays since the skb->priority assigment 
expects a valid socket."

Signed-off-by: Dan Carpenter <error27@gmail.com>

diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 75d5ef8..d26c6ae 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -218,8 +218,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 			}
 			kfree_skb(skb);
 			skb = skb2;
-			if (sk)
-				skb_set_owner_w(skb, sk);
+			skb_set_owner_w(skb, sk);
 		}
 		if (opt->opt_flen)
 			ipv6_push_frag_opts(skb, opt, &proto);

^ permalink raw reply related

* RE: ixgbe and mac-vlans problem
From: Tantilov, Emil S @ 2010-04-30 22:26 UTC (permalink / raw)
  To: Ben Greear; +Cc: Arnd Bergmann, NetDev, Patrick McHardy
In-Reply-To: <4BDB57A6.1090400@candelatech.com>

Ben Greear wrote:
> On 04/30/2010 02:13 PM, Tantilov, Emil S wrote:
>> Ben Greear wrote:
>>> On 04/30/2010 11:00 AM, Arnd Bergmann wrote:
>>>> On Friday 30 April 2010 00:27:39 Ben Greear wrote:
>>>>> Basically, we create 50 mac-vlans, with sequential MAC addresses
>>>>> and sequential IP addresses, and set up ip rules properly.
>>>>> 
>>>>> The issue is that only 10 or so of the mac-vlans receive other
>>>>> than broadcast packets.  The ixgbe NIC doesn't show PROMISC mode.
>>>> 
>>>> I just took a brief look at the driver and noticed that 82599
>>>> should be able to handle 128 entries before going into promisc
>>>> mode, while 82598 (the same driver) does 16.
>>>> 
>>>> Maybe the logic for>16 entries is wrong, so you could try forcing
>>>> hw->mac.num_rar_entries to 16 for 82599 as well.
>>> 
>>> I think I was actually on an 825998 system when I saw it yesterday,
>>> but I have seen similar issues on 82599, though I didn't take time
>>> to debug it fully, so it could have been something else.
>>> 
>>> I will double-check the NIC chipset on the system that showed the
>>> problem yesterday.
>> 
>> I ran a quick test in my setup with 82599 and was able to pass
>> traffic on all 50 mac-vlans without issues. This is on net-next.
> 
> For an 82599 system, I can get 127 mac-vlans working out of 500
> created. 
> 
> That NIC also does not go PROMISC with lots (500) of mac-vlans.
> 
> Once I put it in promisc mode manually, it works fine.
> 
> So, I think whatever logic is supposed to put the NIC into promisc
> mode when it overflows it's lookup tables isn't working for ixgbe
> in 2.6.31.12.

Yeah, you're right. I was able to repro it. 

We'll look into it.

Thanks,
Emil

^ permalink raw reply

* Re: OFT - reserving CPU's for networking
From: David Miller @ 2010-04-30 22:30 UTC (permalink / raw)
  To: andi; +Cc: tglx, shemminger, eric.dumazet, netdev, peterz
In-Reply-To: <20100430210131.GA2833@gargoyle.fritz.box>

From: Andi Kleen <andi@firstfloor.org>
Date: Fri, 30 Apr 2010 23:01:31 +0200

> Besides it seems to me that dispatching is something the NIC should
> just do directly. "RPS only CPU" would be essentially just an 
> interrupt mitigation/flow redirection scheme that a lot of NICs
> do anyways.

We've already established that the NIC can't do a complete job in all
important cases, that's why we've integrated the RPS/RFS patches in
the first place.

And we don't want it to, because the decision mechanisms for steering
that we using now are starting to get into the stateful territory and
that's verbotton for NIC offload as far as we're concerned.

^ permalink raw reply

* Re: [Patch 2/3] sysctl: add proc_do_large_bitmap
From: Changli Gao @ 2010-04-30 22:41 UTC (permalink / raw)
  To: Amerigo Wang
  Cc: linux-kernel, Octavian Purdila, Eric Dumazet, penguin-kernel,
	netdev, Neil Horman, ebiederm, adobriyan, David Miller
In-Reply-To: <20100430082936.5630.67682.sendpatchset@localhost.localdomain>

On Fri, Apr 30, 2010 at 4:25 PM, Amerigo Wang <amwang@redhat.com> wrote:
> From: Octavian Purdila <opurdila@ixiacom.com>
>
> The new function can be used to read/write large bitmaps via /proc. A
> comma separated range format is used for compact output and input
> (e.g. 1,3-4,10-10).
>
> Writing into the file will first reset the bitmap then update it
> based on the given input.
>
> Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
> Signed-off-by: WANG Cong <amwang@redhat.com>
> Cc: Eric W. Biederman <ebiederm@xmission.com>
> ---
>
> Index: linux-2.6/include/linux/sysctl.h
> ===================================================================
> --- linux-2.6.orig/include/linux/sysctl.h
> +++ linux-2.6/include/linux/sysctl.h
> @@ -980,6 +980,8 @@ extern int proc_doulongvec_minmax(struct
>                                  void __user *, size_t *, loff_t *);
>  extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
>                                      void __user *, size_t *, loff_t *);
> +extern int proc_do_large_bitmap(struct ctl_table *, int,
> +                               void __user *, size_t *, loff_t *);
>
>  /*
>  * Register a set of sysctl names by calling register_sysctl_table
> Index: linux-2.6/kernel/sysctl.c
> ===================================================================
> --- linux-2.6.orig/kernel/sysctl.c
> +++ linux-2.6/kernel/sysctl.c
> @@ -2049,6 +2049,16 @@ static size_t proc_skip_spaces(char **bu
>        return ret;
>  }
>
> +static void proc_skip_char(char **buf, size_t *size, const char v)
> +{
> +       while (*size) {
> +               if (**buf != v)
> +                       break;
> +               (*size)--;
> +               (*buf)++;
> +       }
> +}
> +
>  #define TMPBUFLEN 22
>  /**
>  * proc_get_long - reads an ASCII formated integer from a user buffer
> @@ -2675,6 +2685,153 @@ static int proc_do_cad_pid(struct ctl_ta
>        return 0;
>  }
>
> +/**
> + * proc_do_large_bitmap - read/write from/to a large bitmap
> + * @table: the sysctl table
> + * @write: %TRUE if this is a write to the sysctl file
> + * @buffer: the user buffer
> + * @lenp: the size of the user buffer
> + * @ppos: file position
> + *
> + * The bitmap is stored at table->data and the bitmap length (in bits)
> + * in table->maxlen.
> + *
> + * We use a range comma separated format (e.g. 1,3-4,10-10) so that
> + * large bitmaps may be represented in a compact manner. Writing into
> + * the file will clear the bitmap then update it with the given input.
> + *
> + * Returns 0 on success.
> + */
> +int proc_do_large_bitmap(struct ctl_table *table, int write,
> +                        void __user *buffer, size_t *lenp, loff_t *ppos)
> +{
> +       int err = 0;
> +       bool first = 1;
> +       size_t left = *lenp;
> +       unsigned long bitmap_len = table->maxlen;
> +       unsigned long *bitmap = (unsigned long *) table->data;
> +       unsigned long *tmp_bitmap = NULL;
> +       char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
> +
> +       if (!bitmap_len || !left || (*ppos && !write)) {
> +               *lenp = 0;
> +               return 0;
> +       }
> +
> +       if (write) {
> +               unsigned long page = 0;
> +               char *kbuf;
> +
> +               if (left > PAGE_SIZE - 1)
> +                       left = PAGE_SIZE - 1;
> +
> +               page = __get_free_page(GFP_TEMPORARY);
> +               kbuf = (char *) page;
> +               if (!kbuf)
> +                       return -ENOMEM;
> +               if (copy_from_user(kbuf, buffer, left)) {
> +                       free_page(page);
> +                       return -EFAULT;
> +                }
> +               kbuf[left] = 0;
> +
> +               tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
> +                                    GFP_KERNEL);
> +               if (!tmp_bitmap) {
> +                       free_page(page);
> +                       return -ENOMEM;
> +               }
> +               proc_skip_char(&kbuf, &left, '\n');
> +               while (!err && left) {
> +                       unsigned long val_a, val_b;
> +                       bool neg;
> +
> +                       err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
> +                                            sizeof(tr_a), &c);
> +                       if (err)
> +                               break;
> +                       if (val_a >= bitmap_len || neg) {
> +                               err = -EINVAL;
> +                               break;
> +                       }
> +
> +                       val_b = val_a;
> +                       if (left) {
> +                               kbuf++;
> +                               left--;
> +                       }
> +
> +                       if (c == '-') {
> +                               err = proc_get_long(&kbuf, &left, &val_b,
> +                                                    &neg, tr_b, sizeof(tr_b),
> +                                                    &c);
> +                               if (err)
> +                                       break;
> +                               if (val_b >= bitmap_len || neg ||
> +                                   val_a > val_b) {
> +                                       err = -EINVAL;
> +                                       break;
> +                               }
> +                               if (left) {
> +                                       kbuf++;
> +                                       left--;
> +                               }
> +                       }
> +
> +                       while (val_a <= val_b)
> +                               set_bit(val_a++, tmp_bitmap);
> +
> +                       first = 0;
> +                       proc_skip_char(&kbuf, &left, '\n');
> +               }
> +               free_page(page);
> +       } else {
> +               unsigned long bit_a, bit_b = 0;
> +
> +               while (left) {
> +                       bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
> +                       if (bit_a >= bitmap_len)
> +                               break;
> +                       bit_b = find_next_zero_bit(bitmap, bitmap_len,
> +                                                  bit_a + 1) - 1;
> +
> +                       if (!first) {
> +                               err = proc_put_char(&buffer, &left, ',');
> +                               if (err)
> +                                       break;
> +                       }
> +                       err = proc_put_long(&buffer, &left, bit_a, false);
> +                       if (err)
> +                               break;
> +                       if (bit_a != bit_b) {
> +                               err = proc_put_char(&buffer, &left, '-');
> +                               if (err)
> +                                       break;
> +                               err = proc_put_long(&buffer, &left, bit_b, false);
> +                               if (err)
> +                                       break;
> +                       }
> +
> +                       first = 0; bit_b++;
> +               }
> +               if (!err)
> +                       err = proc_put_char(&buffer, &left, '\n');
> +       }
> +
> +       if (!err) {
                     add the following lines to let "echo 1-10 >>
/proc/..." work as normal.
                     if (write && *ppos)
                           bimap_or(bitmap, bitmap, tmp_bitmap,....)
                     else

> +               if (write)
> +                       memcpy(bitmap, tmp_bitmap,
> +                              BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
> +               kfree(tmp_bitmap);
> +               *lenp -= left;
> +               *ppos += *lenp;
> +               return 0;





-- 
Regards,
Changli Gao(xiaosuo@gmail.com)

^ permalink raw reply

* Re: 2.6.34-rc5-git7 (plus all patches) -- another suspicious rcu_dereference_check() usage.
From: Paul E. McKenney @ 2010-04-30 22:48 UTC (permalink / raw)
  To: Miles Lane
  Cc: Vivek Goyal, Eric Paris, Lai Jiangshan, Ingo Molnar,
	Peter Zijlstra, LKML, nauman, eric.dumazet, netdev, Jens Axboe,
	Gui Jianfeng, Li Zefan, Johannes Berg
In-Reply-To: <h2ya44ae5cd1004261751waa5cb65ei3d139cbcfa2cc5cf@mail.gmail.com>

On Mon, Apr 26, 2010 at 08:51:06PM -0400, Miles Lane wrote:
> This one occurred during the wakeup from suspend to RAM.
> 
> [  984.724697] [ INFO: suspicious rcu_dereference_check() usage. ]
> [  984.724700] ---------------------------------------------------
> [  984.724703] include/linux/fdtable.h:88 invoked
> rcu_dereference_check() without protection!
> [  984.724706]
> [  984.724707] other info that might help us debug this:
> [  984.724708]
> [  984.724711]
> [  984.724711] rcu_scheduler_active = 1, debug_locks = 1
> [  984.724714] no locks held by dbus-daemon/4680.
> [  984.724717]
> [  984.724717] stack backtrace:
> [  984.724721] Pid: 4680, comm: dbus-daemon Not tainted 2.6.34-rc5-git7 #33
> [  984.724724] Call Trace:
> [  984.724734]  [<ffffffff81074556>] lockdep_rcu_dereference+0x9d/0xa6
> [  984.724740]  [<ffffffff810fc785>] fcheck_files+0xb1/0xc9
> [  984.724745]  [<ffffffff810fc7f5>] fget_light+0x35/0xab
> [  984.724751]  [<ffffffff81433e1b>] ? sock_poll_wait+0x13/0x18
> [  984.724755]  [<ffffffff81433e39>] ? unix_poll+0x19/0x95
> [  984.724762]  [<ffffffff8110aa95>] do_sys_poll+0x1ff/0x3e5
> [  984.724766]  [<ffffffff8110a19e>] ? __pollwait+0x0/0xc7
> [  984.724771]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724776]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724780]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724784]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724788]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724793]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724797]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724802]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724806]  [<ffffffff8110a265>] ? pollwake+0x0/0x4f
> [  984.724812]  [<ffffffff8110ae0f>] sys_poll+0x50/0xbb
> [  984.724818]  [<ffffffff81009d82>] system_call_fastpath+0x16/0x1b

And here, at long last, is the relevant patch.

							Thanx, Paul

------------------------------------------------------------------------

commit dced7789910f0b1b4e9b94fe74d79f2c2f788399
Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Date:   Fri Apr 30 15:24:24 2010 -0700

    vfs: fix RCU-lockdep false positive due to /proc access
    
    If a single-threaded process does a file-descriptor operation, and
    some other process accesses that same file descriptor via /proc,
    the current rcu_dereference_check_fdtable() can give a false-positive
    RCU-lockdep splat due to the reference count being increased by the
    /proc access after the reference-count check in fget_light() but before
    the check in rcu_dereference_check_fdtable().
    
    This commit prevents this false positive by checking for a single-threaded
    process.
    
    Located-by: Miles Lane <miles.lane@gmail.com>
    Located-by: Eric Dumazet <eric.dumazet@gmail.com>
    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 013dc52..e4a6d31 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -61,7 +61,8 @@ struct files_struct {
 	(rcu_dereference_check((fdtfd), \
 			       rcu_read_lock_held() || \
 			       lockdep_is_held(&(files)->file_lock) || \
-			       atomic_read(&(files)->count) == 1))
+			       atomic_read(&(files)->count) == 1 || \
+			       thread_group_empty(current)))
 
 #define files_fdtable(files) \
 		(rcu_dereference_check_fdtable((files), (files)->fdt))

^ permalink raw reply related


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