Netdev List
 help / color / mirror / Atom feed
* [PATCH 08/12] cxgb4: remove the name field from the adapter structure
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-8-git-send-email-dm@chelsio.com>

Remove a field the driver uses to keep track of the name of the first
netdev it manages to register.  Do this by changing the registration
loop to stop the first time it fails so the first registered device is
trivial to tell.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4.h      |    1 -
 drivers/net/cxgb4/cxgb4_main.c |   37 +++++++++++++++----------------------
 2 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index f3d9f64..9caf95f 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -486,7 +486,6 @@ struct adapter {
 	unsigned int fn;
 	unsigned int flags;
 
-	const char *name;
 	int msg_enable;
 
 	struct adapter_params params;
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 7e26fe5..4d7565c 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -525,10 +525,11 @@ static void name_msix_vecs(struct adapter *adap)
 	int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc);
 
 	/* non-data interrupts */
-	snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+	snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name);
 
 	/* FW events */
-	snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", adap->name);
+	snprintf(adap->msix_info[1].desc, n, "%s-FWeventq",
+		 adap->port[0]->name);
 
 	/* Ethernet queues */
 	for_each_port(adap, j) {
@@ -543,11 +544,11 @@ static void name_msix_vecs(struct adapter *adap)
 	/* offload queues */
 	for_each_ofldrxq(&adap->sge, i)
 		snprintf(adap->msix_info[msi_idx++].desc, n, "%s-ofld%d",
-			 adap->name, i);
+			 adap->port[0]->name, i);
 
 	for_each_rdmarxq(&adap->sge, i)
 		snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d",
-			 adap->name, i);
+			 adap->port[0]->name, i);
 }
 
 static int request_msix_queue_irqs(struct adapter *adap)
@@ -2664,7 +2665,7 @@ static int cxgb_up(struct adapter *adap)
 	} else {
 		err = request_irq(adap->pdev->irq, t4_intr_handler(adap),
 				  (adap->flags & USING_MSI) ? 0 : IRQF_SHARED,
-				  adap->name, adap);
+				  adap->port[0]->name, adap);
 		if (err)
 			goto irq_err;
 	}
@@ -3627,7 +3628,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 	adapter->pdev = pdev;
 	adapter->pdev_dev = &pdev->dev;
 	adapter->fn = func;
-	adapter->name = pci_name(pdev);
 	adapter->msg_enable = dflt_msg_enable;
 	memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
 
@@ -3724,26 +3724,19 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 		err = register_netdev(adapter->port[i]);
 		if (err)
-			dev_warn(&pdev->dev,
-				 "cannot register net device %s, skipping\n",
-				 adapter->port[i]->name);
-		else {
-			/*
-			 * Change the name we use for messages to the name of
-			 * the first successfully registered interface.
-			 */
-			if (!adapter->registered_device_map)
-				adapter->name = adapter->port[i]->name;
-
-			__set_bit(i, &adapter->registered_device_map);
-			adapter->chan_map[pi->tx_chan] = i;
-			print_port_info(adapter->port[i]);
-		}
+			break;
+		__set_bit(i, &adapter->registered_device_map);
+		adapter->chan_map[pi->tx_chan] = i;
+		print_port_info(adapter->port[i]);
 	}
-	if (!adapter->registered_device_map) {
+	if (i == 0) {
 		dev_err(&pdev->dev, "could not register any net devices\n");
 		goto out_free_dev;
 	}
+	if (err) {
+		dev_warn(&pdev->dev, "only %d net devices registered\n", i);
+		err = 0;
+	};
 
 	if (cxgb4_debugfs_root) {
 		adapter->debugfs_root = debugfs_create_dir(pci_name(pdev),
-- 
1.5.4


^ permalink raw reply related

* [PATCH 05/12] cxgb4: print port information after registering each netdev
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-5-git-send-email-dm@chelsio.com>

Print information about each port when its netdev is registered instead
of looping separately over the ports at the end.  The bulk of this patch
is due to indentation change.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4_main.c |   54 ++++++++++++++++-----------------------
 1 files changed, 22 insertions(+), 32 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 3f33d51..089b753 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -3490,50 +3490,41 @@ static int __devinit init_rss(struct adapter *adap)
 	return 0;
 }
 
-static void __devinit print_port_info(struct adapter *adap)
+static void __devinit print_port_info(const struct net_device *dev)
 {
 	static const char *base[] = {
 		"R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
 		"KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4"
 	};
 
-	int i;
 	char buf[80];
+	char *bufp = buf;
 	const char *spd = "";
+	const struct port_info *pi = netdev_priv(dev);
+	const struct adapter *adap = pi->adapter;
 
 	if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_2_5GB)
 		spd = " 2.5 GT/s";
 	else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB)
 		spd = " 5 GT/s";
 
-	for_each_port(adap, i) {
-		struct net_device *dev = adap->port[i];
-		const struct port_info *pi = netdev_priv(dev);
-		char *bufp = buf;
-
-		if (!test_bit(i, &adap->registered_device_map))
-			continue;
-
-		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
-			bufp += sprintf(bufp, "100/");
-		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
-			bufp += sprintf(bufp, "1000/");
-		if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
-			bufp += sprintf(bufp, "10G/");
-		if (bufp != buf)
-			--bufp;
-		sprintf(bufp, "BASE-%s", base[pi->port_type]);
-
-		netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
-			    adap->params.vpd.id, adap->params.rev,
-			    buf, is_offload(adap) ? "R" : "",
-			    adap->params.pci.width, spd,
-			    (adap->flags & USING_MSIX) ? " MSI-X" :
-			    (adap->flags & USING_MSI) ? " MSI" : "");
-		if (adap->name == dev->name)
-			netdev_info(dev, "S/N: %s, E/C: %s\n",
-				    adap->params.vpd.sn, adap->params.vpd.ec);
-	}
+	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M)
+		bufp += sprintf(bufp, "100/");
+	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G)
+		bufp += sprintf(bufp, "1000/");
+	if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
+		bufp += sprintf(bufp, "10G/");
+	if (bufp != buf)
+		--bufp;
+	sprintf(bufp, "BASE-%s", base[pi->port_type]);
+
+	netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
+		    adap->params.vpd.id, adap->params.rev, buf,
+		    is_offload(adap) ? "R" : "", adap->params.pci.width, spd,
+		    (adap->flags & USING_MSIX) ? " MSI-X" :
+		    (adap->flags & USING_MSI) ? " MSI" : "");
+	netdev_info(dev, "S/N: %s, E/C: %s\n",
+		    adap->params.vpd.sn, adap->params.vpd.ec);
 }
 
 static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev)
@@ -3753,6 +3744,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
 			__set_bit(i, &adapter->registered_device_map);
 			adapter->chan_map[pi->tx_chan] = i;
+			print_port_info(adapter->port[i]);
 		}
 	}
 	if (!adapter->registered_device_map) {
@@ -3769,8 +3761,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 	if (is_offload(adapter))
 		attach_ulds(adapter);
 
-	print_port_info(adapter);
-
 sriov:
 #ifdef CONFIG_PCI_IOV
 	if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0)
-- 
1.5.4


^ permalink raw reply related

* [PATCH 04/12] cxgb4: distinguish between 1-lane KR/KX and 4-lane KR/KX/KX4 ports
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-4-git-send-email-dm@chelsio.com>

And fix the supported flags ethtool reports for the two cases.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4_main.c |    9 +++++++--
 drivers/net/cxgb4/t4fw_api.h   |    1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 3012a8a..3f33d51 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -1375,7 +1375,12 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
 	} else if (type == FW_PORT_TYPE_KR)
 		v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full;
 	else if (type == FW_PORT_TYPE_BP_AP)
-		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC;
+		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+		     SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full;
+	else if (type == FW_PORT_TYPE_BP4_AP)
+		v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+		     SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full |
+		     SUPPORTED_10000baseKX4_Full;
 	else if (type == FW_PORT_TYPE_FIBER_XFI ||
 		 type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
 		v |= SUPPORTED_FIBRE;
@@ -3489,7 +3494,7 @@ static void __devinit print_port_info(struct adapter *adap)
 {
 	static const char *base[] = {
 		"R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
-		"KX", "KR", "KR SFP+", "KR FEC"
+		"KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4"
 	};
 
 	int i;
diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h
index 940584a..edcfd7e 100644
--- a/drivers/net/cxgb4/t4fw_api.h
+++ b/drivers/net/cxgb4/t4fw_api.h
@@ -1239,6 +1239,7 @@ enum fw_port_type {
 	FW_PORT_TYPE_KR,
 	FW_PORT_TYPE_SFP,
 	FW_PORT_TYPE_BP_AP,
+	FW_PORT_TYPE_BP4_AP,
 
 	FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
 };
-- 
1.5.4


^ permalink raw reply related

* [PATCH 00/12 net-next] cxgb4 update v2
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev


This is v2 of the cxgb4 series.  I've removed the fallback call to kcalloc in
patch 12 per Eric's comment and restored an accidentally removed increment in
patch 7.

 drivers/net/cxgb4/cxgb4.h      |    4 +-
 drivers/net/cxgb4/cxgb4_main.c |  134 +++++++++++++++++++---------------------
 drivers/net/cxgb4/sge.c        |   22 +++++--
 drivers/net/cxgb4/t4_hw.c      |   93 ++++++++++++++--------------
 drivers/net/cxgb4/t4fw_api.h   |    1 +
 5 files changed, 127 insertions(+), 127 deletions(-)

^ permalink raw reply

* [PATCH 01/12] cxgb4: enable PCIe relaxed ordering
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-1-git-send-email-dm@chelsio.com>

Enable relaxed ordering for descriptor reads and packet I/O.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4_main.c |   14 ++++++++++++++
 drivers/net/cxgb4/sge.c        |    5 +++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 848f89d..953d62a 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -3535,6 +3535,19 @@ static void __devinit print_port_info(struct adapter *adap)
 	}
 }
 
+static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev)
+{
+	u16 v;
+	int pos;
+
+	pos = pci_pcie_cap(dev);
+	if (pos > 0) {
+		pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &v);
+		v |= PCI_EXP_DEVCTL_RELAX_EN;
+		pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, v);
+	}
+}
+
 /*
  * Free the following resources:
  * - memory used for tables
@@ -3609,6 +3622,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 	}
 
 	pci_enable_pcie_error_reporting(pdev);
+	enable_pcie_relaxed_ordering(pdev);
 	pci_set_master(pdev);
 	pci_save_state(pdev);
 
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index 1702225..cc0b997 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -2014,6 +2014,8 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
 
 		flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc);
 		c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN |
+					    FW_IQ_CMD_FL0FETCHRO(1) |
+					    FW_IQ_CMD_FL0DATARO(1) |
 					    FW_IQ_CMD_FL0PADEN);
 		c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) |
 				FW_IQ_CMD_FL0FBMAX(3));
@@ -2106,6 +2108,7 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
 	c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
 	c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) |
 				   FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) |
+				   FW_EQ_ETH_CMD_FETCHRO(1) |
 				   FW_EQ_ETH_CMD_IQID(iqid));
 	c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN(2) |
 				  FW_EQ_ETH_CMD_FBMAX(3) |
@@ -2158,6 +2161,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
 	c.physeqid_pkd = htonl(0);
 	c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE(2) |
 				   FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) |
+				   FW_EQ_CTRL_CMD_FETCHRO |
 				   FW_EQ_CTRL_CMD_IQID(iqid));
 	c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN(2) |
 				  FW_EQ_CTRL_CMD_FBMAX(3) |
@@ -2207,6 +2211,7 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
 				 FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c));
 	c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) |
 				   FW_EQ_OFLD_CMD_PCIECHN(pi->tx_chan) |
+				   FW_EQ_OFLD_CMD_FETCHRO(1) |
 				   FW_EQ_OFLD_CMD_IQID(iqid));
 	c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN(2) |
 				  FW_EQ_OFLD_CMD_FBMAX(3) |
-- 
1.5.4


^ permalink raw reply related

* [PATCH 07/12] cxgb4: correct formatting of MSI-X interrupt names
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-7-git-send-email-dm@chelsio.com>

The last byte of the buffer for MSI-X names could not be used due to a
bogus -1.  Also do not explicitly clear the last byte, snprintf will do
the right thing.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4_main.c |   21 +++++++--------------
 1 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 089b753..7e26fe5 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -522,39 +522,32 @@ static irqreturn_t t4_nondata_intr(int irq, void *cookie)
  */
 static void name_msix_vecs(struct adapter *adap)
 {
-	int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc) - 1;
+	int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc);
 
 	/* non-data interrupts */
 	snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
-	adap->msix_info[0].desc[n] = 0;
 
 	/* FW events */
 	snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", adap->name);
-	adap->msix_info[1].desc[n] = 0;
 
 	/* Ethernet queues */
 	for_each_port(adap, j) {
 		struct net_device *d = adap->port[j];
 		const struct port_info *pi = netdev_priv(d);
 
-		for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+		for (i = 0; i < pi->nqsets; i++, msi_idx++)
 			snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d",
 				 d->name, i);
-			adap->msix_info[msi_idx].desc[n] = 0;
-		}
 	}
 
 	/* offload queues */
-	for_each_ofldrxq(&adap->sge, i) {
-		snprintf(adap->msix_info[msi_idx].desc, n, "%s-ofld%d",
+	for_each_ofldrxq(&adap->sge, i)
+		snprintf(adap->msix_info[msi_idx++].desc, n, "%s-ofld%d",
 			 adap->name, i);
-		adap->msix_info[msi_idx++].desc[n] = 0;
-	}
-	for_each_rdmarxq(&adap->sge, i) {
-		snprintf(adap->msix_info[msi_idx].desc, n, "%s-rdma%d",
+
+	for_each_rdmarxq(&adap->sge, i)
+		snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d",
 			 adap->name, i);
-		adap->msix_info[msi_idx++].desc[n] = 0;
-	}
 }
 
 static int request_msix_queue_irqs(struct adapter *adap)
-- 
1.5.4


^ permalink raw reply related

* [PATCH 11/12] cxgb4: extend VPD parsing
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-11-git-send-email-dm@chelsio.com>

Current code parses the VPD RO section for keywords but makes static
assumptions about the location of the section.  Remove them and parse
the VPD to find it.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/t4_hw.c |   41 +++++++++++++++++++++--------------------
 1 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index c7fb549..b9fd8a6 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -330,18 +330,6 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
 	return 0;
 }
 
-/*
- * Partial EEPROM Vital Product Data structure.  Includes only the ID and
- * VPD-R header.
- */
-struct t4_vpd_hdr {
-	u8  id_tag;
-	u8  id_len[2];
-	u8  id_data[ID_LEN];
-	u8  vpdr_tag;
-	u8  vpdr_len[2];
-};
-
 #define EEPROM_STAT_ADDR   0x7bfc
 #define VPD_BASE           0
 #define VPD_LEN            512
@@ -372,23 +360,36 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 	int i, ret;
 	int ec, sn;
 	u8 vpd[VPD_LEN], csum;
-	unsigned int vpdr_len;
-	const struct t4_vpd_hdr *v;
+	unsigned int vpdr_len, kw_offset, id_len;
 
 	ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
 	if (ret < 0)
 		return ret;
 
-	v = (const struct t4_vpd_hdr *)vpd;
-	vpdr_len = pci_vpd_lrdt_size(&v->vpdr_tag);
-	if (vpdr_len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
+	if (vpd[0] != PCI_VPD_LRDT_ID_STRING) {
+		dev_err(adapter->pdev_dev, "missing VPD ID string\n");
+		return -EINVAL;
+	}
+
+	id_len = pci_vpd_lrdt_size(vpd);
+	if (id_len > ID_LEN)
+		id_len = ID_LEN;
+
+	i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA);
+	if (i < 0) {
+		dev_err(adapter->pdev_dev, "missing VPD-R section\n");
+		return -EINVAL;
+	}
+
+	vpdr_len = pci_vpd_lrdt_size(&vpd[i]);
+	kw_offset = i + PCI_VPD_LRDT_TAG_SIZE;
+	if (vpdr_len + kw_offset > VPD_LEN) {
 		dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
 		return -EINVAL;
 	}
 
 #define FIND_VPD_KW(var, name) do { \
-	var = pci_vpd_find_info_keyword(&v->id_tag, sizeof(struct t4_vpd_hdr), \
-					vpdr_len, name); \
+	var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \
 	if (var < 0) { \
 		dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
 		return -EINVAL; \
@@ -410,7 +411,7 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 	FIND_VPD_KW(sn, "SN");
 #undef FIND_VPD_KW
 
-	memcpy(p->id, v->id_data, ID_LEN);
+	memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
 	strim(p->id);
 	memcpy(p->ec, vpd + ec, EC_LEN);
 	strim(p->ec);
-- 
1.5.4


^ permalink raw reply related

* [PATCH 02/12] cxgb4: do not read the clock frequency from VPD
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-2-git-send-email-dm@chelsio.com>

No need to read the clock frequency from VPD, we already get it a bit
later from FW, after any potential adjustments.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/t4_hw.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index e97521c..6af0452 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -370,7 +370,7 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
 static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 {
 	int i, ret;
-	int ec, sn, v2;
+	int ec, sn;
 	u8 vpd[VPD_LEN], csum;
 	unsigned int vpdr_len;
 	const struct t4_vpd_hdr *v;
@@ -408,10 +408,8 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 
 	FIND_VPD_KW(ec, "EC");
 	FIND_VPD_KW(sn, "SN");
-	FIND_VPD_KW(v2, "V2");
 #undef FIND_VPD_KW
 
-	p->cclk = simple_strtoul(vpd + v2, NULL, 10);
 	memcpy(p->id, v->id_data, ID_LEN);
 	strim(p->id);
 	memcpy(p->ec, vpd + ec, EC_LEN);
-- 
1.5.4


^ permalink raw reply related

* [PATCH 03/12] cxgb4: set the number of queues before device registration
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-3-git-send-email-dm@chelsio.com>

The number of queues is known early, move the calls to
netif_set_real_num_[rt]x_queues before register_netdev.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4_main.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 953d62a..3012a8a 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -2717,10 +2717,6 @@ static int cxgb_open(struct net_device *dev)
 			return err;
 	}
 
-	netif_set_real_num_tx_queues(dev, pi->nqsets);
-	err = netif_set_real_num_rx_queues(dev, pi->nqsets);
-	if (err)
-		return err;
 	err = link_start(dev);
 	if (!err)
 		netif_tx_start_all_queues(dev);
@@ -3733,6 +3729,10 @@ static int __devinit init_one(struct pci_dev *pdev,
 	 * register at least one net device.
 	 */
 	for_each_port(adapter, i) {
+		pi = adap2pinfo(adapter, i);
+		netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets);
+		netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets);
+
 		err = register_netdev(adapter->port[i]);
 		if (err)
 			dev_warn(&pdev->dev,
@@ -3747,7 +3747,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 				adapter->name = adapter->port[i]->name;
 
 			__set_bit(i, &adapter->registered_device_map);
-			adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
+			adapter->chan_map[pi->tx_chan] = i;
 		}
 	}
 	if (!adapter->registered_device_map) {
-- 
1.5.4


^ permalink raw reply related

* [PATCH 09/12] cxgb4: remove a bitmap
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-9-git-send-email-dm@chelsio.com>

The driver keeps a bitmap of the netdevs it registered so it knows what to
unregister later.  Remove that and look at reg_state instead.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4.h      |    1 -
 drivers/net/cxgb4/cxgb4_main.c |    3 +--
 2 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index 9caf95f..01d49ea 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -482,7 +482,6 @@ struct adapter {
 	void __iomem *regs;
 	struct pci_dev *pdev;
 	struct device *pdev_dev;
-	unsigned long registered_device_map;
 	unsigned int fn;
 	unsigned int flags;
 
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 4d7565c..059c1ee 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -3725,7 +3725,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 		err = register_netdev(adapter->port[i]);
 		if (err)
 			break;
-		__set_bit(i, &adapter->registered_device_map);
 		adapter->chan_map[pi->tx_chan] = i;
 		print_port_info(adapter->port[i]);
 	}
@@ -3785,7 +3784,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
 			detach_ulds(adapter);
 
 		for_each_port(adapter, i)
-			if (test_bit(i, &adapter->registered_device_map))
+			if (adapter->port[i]->reg_state == NETREG_REGISTERED)
 				unregister_netdev(adapter->port[i]);
 
 		if (adapter->debugfs_root)
-- 
1.5.4


^ permalink raw reply related

* [PATCH 06/12] cxgb4: allocate more space for MSI-X interrupt names
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-6-git-send-email-dm@chelsio.com>

Currently MSI-X names for netdevs with long names are truncated in
/proc/interrupts due to insufficient space.  Use IFNAMSIZ to size the
needed space.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/cxgb4.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index 3d4253d..f3d9f64 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -497,7 +497,7 @@ struct adapter {
 
 	struct {
 		unsigned short vec;
-		char desc[14];
+		char desc[IFNAMSIZ + 10];
 	} msix_info[MAX_INGQ + 1];
 
 	struct sge sge;
-- 
1.5.4


^ permalink raw reply related

* [PATCH 10/12] cxgb4: add const to static arrays
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-10-git-send-email-dm@chelsio.com>

Patch originally from Joe Perches, unmodified.

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/t4_hw.c |   48 ++++++++++++++++++++++----------------------
 1 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index 6af0452..c7fb549 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -183,7 +183,7 @@ static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
 int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
 		    void *rpl, bool sleep_ok)
 {
-	static int delay[] = {
+	static const int delay[] = {
 		1, 1, 3, 5, 10, 10, 20, 50, 100, 200
 	};
 
@@ -917,7 +917,7 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
  */
 static void pcie_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info sysbus_intr_info[] = {
+	static const struct intr_info sysbus_intr_info[] = {
 		{ RNPP, "RXNP array parity error", -1, 1 },
 		{ RPCP, "RXPC array parity error", -1, 1 },
 		{ RCIP, "RXCIF array parity error", -1, 1 },
@@ -925,7 +925,7 @@ static void pcie_intr_handler(struct adapter *adapter)
 		{ RFTP, "RXFT array parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info pcie_port_intr_info[] = {
+	static const struct intr_info pcie_port_intr_info[] = {
 		{ TPCP, "TXPC array parity error", -1, 1 },
 		{ TNPP, "TXNP array parity error", -1, 1 },
 		{ TFTP, "TXFT array parity error", -1, 1 },
@@ -937,7 +937,7 @@ static void pcie_intr_handler(struct adapter *adapter)
 		{ TDUE, "Tx uncorrectable data error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info pcie_intr_info[] = {
+	static const struct intr_info pcie_intr_info[] = {
 		{ MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
 		{ MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
 		{ MSIDATAPERR, "MSI data parity error", -1, 1 },
@@ -989,7 +989,7 @@ static void pcie_intr_handler(struct adapter *adapter)
  */
 static void tp_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info tp_intr_info[] = {
+	static const struct intr_info tp_intr_info[] = {
 		{ 0x3fffffff, "TP parity error", -1, 1 },
 		{ FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
 		{ 0 }
@@ -1006,7 +1006,7 @@ static void sge_intr_handler(struct adapter *adapter)
 {
 	u64 v;
 
-	static struct intr_info sge_intr_info[] = {
+	static const struct intr_info sge_intr_info[] = {
 		{ ERR_CPL_EXCEED_IQE_SIZE,
 		  "SGE received CPL exceeding IQE size", -1, 1 },
 		{ ERR_INVALID_CIDX_INC,
@@ -1051,7 +1051,7 @@ static void sge_intr_handler(struct adapter *adapter)
  */
 static void cim_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info cim_intr_info[] = {
+	static const struct intr_info cim_intr_info[] = {
 		{ PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
 		{ OBQPARERR, "CIM OBQ parity error", -1, 1 },
 		{ IBQPARERR, "CIM IBQ parity error", -1, 1 },
@@ -1061,7 +1061,7 @@ static void cim_intr_handler(struct adapter *adapter)
 		{ TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info cim_upintr_info[] = {
+	static const struct intr_info cim_upintr_info[] = {
 		{ RSVDSPACEINT, "CIM reserved space access", -1, 1 },
 		{ ILLTRANSINT, "CIM illegal transaction", -1, 1 },
 		{ ILLWRINT, "CIM illegal write", -1, 1 },
@@ -1108,7 +1108,7 @@ static void cim_intr_handler(struct adapter *adapter)
  */
 static void ulprx_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info ulprx_intr_info[] = {
+	static const struct intr_info ulprx_intr_info[] = {
 		{ 0x1800000, "ULPRX context error", -1, 1 },
 		{ 0x7fffff, "ULPRX parity error", -1, 1 },
 		{ 0 }
@@ -1123,7 +1123,7 @@ static void ulprx_intr_handler(struct adapter *adapter)
  */
 static void ulptx_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info ulptx_intr_info[] = {
+	static const struct intr_info ulptx_intr_info[] = {
 		{ PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
 		  0 },
 		{ PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
@@ -1145,7 +1145,7 @@ static void ulptx_intr_handler(struct adapter *adapter)
  */
 static void pmtx_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info pmtx_intr_info[] = {
+	static const struct intr_info pmtx_intr_info[] = {
 		{ PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
 		{ PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
 		{ PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
@@ -1167,7 +1167,7 @@ static void pmtx_intr_handler(struct adapter *adapter)
  */
 static void pmrx_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info pmrx_intr_info[] = {
+	static const struct intr_info pmrx_intr_info[] = {
 		{ ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
 		{ PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 },
 		{ OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
@@ -1186,7 +1186,7 @@ static void pmrx_intr_handler(struct adapter *adapter)
  */
 static void cplsw_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info cplsw_intr_info[] = {
+	static const struct intr_info cplsw_intr_info[] = {
 		{ CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
 		{ CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
 		{ TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
@@ -1205,7 +1205,7 @@ static void cplsw_intr_handler(struct adapter *adapter)
  */
 static void le_intr_handler(struct adapter *adap)
 {
-	static struct intr_info le_intr_info[] = {
+	static const struct intr_info le_intr_info[] = {
 		{ LIPMISS, "LE LIP miss", -1, 0 },
 		{ LIP0, "LE 0 LIP error", -1, 0 },
 		{ PARITYERR, "LE parity error", -1, 1 },
@@ -1223,11 +1223,11 @@ static void le_intr_handler(struct adapter *adap)
  */
 static void mps_intr_handler(struct adapter *adapter)
 {
-	static struct intr_info mps_rx_intr_info[] = {
+	static const struct intr_info mps_rx_intr_info[] = {
 		{ 0xffffff, "MPS Rx parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_tx_intr_info[] = {
+	static const struct intr_info mps_tx_intr_info[] = {
 		{ TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 },
 		{ NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
 		{ TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 },
@@ -1237,25 +1237,25 @@ static void mps_intr_handler(struct adapter *adapter)
 		{ FRMERR, "MPS Tx framing error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_trc_intr_info[] = {
+	static const struct intr_info mps_trc_intr_info[] = {
 		{ FILTMEM, "MPS TRC filter parity error", -1, 1 },
 		{ PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 },
 		{ MISCPERR, "MPS TRC misc parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_stat_sram_intr_info[] = {
+	static const struct intr_info mps_stat_sram_intr_info[] = {
 		{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_stat_tx_intr_info[] = {
+	static const struct intr_info mps_stat_tx_intr_info[] = {
 		{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_stat_rx_intr_info[] = {
+	static const struct intr_info mps_stat_rx_intr_info[] = {
 		{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
 		{ 0 }
 	};
-	static struct intr_info mps_cls_intr_info[] = {
+	static const struct intr_info mps_cls_intr_info[] = {
 		{ MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
 		{ MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
 		{ HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
@@ -1354,7 +1354,7 @@ static void ma_intr_handler(struct adapter *adap)
  */
 static void smb_intr_handler(struct adapter *adap)
 {
-	static struct intr_info smb_intr_info[] = {
+	static const struct intr_info smb_intr_info[] = {
 		{ MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
 		{ MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
 		{ SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
@@ -1370,7 +1370,7 @@ static void smb_intr_handler(struct adapter *adap)
  */
 static void ncsi_intr_handler(struct adapter *adap)
 {
-	static struct intr_info ncsi_intr_info[] = {
+	static const struct intr_info ncsi_intr_info[] = {
 		{ CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
 		{ MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
 		{ TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
@@ -1408,7 +1408,7 @@ static void xgmac_intr_handler(struct adapter *adap, int port)
  */
 static void pl_intr_handler(struct adapter *adap)
 {
-	static struct intr_info pl_intr_info[] = {
+	static const struct intr_info pl_intr_info[] = {
 		{ FATALPERR, "T4 fatal parity error", -1, 1 },
 		{ PERRVFID, "PL VFID_MAP parity error", -1, 1 },
 		{ 0 }
-- 
1.5.4


^ permalink raw reply related

* [PATCH 12/12] cxgb4: NUMA-aware Tx queue allocations
From: Dimitris Michailidis @ 2010-12-15  7:36 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1292398615-26527-12-git-send-email-dm@chelsio.com>

Allocate Tx queue memory on the node indicated by the new
netdev_queue_numa_node_read.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
---
 drivers/net/cxgb4/sge.c |   17 ++++++++++-------
 1 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index cc0b997..311471b 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -579,6 +579,7 @@ static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
  *	@phys: the physical address of the allocated ring
  *	@metadata: address of the array holding the SW state for the ring
  *	@stat_size: extra space in HW ring for status information
+ *	@node: preferred node for memory allocations
  *
  *	Allocates resources for an SGE descriptor ring, such as Tx queues,
  *	free buffer lists, or response queues.  Each SGE ring requires
@@ -590,7 +591,7 @@ static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
  */
 static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size,
 			size_t sw_size, dma_addr_t *phys, void *metadata,
-			size_t stat_size)
+			size_t stat_size, int node)
 {
 	size_t len = nelem * elem_size + stat_size;
 	void *s = NULL;
@@ -599,7 +600,7 @@ static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size,
 	if (!p)
 		return NULL;
 	if (sw_size) {
-		s = kcalloc(nelem, sw_size, GFP_KERNEL);
+		s = kzalloc_node(nelem * sw_size, GFP_KERNEL, node);
 
 		if (!s) {
 			dma_free_coherent(dev, len, p, *phys);
@@ -1982,7 +1983,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
 	iq->size = roundup(iq->size, 16);
 
 	iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0,
-			      &iq->phys_addr, NULL, 0);
+			      &iq->phys_addr, NULL, 0, NUMA_NO_NODE);
 	if (!iq->desc)
 		return -ENOMEM;
 
@@ -2008,7 +2009,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
 		fl->size = roundup(fl->size, 8);
 		fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64),
 				      sizeof(struct rx_sw_desc), &fl->addr,
-				      &fl->sdesc, STAT_LEN);
+				      &fl->sdesc, STAT_LEN, NUMA_NO_NODE);
 		if (!fl->desc)
 			goto fl_nomem;
 
@@ -2095,7 +2096,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
 
 	txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
 			sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
-			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
+			netdev_queue_numa_node_read(netdevq));
 	if (!txq->q.desc)
 		return -ENOMEM;
 
@@ -2147,7 +2149,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
 
 	txq->q.desc = alloc_ring(adap->pdev_dev, nentries,
 				 sizeof(struct tx_desc), 0, &txq->q.phys_addr,
-				 NULL, 0);
+				 NULL, 0, NUMA_NO_NODE);
 	if (!txq->q.desc)
 		return -ENOMEM;
 
@@ -2198,7 +2200,8 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
 
 	txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size,
 			sizeof(struct tx_desc), sizeof(struct tx_sw_desc),
-			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN);
+			&txq->q.phys_addr, &txq->q.sdesc, STAT_LEN,
+			NUMA_NO_NODE);
 	if (!txq->q.desc)
 		return -ENOMEM;
 
-- 
1.5.4


^ permalink raw reply related

* [2.6.37-rc5] Build error on parisc.
From: Tetsuo Handa @ 2010-12-15  8:01 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev

[2.6.37-rc5] Build error on parisc.

Commit 5635c10d "net: make sure struct dst_entry refcount is aligned on 64 bytes"
uses manual padding. I triggered BUILD_BUG_ON() when using
http://kernel.org/pub/tools/crosstool/files/bin/i686/4.5.1/i686-gcc-4.5.1-nolibc_hppa64-linux.tar.bz2 .

  make -s CROSS_COMPILE=hppa64-linux- ARCH=parisc

  include/net/dst.h: In function 'dst_hold':
  include/net/dst.h:161:2: error: negative width in bit-field '<anonymous>'

I think below patch can fix the error but that commit says that we cannot use
__atribute((aligned)). Why?

diff --git a/include/net/dst.h b/include/net/dst.h
index ffe9cb7..02df303 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -62,8 +62,6 @@ struct dst_entry {
 	struct hh_cache		*hh;
 #ifdef CONFIG_XFRM
 	struct xfrm_state	*xfrm;
-#else
-	void			*__pad1;
 #endif
 	int			(*input)(struct sk_buff*);
 	int			(*output)(struct sk_buff*);
@@ -74,23 +72,15 @@ struct dst_entry {
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	__u32			tclassid;
-#else
-	__u32			__pad2;
-#endif
-
-
-	/*
-	 * Align __refcnt to a 64 bytes alignment
-	 * (L1_CACHE_SIZE would be too much)
-	 */
-#ifdef CONFIG_64BIT
-	long			__pad_to_align_refcnt[1];
 #endif
 	/*
 	 * __refcnt wants to be on a different cache line from
 	 * input/output/ops or performance tanks badly
+	 *
+	 * Align __refcnt to a 64 bytes alignment
+	 * (L1_CACHE_SIZE would be too much)
 	 */
-	atomic_t		__refcnt;	/* client references	*/
+	atomic_t		__refcnt __aligned(64);	/* client references */
 	int			__use;
 	unsigned long		lastuse;
 	union {
@@ -154,11 +144,6 @@ dst_metric_locked(struct dst_entry *dst, int metric)
 
 static inline void dst_hold(struct dst_entry * dst)
 {
-	/*
-	 * If your kernel compilation stops here, please check
-	 * __pad_to_align_refcnt declaration in struct dst_entry
-	 */
-	BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63);
 	atomic_inc(&dst->__refcnt);
 }
 

^ permalink raw reply related

* |PATCH net-next-2.6] ifb: use netif_receive_skb() instead of netif_rx()
From: Eric Dumazet @ 2010-12-15  8:39 UTC (permalink / raw)
  To: Changli Gao
  Cc: Jamal Hadi Salim, David S. Miller, Stephen Hemminger, Tom Herbert,
	Jiri Pirko, netdev, netem
In-Reply-To: <AANLkTi=TuZNTXTBxmLqu0yyF=f0xM3CQyr_stRHerv6r@mail.gmail.com>

In ri_tasklet(), we run from softirq, so can directly handle packet
through netif_receive_skb() instead of netif_rx().
There is no risk of recursion.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 drivers/net/ifb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index bfa03db..a44901b 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -96,7 +96,7 @@ static void ri_tasklet(unsigned long dev)
 			dev_queue_xmit(skb);
 		} else if (from & AT_INGRESS) {
 			skb_pull(skb, skb->dev->hard_header_len);
-			netif_rx(skb);
+			netif_receive_skb(skb);
 		} else
 			BUG();
 	}



^ permalink raw reply related

* [OOPS]e1000e .ko 1.0.2-k2
From: Jeff Wu @ 2010-12-15  8:43 UTC (permalink / raw)
  To: netdev

Hi ,

iozone test for our distributed file system ,
we detect a oops(see below ,logs).
1. OS ubuntu 10.04 server x86_64
2. test tool iozone
3. ethernet card driver : e1000e



[181174.958159] 24188 total pagecache pages
[181174.958161] 21082 pages in swap cache
[181174.958162] Swap cache stats: add 118851, delete 97769, find
5970/11916
[181174.958164] Free swap  = 3649128kB
[181174.958165] Total swap = 3905528kB
[181174.967050] 1032192 pages RAM
[181174.967052] 43435 pages reserved
[181174.967053] 7509 pages shared
[181174.967054] 978870 pages non-shared
[181174.967056] SLUB: Unable to allocate memory on node -1 (gfp=0x20)
[181174.967058]   cache: kmalloc-4096, object size: 4096, buffer size:
4096, default order: 3, min order: 0
[181174.967060]   node 0: slabs: 670, objs: 1685, free: 0
[181174.967116] swapper: page allocation failure. order:0, mode:0x4020
[181174.967120] Pid: 0, comm: swapper Not tainted 2.6.32-21-server
#32-Ubuntu
[181174.967121] Call Trace:
[181174.967123]  <IRQ>  [<ffffffff810f97de>] __alloc_pages_slowpath
+0x56e/0x580
[181174.967131]  [<ffffffff810f9961>] __alloc_pages_nodemask+0x171/0x180
[181174.967134]  [<ffffffff8112c597>] alloc_pages_current+0x87/0xd0
[181174.967137]  [<ffffffff81132547>] new_slab+0x2f7/0x310
[181174.967140]  [<ffffffff81134dc1>] __slab_alloc+0x201/0x2d0
[181174.967143]  [<ffffffff814668d6>] ? __netdev_alloc_skb+0x36/0x60
[181174.967146]  [<ffffffff81135d9f>] __kmalloc_node_track_caller
+0xaf/0x160
[181174.967148]  [<ffffffff814668d6>] ? __netdev_alloc_skb+0x36/0x60
[181174.967150]  [<ffffffff81466590>] __alloc_skb+0x80/0x190
[181174.967153]  [<ffffffff814668d6>] __netdev_alloc_skb+0x36/0x60
[181174.967162]  [<ffffffffa00136e1>] e1000_alloc_rx_buffers+0x2b1/0x320
[e1000e]
[181174.967165]  [<ffffffff814708a9>] ? napi_gro_receive+0x39/0x50
[181174.967170]  [<ffffffffa001394f>] e1000_clean_rx_irq+0x1ff/0x460
[e1000e]
[181174.967175]  [<ffffffffa000ff34>] ? e1000_clean_tx_irq+0x104/0x3a0
[e1000e]
[181174.967180]  [<ffffffffa001256e>] e1000_clean+0x7e/0x280 [e1000e]
[181174.967182]  [<ffffffff81470a7f>] net_rx_action+0x10f/0x250
[181174.967186]  [<ffffffff8106e257>] __do_softirq+0xb7/0x1e0
[181174.967188]  [<ffffffff810c4880>] ? handle_IRQ_event+0x60/0x170
[181174.967192]  [<ffffffff810142ec>] call_softirq+0x1c/0x30
[181174.967194]  [<ffffffff81015cb5>] do_softirq+0x65/0xa0
[181174.967196]  [<ffffffff8106e0f5>] irq_exit+0x85/0x90
[181174.967199]  [<ffffffff8155c615>] do_IRQ+0x75/0xf0
[181174.967202]  [<ffffffff81013b13>] ret_from_intr+0x0/0x11
[181174.967203]  <EOI>  [<ffffffff8101b551>] ? mwait_idle+0x71/0xd0
[181174.967208]  [<ffffffff8155a2ea>] ? atomic_notifier_call_chain
+0x1a/0x20
[181174.967211]  [<ffffffff81011e63>] ? cpu_idle+0xb3/0x110
[181174.967214]  [<ffffffff8154f580>] ? start_secondary+0xa8/0xaa
[181174.967216] Mem-Info:
[181174.967217] Node 0 DMA per-cpu:
[181174.967219] CPU    0: hi:    0, btch:   1 usd:   0
[181174.967221] CPU    1: hi:    0, btch:   1 usd:   0
[181174.967223] CPU    2: hi:    0, btch:   1 usd:   0
[181174.967224] CPU    3: hi:    0, btch:   1 usd:   0
[181174.967225] Node 0 DMA32 per-cpu:
[181174.967227] CPU    0: hi:  186, btch:  31 usd:  91
[181174.967229] CPU    1: hi:  186, btch:  31 usd:  30
[181174.967231] CPU    2: hi:  186, btch:  31 usd: 100
[181174.967232] CPU    3: hi:  186, btch:  31 usd:   0
[181174.967233] Node 0 Normal per-cpu:
[181174.967235] CPU    0: hi:  186, btch:  31 usd:  31
[181174.967237] CPU    1: hi:  186, btch:  31 usd:  30
[181174.967238] CPU    2: hi:  186, btch:  31 usd:  44
[181174.967240] CPU    3: hi:  186, btch:  31 usd:   5



Jeff .C.P.Wu



^ permalink raw reply

* Re: |PATCH net-next-2.6] ifb: use netif_receive_skb() instead of netif_rx()
From: Changli Gao @ 2010-12-15  8:51 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Jamal Hadi Salim, David S. Miller, Stephen Hemminger, Tom Herbert,
	Jiri Pirko, netdev, netem
In-Reply-To: <1292402398.3427.6.camel@edumazet-laptop>

On Wed, Dec 15, 2010 at 4:39 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> In ri_tasklet(), we run from softirq, so can directly handle packet
> through netif_receive_skb() instead of netif_rx().
> There is no risk of recursion.
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---

Acked-by: Changli Gao <xiaosuo@gmail.com>


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

^ permalink raw reply

* [PATCH 5/5 v3] net: add old_queue_mapping into skb->cb
From: Changli Gao @ 2010-12-15  8:48 UTC (permalink / raw)
  To: Jamal Hadi Salim
  Cc: David S. Miller, Stephen Hemminger, Eric Dumazet, Tom Herbert,
	Jiri Pirko, netdev, netem, Changli Gao

For the skbs returned from ifb, we should use the queue_mapping
saved before ifb.

We save old queue_mapping in old_queue_mapping just before calling 
dev_queue_xmit, and restore the old_queue_mapping to queue_mapping
just before reinjecting the skb.

dev_pick_tx() use the current queue_mapping for the skbs reinjected
by ifb.

A new struct dev_skb_cb is added, and valid in qdisc and gso layer.
The original qdisc_skb_cb and DEV_GSO_CB use dev_skb_cb as the first
member.

netem_skb_cb is changed to contain qdisc_skb_cb.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
v3: use the method from Eric to allocate memory from skb->cb. Thank him.
v2: save old_queue_mapping in skb->cb
 drivers/net/ifb.c         |    1 +
 include/linux/netdevice.h |   10 ++++++++++
 include/net/sch_generic.h |    3 ++-
 net/core/dev.c            |   21 ++++++++++++++++-----
 net/sched/act_mirred.c    |    1 +
 net/sched/sch_netem.c     |    8 ++++----
 6 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 918a38e..ff01795 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -92,6 +92,7 @@ static void ri_tasklet(unsigned long arg)
 		u64_stats_update_end(&qp->syncp);
 		skb->skb_iif = dev->ifindex;
 
+		skb->queue_mapping = dev_skb_cb(skb)->old_queue_mapping;
 		if (from & AT_EGRESS) {
 			dev_queue_xmit(skb);
 		} else if (from & AT_INGRESS) {
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d31bc3c..6f128e3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1295,6 +1295,16 @@ struct napi_gro_cb {
 
 #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
 
+struct dev_skb_cb {
+	u16		old_queue_mapping;
+};
+
+static inline struct dev_skb_cb *dev_skb_cb(struct sk_buff *skb)
+{
+	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct dev_skb_cb));
+	return (struct dev_skb_cb *)skb->cb;
+}
+
 struct packet_type {
 	__be16			type;	/* This is really htons(ether_type). */
 	struct net_device	*dev;	/* NULL is wildcarded here	     */
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index ea1f8a8..52c32e3 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -198,8 +198,8 @@ struct tcf_proto {
 };
 
 struct qdisc_skb_cb {
+	struct dev_skb_cb	dev_cb; /* must be the first */
 	unsigned int		pkt_len;
-	char			data[];
 };
 
 static inline int qdisc_qlen(struct Qdisc *q)
@@ -209,6 +209,7 @@ static inline int qdisc_qlen(struct Qdisc *q)
 
 static inline struct qdisc_skb_cb *qdisc_skb_cb(struct sk_buff *skb)
 {
+	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct qdisc_skb_cb));
 	return (struct qdisc_skb_cb *)skb->cb;
 }
 
diff --git a/net/core/dev.c b/net/core/dev.c
index d28b3a0..2b8f863 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1901,10 +1901,15 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 }
 
 struct dev_gso_cb {
-	void (*destructor)(struct sk_buff *skb);
+	struct dev_skb_cb	dev_cb; /* must be the first */
+	void			(*destructor)(struct sk_buff *skb);
 };
 
-#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
+static inline struct dev_gso_cb *dev_gso_cb(struct sk_buff *skb)
+{
+	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct dev_gso_cb));
+	return (struct dev_gso_cb *)skb->cb;
+}
 
 static void dev_gso_skb_destructor(struct sk_buff *skb)
 {
@@ -1918,7 +1923,7 @@ static void dev_gso_skb_destructor(struct sk_buff *skb)
 		kfree_skb(nskb);
 	} while (skb->next);
 
-	cb = DEV_GSO_CB(skb);
+	cb = dev_gso_cb(skb);
 	if (cb->destructor)
 		cb->destructor(skb);
 }
@@ -1947,7 +1952,7 @@ static int dev_gso_segment(struct sk_buff *skb)
 		return PTR_ERR(segs);
 
 	skb->next = segs;
-	DEV_GSO_CB(skb)->destructor = skb->destructor;
+	dev_gso_cb(skb)->destructor = skb->destructor;
 	skb->destructor = dev_gso_skb_destructor;
 
 	return 0;
@@ -2103,7 +2108,7 @@ gso:
 
 out_kfree_gso_skb:
 	if (likely(skb->next == NULL))
-		skb->destructor = DEV_GSO_CB(skb)->destructor;
+		skb->destructor = dev_gso_cb(skb)->destructor;
 out_kfree_skb:
 	kfree_skb(skb);
 out:
@@ -2190,6 +2195,12 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
 	int queue_index;
 	const struct net_device_ops *ops = dev->netdev_ops;
 
+#ifdef CONFIG_NET_CLS_ACT
+	if (skb->tc_verd & TC_NCLS) {
+		queue_index = skb_get_queue_mapping(skb);
+		queue_index = dev_cap_txqueue(dev, queue_index);
+	} else
+#endif
 	if (dev->real_num_tx_queues == 1)
 		queue_index = 0;
 	else if (ops->ndo_select_queue) {
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 0c311be..419e82f 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -197,6 +197,7 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
 
 	skb2->skb_iif = skb->dev->ifindex;
 	skb2->dev = dev;
+	dev_skb_cb(skb2)->old_queue_mapping = skb->queue_mapping;
 	dev_queue_xmit(skb2);
 	err = 0;
 
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index e5593c0..c2cf72f 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -77,14 +77,14 @@ struct netem_sched_data {
 
 /* Time stamp put into socket buffer control block */
 struct netem_skb_cb {
-	psched_time_t	time_to_send;
+	struct qdisc_skb_cb	qdisc_cb; /* must be the first */
+	psched_time_t		time_to_send;
 };
 
 static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
 {
-	BUILD_BUG_ON(sizeof(skb->cb) <
-		sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb));
-	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
+	BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct netem_skb_cb));
+	return (struct netem_skb_cb *)skb->cb;
 }
 
 /* init_crandom - initialize correlated random number generator

^ permalink raw reply related

* [PATCH net-next-2.6 v2 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Bhupesh Sharma @ 2010-12-15  9:58 UTC (permalink / raw)
  To: netdev; +Cc: Socketcan-core, Bhupesh Sharma

Bosch C_CAN controller is a full-CAN implementation which is compliant
to CAN protocol version 2.0 part A and B. Bosch C_CAN user manual can be
obtained from:
http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf

This patch adds the support for this controller.
The following are the design choices made while writing the controller driver:
1. Interface Register set IF1 has be used only in the current design.
2. Out of the 32 Message objects available, 16 are kept aside for RX purposes
   and the rest for TX purposes.
3. NAPI implementation is such that both the TX and RX paths function in
   polling mode.

Changes since V1:
1. Implemented C_CAN as a platform driver with means of providing the
   platform details and register offsets which may vary for different SoCs
   through platform data struct.
2. Implemented NAPI.
3. Removed memcpy calls globally.
4. Implemented CAN_CTRLMODE_*
5. Implemented and used priv->can.do_get_berr_counter.
6. Implemented c_can registers as a struct instead of enum.
7. Improved the TX path by implementing routines to get next Tx and echo msg
   objects.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@st.com>
---
 drivers/net/can/Kconfig  |    7 +
 drivers/net/can/Makefile |    1 +
 drivers/net/can/c_can.c  | 1217 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1225 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/can/c_can.c

diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 9d9e453..25d9d2e 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -41,6 +41,13 @@ config CAN_AT91
 	---help---
 	  This is a driver for the SoC CAN controller in Atmel's AT91SAM9263.
 
+config CAN_C_CAN
+	tristate "Bosch C_CAN controller"
+	depends on CAN_DEV
+	---help---
+	  If you say yes to this option, support will be included for the
+	  Bosch C_CAN controller.
+
 config CAN_TI_HECC
 	depends on CAN_DEV && ARCH_OMAP3
 	tristate "TI High End CAN Controller"
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 0057537..b6cbe74 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -12,6 +12,7 @@ obj-y				+= usb/
 obj-$(CONFIG_CAN_SJA1000)	+= sja1000/
 obj-$(CONFIG_CAN_MSCAN)		+= mscan/
 obj-$(CONFIG_CAN_AT91)		+= at91_can.o
+obj-$(CONFIG_CAN_C_CAN)		+= c_can.o
 obj-$(CONFIG_CAN_TI_HECC)	+= ti_hecc.o
 obj-$(CONFIG_CAN_MCP251X)	+= mcp251x.o
 obj-$(CONFIG_CAN_BFIN)		+= bfin_can.o
diff --git a/drivers/net/can/c_can.c b/drivers/net/can/c_can.c
new file mode 100644
index 0000000..c281c17
--- /dev/null
+++ b/drivers/net/can/c_can.c
@@ -0,0 +1,1217 @@
+/*
+ * CAN bus driver for Bosch C_CAN controller
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Bhupesh Sharma <bhupesh.sharma@st.com>
+ *
+ * Borrowed heavily from the C_CAN driver originally written by:
+ * Copyright (C) 2007
+ * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
+ * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
+ *
+ * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
+ * Bosch C_CAN user manual can be obtained from:
+ * http://www.semiconductors.bosch.de/pdf/Users_Manual_C_CAN.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#define DRV_NAME "c_can"
+
+/* control register */
+#define CONTROL_TEST		(1 << 7)
+#define CONTROL_CCE		(1 << 6)
+#define CONTROL_DISABLE_AR	(1 << 5)
+#define CONTROL_ENABLE_AR	(0 << 5)
+#define CONTROL_EIE		(1 << 3)
+#define CONTROL_SIE		(1 << 2)
+#define CONTROL_IE		(1 << 1)
+#define CONTROL_INIT		(1 << 0)
+
+/* test register */
+#define TEST_RX			(1 << 7)
+#define TEST_TX1		(1 << 6)
+#define TEST_TX2		(1 << 5)
+#define TEST_LBACK		(1 << 4)
+#define TEST_SILENT		(1 << 3)
+#define TEST_BASIC		(1 << 2)
+
+/* status register */
+#define STATUS_BOFF		(1 << 7)
+#define STATUS_EWARN		(1 << 6)
+#define STATUS_EPASS		(1 << 5)
+#define STATUS_RXOK		(1 << 4)
+#define STATUS_TXOK		(1 << 3)
+#define STATUS_LEC_MASK		0x07
+#define LEC_STUFF_ERROR		1
+#define LEC_FORM_ERROR		2
+#define LEC_ACK_ERROR		3
+#define LEC_BIT1_ERROR		4
+#define LEC_BIT0_ERROR		5
+#define LEC_CRC_ERROR		6
+
+/* error counter register */
+#define ERR_COUNTER_TEC_MASK	0xff
+#define ERR_COUNTER_TEC_SHIFT	0x0
+#define ERR_COUNTER_REC_SHIFT	8
+#define ERR_COUNTER_REC_MASK	(0x7f << ERR_COUNTER_REC_SHIFT)
+#define ERR_COUNTER_RP_SHIFT	15
+#define ERR_COUNTER_RP_MASK	(0x1 << ERR_COUNTER_RP_SHIFT)
+
+/* bit-timing register */
+#define BTR_BRP_MASK		0x3f
+#define BTR_BRP_SHIFT		0
+#define BTR_SJW_SHIFT		6
+#define BTR_SJW_MASK		(0x3 << BTR_SJW_SHIFT)
+#define BTR_TSEG1_SHIFT		8
+#define BTR_TSEG1_MASK		(0xf << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT		12
+#define BTR_TSEG2_MASK		(0x7 << BTR_TSEG2_SHIFT)
+
+/* brp extension register */
+#define BRP_EXT_BRPE_MASK	0x0f
+#define BRP_EXT_BRPE_SHIFT	0
+
+/* IFx command request */
+#define IF_COMR_BUSY		(1 << 15)
+
+/* IFx command mask */
+#define IF_COMM_WR		(1 << 7)
+#define IF_COMM_MASK		(1 << 6)
+#define IF_COMM_ARB		(1 << 5)
+#define IF_COMM_CONTROL		(1 << 4)
+#define IF_COMM_CLR_INT_PND	(1 << 3)
+#define IF_COMM_TXRQST		(1 << 2)
+#define IF_COMM_DATAA		(1 << 1)
+#define IF_COMM_DATAB		(1 << 0)
+#define IF_COMM_ALL		(IF_COMM_MASK | IF_COMM_ARB | \
+				IF_COMM_CONTROL | IF_COMM_TXRQST | \
+				IF_COMM_DATAA | IF_COMM_DATAB)
+
+/* IFx arbitration */
+#define IF_ARB_MSGVAL		(1 << 15)
+#define IF_ARB_MSGXTD		(1 << 14)
+#define IF_ARB_TRANSMIT		(1 << 13)
+
+/* IFx message control */
+#define IF_MCONT_NEWDAT		(1 << 15)
+#define IF_MCONT_MSGLST		(1 << 14)
+#define IF_MCONT_INTPND		(1 << 13)
+#define IF_MCONT_UMASK		(1 << 12)
+#define IF_MCONT_TXIE		(1 << 11)
+#define IF_MCONT_RXIE		(1 << 10)
+#define IF_MCONT_RMTEN		(1 << 9)
+#define IF_MCONT_TXRQST		(1 << 8)
+#define IF_MCONT_EOB		(1 << 7)
+
+/*
+ * IFx register masks:
+ * allow easy operation on 16-bit registers when the
+ * argument is 32-bit instead
+ */
+#define IFX_WRITE_LOW_16BIT(x)	(x & 0xFFFF)
+#define IFX_WRITE_HIGH_16BIT(x)	((x & 0xFFFF0000) >> 16)
+
+/* message object split */
+#define C_CAN_NO_OF_OBJECTS	31
+#define C_CAN_MSG_OBJ_RX_NUM	16
+#define C_CAN_MSG_OBJ_TX_NUM	16
+
+#define C_CAN_MSG_OBJ_RX_FIRST	0
+#define C_CAN_MSG_OBJ_RX_LAST	(C_CAN_MSG_OBJ_RX_FIRST + \
+				C_CAN_MSG_OBJ_RX_NUM - 1)
+
+#define C_CAN_MSG_OBJ_TX_FIRST	(C_CAN_MSG_OBJ_RX_LAST + 1)
+#define C_CAN_MSG_OBJ_TX_LAST	(C_CAN_MSG_OBJ_TX_FIRST + \
+				C_CAN_MSG_OBJ_TX_NUM - 1)
+#define C_CAN_NEXT_MSG_OBJ_MASK	(C_CAN_MSG_OBJ_TX_NUM - 1)
+#define RECEIVE_OBJECT_BITS	0x0000ffff
+
+/* status interrupt */
+#define STATUS_INTERRUPT	0x8000
+
+/* napi related */
+#define C_CAN_NAPI_WEIGHT	C_CAN_MSG_OBJ_RX_NUM
+
+/* c_can IF registers */
+struct c_can_if_regs {
+	u16 com_reg;
+	u16 com_mask;
+	u16 mask1;
+	u16 mask2;
+	u16 arb1;
+	u16 arb2;
+	u16 msg_cntrl;
+	u16 data_a1;
+	u16 data_a2;
+	u16 data_b1;
+	u16 data_b2;
+	u16 _reserved[13];
+};
+
+/* c_can hardware registers */
+struct c_can_regs {
+	u16 control;
+	u16 status;
+	u16 error_counter;
+	u16 btr;
+	u16 ir;
+	u16 test;
+	u16 brp_ext;
+	u16 _reserved1;
+	struct c_can_if_regs ifreg[2]; /* [0] = IF1 and [1] = IF2 */
+	u16 _reserved2[8];
+	u16 txrqst1;
+	u16 txrqst2;
+	u16 _reserved3[6];
+	u16 newdat1;
+	u16 newdat2;
+	u16 _reserved4[6];
+	u16 intpnd1;
+	u16 intpnd2;
+	u16 _reserved5[6];
+	u16 msgval1;
+	u16 msgval2;
+	u16 _reserved6[6];
+};
+
+/*
+ * c_can error types:
+ * Bus errors (BUS_OFF, ERROR_WARNING, ERROR_PASSIVE) are supported
+ */
+enum c_can_bus_error_types {
+	C_CAN_NO_ERROR = 0,
+	C_CAN_BUS_OFF,
+	C_CAN_ERROR_WARNING,
+	C_CAN_ERROR_PASSIVE
+};
+
+enum c_can_interrupt_mode {
+	ENABLE_MODULE_INTERRUPT = 0,
+	DISABLE_MODULE_INTERRUPT,
+	ENABLE_ALL_INTERRUPTS,
+	DISABLE_ALL_INTERRUPTS
+};
+
+/* c_can private data structure */
+struct c_can_priv {
+	struct can_priv can;	/* must be the first member */
+	struct napi_struct napi;
+	struct net_device *dev;
+	int tx_object;
+	int current_status;
+	int last_status;
+	u16 (*read_reg) (struct c_can_priv *priv, void *reg);
+	void (*write_reg) (struct c_can_priv *priv, void *reg, u16 val);
+	struct c_can_regs __iomem *reg_base;
+	unsigned long irq_flags; /* for request_irq() */
+	unsigned int tx_next;
+	unsigned int tx_echo;
+	struct clk *clk;
+};
+
+static struct can_bittiming_const c_can_bittiming_const = {
+	.name = DRV_NAME,
+	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
+	.tseg1_max = 16,
+	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
+	.tseg2_max = 8,
+	.sjw_max = 4,
+	.brp_min = 1,
+	.brp_max = 1024,	/* 6-bit BRP field + 4-bit BRPE field*/
+	.brp_inc = 1,
+};
+
+static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
+{
+	return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
+			C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+static inline int get_tx_echo_msg_obj(const struct c_can_priv *priv)
+{
+	return (priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) +
+			C_CAN_MSG_OBJ_TX_FIRST;
+}
+
+/* 16-bit c_can registers can be arranged differently in the memory
+ * architecture of different implementations. For example: 16-bit
+ * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
+ * Handle the same by providing a common read/write interface.
+ */
+static u16 c_can_read_reg_aligned_to_16bit(void *reg)
+{
+	return readw(reg);
+}
+
+static void c_can_write_reg_aligned_to_16bit(void *reg, u16 val)
+{
+	writew(val, reg);
+}
+
+static u16 c_can_read_reg_aligned_to_32bit(struct c_can_priv *priv, void *reg)
+{
+	return readw(reg + (u32)reg - (u32)priv->reg_base);
+}
+
+static void c_can_write_reg_aligned_to_32bit(struct c_can_priv *priv,
+					void *reg, u16 val)
+{
+	writew(val, reg + (u32)reg - (u32)priv->reg_base);
+}
+
+static u32 c_can_read_reg32(struct c_can_priv *priv, void *reg)
+{
+	u32 val = priv->read_reg(priv, reg);
+	val |= ((u32) priv->read_reg(priv, reg + 2)) << 16;
+	return val;
+}
+
+static inline int c_can_configure_interrupts(struct c_can_priv *priv,
+					enum c_can_interrupt_mode intr_mode)
+{
+	unsigned int cntrl_save = priv->read_reg(priv,
+						&priv->reg_base->control);
+
+	switch (intr_mode) {
+	case ENABLE_MODULE_INTERRUPT:
+		cntrl_save |= CONTROL_IE;
+		break;
+	case DISABLE_MODULE_INTERRUPT:
+		cntrl_save &= ~CONTROL_IE;
+		break;
+	case ENABLE_ALL_INTERRUPTS:
+		cntrl_save |= (CONTROL_SIE | CONTROL_EIE | CONTROL_IE);
+		break;
+	case DISABLE_ALL_INTERRUPTS:
+		cntrl_save &= ~(CONTROL_EIE | CONTROL_IE | CONTROL_SIE);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	priv->write_reg(priv, &priv->reg_base->control, cntrl_save);
+
+	return 0;
+}
+
+static inline int c_can_object_get(struct net_device *dev,
+					int iface, int objno, int mask)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+	int timeout = (6 / priv->can.clock.freq);
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_mask,
+			IFX_WRITE_LOW_16BIT(mask));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_reg,
+			IFX_WRITE_LOW_16BIT(objno + 1));
+
+	/* as per specs, after writting the message object number in the
+	 * IF command request register the transfer b/w interface
+	 * register and message RAM must be complete in 6 CAN-CLK
+	 * period. The delay accounts for the same
+	 */
+	udelay(timeout);
+	if ((priv->read_reg(priv, &priv->reg_base->ifreg[iface].com_reg)) &
+			IF_COMR_BUSY) {
+		dev_info(dev->dev.parent, "timed out in object get\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static inline int c_can_object_put(struct net_device *dev,
+					int iface, int objno, int mask)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+	int timeout = (6 / priv->can.clock.freq);
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_mask,
+			(IF_COMM_WR | IFX_WRITE_LOW_16BIT(mask)));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].com_reg,
+			IFX_WRITE_LOW_16BIT(objno + 1));
+
+	/* as per specs, after writting the message object number in the
+	 * IF command request register the transfer b/w interface
+	 * register and message RAM must be complete in 6 CAN-CLK
+	 * period. The delay accounts for the same
+	 */
+	udelay(timeout);
+	if ((priv->read_reg(priv, &priv->reg_base->ifreg[iface].com_reg)) &
+			IF_COMR_BUSY) {
+		dev_info(dev->dev.parent, "timed out in object put\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int c_can_write_msg_object(struct net_device *dev,
+			int iface, struct can_frame *frame, int objno)
+{
+	u16 flags = 0;
+	unsigned int id;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	if (frame->can_id & CAN_EFF_FLAG) {
+		id = frame->can_id & CAN_EFF_MASK;
+		flags |= IF_ARB_MSGXTD;
+	} else
+		id = ((frame->can_id & CAN_SFF_MASK) << 18);
+
+	if (!(frame->can_id & CAN_RTR_FLAG))
+		flags |= IF_ARB_TRANSMIT;
+
+	flags |= IF_ARB_MSGVAL;
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1,
+				IFX_WRITE_LOW_16BIT(id));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2, flags |
+				IFX_WRITE_HIGH_16BIT(id));
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].data_a1,
+			(*(u16 *)(frame->data)));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].data_a2,
+			(*(u32 *)(frame->data)) >> 16);
+
+	if (frame->can_dlc > 4) {
+		priv->write_reg(priv, &priv->reg_base->ifreg[iface].data_b1,
+			(*(u16 *)(frame->data + 4)));
+		priv->write_reg(priv, &priv->reg_base->ifreg[iface].data_b2,
+			(*(u32 *)(frame->data + 4)) >> 16);
+	} else
+		*(u32 *)(frame->data + 4) = 0;
+
+	return frame->can_dlc;
+}
+
+static int c_can_read_msg_object(struct net_device *dev, int iface, int objno)
+{
+	u16 flags;
+	int ctrl;
+	unsigned int val, data;
+	struct c_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct sk_buff *skb;
+	struct can_frame *frame;
+
+	skb = alloc_can_skb(dev, &frame);
+	if (!skb) {
+		stats->rx_dropped++;
+		return -ENOMEM;
+	}
+
+	val = c_can_object_get(dev, iface, objno, IF_COMM_ALL &
+						~IF_COMM_TXRQST);
+	if (val < 0)
+		return val;
+
+	ctrl = priv->read_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl);
+	if (ctrl & IF_MCONT_MSGLST) {
+		stats->rx_errors++;
+		dev_info(dev->dev.parent, "msg lost in buffer %d\n", objno);
+	}
+
+	frame->can_dlc = get_can_dlc(ctrl & 0x0F);
+	data = priv->read_reg(priv, &priv->reg_base->ifreg[iface].data_a1) |
+		(priv->read_reg(priv, &priv->reg_base->ifreg[iface].data_a2) <<
+			16);
+	*(u32 *)(frame->data) = data;
+	if (frame->can_dlc > 4) {
+		data = priv->read_reg(priv,
+				&priv->reg_base->ifreg[iface].data_b1) |
+			(priv->read_reg(priv,
+				&priv->reg_base->ifreg[iface].data_b2) <<
+				16);
+		*(u32 *)(frame->data + 4) = data;
+	} else
+		*(u32 *)(frame->data + 4) = 0;
+
+	flags =	priv->read_reg(priv, &priv->reg_base->ifreg[iface].arb2);
+	val = priv->read_reg(priv, &priv->reg_base->ifreg[iface].arb1) |
+		(flags << 16);
+
+	if (flags & IF_ARB_MSGXTD)
+		frame->can_id = (val & CAN_EFF_MASK) | CAN_EFF_FLAG;
+	else
+		frame->can_id = (val >> 18) & CAN_SFF_MASK;
+
+	if (flags & IF_ARB_TRANSMIT)
+		frame->can_id |= CAN_RTR_FLAG;
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl, ctrl &
+			~(IF_MCONT_MSGLST | IF_MCONT_INTPND | IF_MCONT_NEWDAT));
+
+	val = c_can_object_put(dev, iface, objno, IF_COMM_CONTROL);
+	if (val < 0)
+		return val;
+
+	netif_receive_skb(skb);
+
+	stats->rx_packets++;
+	stats->rx_bytes += frame->can_dlc;
+
+	return 0;
+}
+
+static int c_can_setup_receive_object(struct net_device *dev, int iface,
+					int objno, unsigned int mask,
+					unsigned int id, unsigned int mcont)
+{
+	int ret;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].mask1,
+			IFX_WRITE_LOW_16BIT(mask));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].mask2,
+			IFX_WRITE_HIGH_16BIT(mask));
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1,
+			IFX_WRITE_LOW_16BIT(id));
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2,
+			(IF_ARB_MSGVAL | IFX_WRITE_HIGH_16BIT(id)));
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl, mcont);
+	ret = c_can_object_put(dev, iface, objno, IF_COMM_ALL &
+						~IF_COMM_TXRQST);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev->dev.parent, "obj no:%d, msgval:0x%08x\n", objno,
+			c_can_read_reg32(priv, &priv->reg_base->msgval1));
+
+	return 0;
+}
+
+static int c_can_inval_msg_object(struct net_device *dev, int iface, int objno)
+{
+	int ret;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb1, 0);
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].arb2, 0);
+	priv->write_reg(priv, &priv->reg_base->ifreg[iface].msg_cntrl, 0);
+
+	ret = c_can_object_put(dev, iface, objno,
+				IF_COMM_ARB | IF_COMM_CONTROL);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev->dev.parent, "obj no:%d, msgval:0x%08x\n", objno,
+			c_can_read_reg32(priv, &priv->reg_base->msgval1));
+
+	return 0;
+}
+
+static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
+					struct net_device *dev)
+{
+	u32 val;
+	u32 msg_obj_no;
+	struct c_can_priv *priv = netdev_priv(dev);
+	struct can_frame *frame = (struct can_frame *)skb->data;
+
+	if (can_dropped_invalid_skb(dev, skb))
+		return NETDEV_TX_OK;
+
+	msg_obj_no = get_tx_next_msg_obj(priv);
+
+	/* prepare message object for transmission */
+	val = c_can_write_msg_object(dev, 0, frame, msg_obj_no);
+
+	/* enable interrupt for this message object */
+	priv->write_reg(priv, &priv->reg_base->ifreg[0].msg_cntrl,
+			IF_MCONT_TXIE | IF_MCONT_TXRQST | IF_MCONT_EOB |
+			(val & 0xf));
+	val = c_can_object_put(dev, 0, msg_obj_no, IF_COMM_ALL);
+	if (val < 0)
+		return val;
+
+	can_put_echo_skb(skb, dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+
+	priv->tx_next++;
+	if ((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) == 0)
+		netif_stop_queue(dev);
+
+	return NETDEV_TX_OK;
+}
+
+static int c_can_set_bittiming(struct net_device *dev)
+{
+	unsigned int reg_btr, reg_brpe, ctrl_save;
+	u8 brp, brpe, sjw, tseg1, tseg2;
+	u32 ten_bit_brp;
+	struct c_can_priv *priv = netdev_priv(dev);
+	const struct can_bittiming *bt = &priv->can.bittiming;
+
+	/* c_can provides a 6-bit brp and 4-bit brpe fields */
+	ten_bit_brp = bt->brp - 1;
+	brp = ten_bit_brp & BTR_BRP_MASK;
+	brpe = ten_bit_brp >> 6;
+
+	sjw = bt->sjw - 1;
+	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+	tseg2 = bt->phase_seg2 - 1;
+
+	reg_btr = ((brp) | (sjw << BTR_SJW_SHIFT) | (tseg1 << BTR_TSEG1_SHIFT) |
+			(tseg2 << BTR_TSEG2_SHIFT));
+
+	reg_brpe = brpe & BRP_EXT_BRPE_MASK;
+
+	dev_dbg(dev->dev.parent,
+			"brp = %d, brpe = %d, sjw = %d, seg1 = %d, seg2 = %d\n",
+			brp, brpe, sjw, tseg1, tseg2);
+	dev_dbg(dev->dev.parent, "setting BTR to %04x\n", reg_btr);
+	dev_dbg(dev->dev.parent, "setting BRPE to %04x\n", reg_brpe);
+
+	ctrl_save = priv->read_reg(priv, &priv->reg_base->control);
+	priv->write_reg(priv, &priv->reg_base->control,
+			ctrl_save | CONTROL_CCE | CONTROL_INIT);
+	priv->write_reg(priv, &priv->reg_base->btr, reg_btr);
+	priv->write_reg(priv, &priv->reg_base->brp_ext, reg_brpe);
+	priv->write_reg(priv, &priv->reg_base->control, ctrl_save);
+
+	return 0;
+}
+
+/*
+ * Configure C_CAN message objects for Tx and Rx purposes:
+ * C_CAN provides a total of 32 message objects that can be configured
+ * either for Tx or Rx purposes. Here the first 16 message objects are used as
+ * a reception FIFO. The end of reception FIFO is signified by the EoB bit
+ * being SET. The remaining 16 message objects are kept aside for Tx purposes.
+ * See user guide document for further details on configuring message
+ * objects.
+ */
+static int c_can_configure_msg_objects(struct net_device *dev)
+{
+	int i;
+
+	/* first invalidate all message objects */
+	for (i = 0; i <= C_CAN_NO_OF_OBJECTS; i++)
+		c_can_inval_msg_object(dev, 0, i);
+
+	/* setup receive message objects */
+	for (i = C_CAN_MSG_OBJ_RX_FIRST + 1 ; i < C_CAN_MSG_OBJ_RX_LAST; i++)
+		c_can_setup_receive_object(dev, 0, i, 0, 0,
+			((IF_MCONT_RXIE | IF_MCONT_UMASK) & ~IF_MCONT_EOB));
+
+	c_can_setup_receive_object(dev, 0, C_CAN_MSG_OBJ_RX_LAST, 0, 0,
+				IF_MCONT_EOB | IF_MCONT_RXIE | IF_MCONT_UMASK);
+	return 0;
+}
+
+/*
+ * Configure C_CAN chip:
+ * - enable/disable auto-retransmission
+ * - set operating mode
+ * - configure message objects
+ */
+static int c_can_chip_config(struct net_device *dev)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+		/* disable automatic retransmission */
+		priv->write_reg(priv, &priv->reg_base->control,
+				CONTROL_DISABLE_AR);
+	else
+		/* enable automatic retransmission */
+		priv->write_reg(priv, &priv->reg_base->control,
+				CONTROL_ENABLE_AR);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+		/* loopback mode : useful for self-test function */
+		priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
+				CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
+		priv->write_reg(priv, &priv->reg_base->test, TEST_LBACK);
+	} else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+		/* silent mode : bus-monitoring mode */
+		priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
+				CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
+		priv->write_reg(priv, &priv->reg_base->test, TEST_SILENT);
+	} else if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY &
+					CAN_CTRLMODE_LOOPBACK)) {
+		/* loopback + silent mode : useful for hot self-test */
+		priv->write_reg(priv, &priv->reg_base->control, (CONTROL_EIE |
+				CONTROL_SIE | CONTROL_IE | CONTROL_TEST));
+		priv->write_reg(priv, &priv->reg_base->test,
+				(TEST_LBACK | TEST_SILENT));
+	} else
+		/* normal mode*/
+		priv->write_reg(priv, &priv->reg_base->control,
+				(CONTROL_EIE | CONTROL_SIE | CONTROL_IE));
+
+	/* configure message objects */
+	c_can_configure_msg_objects(dev);
+
+	return 0;
+}
+
+static int c_can_start(struct net_device *dev)
+{
+	int err;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	/* enable status change, error and module interrupts */
+	c_can_configure_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+
+	/* basic c_can configuration */
+	err = c_can_chip_config(dev);
+	if (err)
+		return err;
+
+	priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+	/* reset tx helper pointers */
+	priv->tx_next = priv->tx_echo = 0;
+
+	return 0;
+}
+
+static int c_can_stop(struct net_device *dev)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	/* disable all interrupts */
+	c_can_configure_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+	/* set the state as STOPPED */
+	priv->can.state = CAN_STATE_STOPPED;
+
+	return 0;
+}
+
+static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+	switch (mode) {
+	case CAN_MODE_START:
+		c_can_start(dev);
+		netif_wake_queue(dev);
+		dev_info(dev->dev.parent,
+				"c_can CAN_MODE_START requested\n");
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int c_can_get_state(const struct net_device *dev,
+				enum can_state *state)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	*state = priv->can.state;
+
+	return 0;
+}
+
+static int c_can_get_berr_counter(const struct net_device *dev,
+					struct can_berr_counter *bec)
+{
+	unsigned int reg_err_counter;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	reg_err_counter = priv->read_reg(priv, &priv->reg_base->error_counter);
+	bec->rxerr = ((reg_err_counter & ERR_COUNTER_REC_MASK) >>
+				ERR_COUNTER_REC_SHIFT);
+	bec->txerr = (reg_err_counter & ERR_COUNTER_TEC_MASK);
+
+	return 0;
+}
+
+/*
+ * theory of operation:
+ *
+ * priv->tx_echo holds the number of the oldest can_frame put for
+ * transmission into the hardware, but not yet ACKed by the CAN tx
+ * complete IRQ.
+ *
+ * We iterate from priv->tx_echo to priv->tx_next and check if the
+ * packet has been transmitted, echo it back to the CAN framework. If
+ * we discover a not yet transmitted package, stop looking for more.
+ */
+static void c_can_do_tx(struct net_device *dev)
+{
+	u32 val;
+	u32 msg_obj_no;
+	struct c_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+
+	for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) {
+		msg_obj_no = get_tx_echo_msg_obj(priv);
+		c_can_inval_msg_object(dev, 0, msg_obj_no);
+		val = c_can_read_reg32(priv, &priv->reg_base->txrqst1);
+		if (!(val & (1 << msg_obj_no))) {
+			can_get_echo_skb(dev,
+					msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST);
+			stats->tx_bytes += priv->read_reg(priv,
+					&priv->reg_base->ifreg[0].msg_cntrl)
+					& 0xF;
+			stats->tx_packets++;
+		}
+	}
+
+	/* restart queue if wrap-up or if queue stalled on last pkt */
+	if (((priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) != 0) ||
+			((priv->tx_echo & C_CAN_NEXT_MSG_OBJ_MASK) == 0))
+		netif_wake_queue(dev);
+}
+
+/*
+ * c_can_do_rx_poll - read multiple CAN messages from message objects
+ */
+static int c_can_do_rx_poll(struct net_device *dev, int quota)
+{
+	u32 num_rx_pkts = 0;
+	unsigned int msg_obj;
+	struct c_can_priv *priv = netdev_priv(dev);
+	u32 val = c_can_read_reg32(priv, &priv->reg_base->newdat1);
+
+	while (val & RECEIVE_OBJECT_BITS) {
+		for (msg_obj = C_CAN_MSG_OBJ_RX_FIRST;
+				msg_obj <= C_CAN_MSG_OBJ_RX_LAST; msg_obj++) {
+			if (val & (1 << msg_obj)) {
+				c_can_read_msg_object(dev, 0, msg_obj);
+				num_rx_pkts++;
+				quota--;
+			}
+		}
+
+		val = c_can_read_reg32(priv, &priv->reg_base->newdat1);
+	}
+
+	return num_rx_pkts;
+}
+
+static int c_can_err(struct net_device *dev,
+				enum c_can_bus_error_types error_type,
+				int lec_type)
+{
+	unsigned int reg_err_counter;
+	unsigned int rx_err_passive;
+	struct c_can_priv *priv = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct can_frame *cf;
+	struct sk_buff *skb;
+	struct can_berr_counter bec;
+
+	/* propogate the error condition to the CAN stack */
+	skb = alloc_can_err_skb(dev, &cf);
+	if (unlikely(!skb))
+		return 0;
+
+	c_can_get_berr_counter(dev, &bec);
+	reg_err_counter = priv->read_reg(priv, &priv->reg_base->error_counter);
+	rx_err_passive = ((reg_err_counter & ERR_COUNTER_RP_MASK) >>
+				ERR_COUNTER_RP_SHIFT);
+
+	if (error_type & C_CAN_ERROR_WARNING) {
+		/* error warning state */
+		priv->can.can_stats.error_warning++;
+		priv->can.state = CAN_STATE_ERROR_WARNING;
+		cf->can_id |= CAN_ERR_CRTL;
+		if (bec.rxerr > 96)
+			cf->data[1] = CAN_ERR_CRTL_RX_WARNING;
+		if (bec.txerr > 96)
+			cf->data[1] = CAN_ERR_CRTL_TX_WARNING;
+	}
+	if (error_type & C_CAN_ERROR_PASSIVE) {
+		/* error passive state */
+		priv->can.can_stats.error_passive++;
+		priv->can.state = CAN_STATE_ERROR_PASSIVE;
+		cf->can_id |= CAN_ERR_CRTL;
+		if (rx_err_passive)
+			cf->data[1] = CAN_ERR_CRTL_RX_PASSIVE;
+		if (bec.txerr > 127)
+			cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE;
+	}
+	if (error_type & C_CAN_BUS_OFF) {
+		/* bus-off state */
+		priv->can.state = CAN_STATE_BUS_OFF;
+		cf->can_id |= CAN_ERR_BUSOFF;
+		/* disable all interrupts in bus-off mode to ensure that
+		 * the CPU is not hogged down
+		 */
+		c_can_configure_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+		can_bus_off(dev);
+	}
+
+	/* check for 'last error code' which tells us the
+	 * type of the last error to occur on the CAN bus
+	 */
+	if (lec_type) {
+		/* common for all type of bus errors */
+		priv->can.can_stats.bus_error++;
+		stats->rx_errors++;
+		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+		cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+		if (lec_type & LEC_STUFF_ERROR) {
+			dev_info(dev->dev.parent, "stuff error\n");
+			cf->data[2] |= CAN_ERR_PROT_STUFF;
+		}
+		if (lec_type & LEC_FORM_ERROR) {
+			dev_info(dev->dev.parent, "form error\n");
+			cf->data[2] |= CAN_ERR_PROT_FORM;
+		}
+		if (lec_type & LEC_ACK_ERROR) {
+			dev_info(dev->dev.parent, "ack error\n");
+			cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
+					CAN_ERR_PROT_LOC_ACK_DEL);
+		}
+		if (lec_type & LEC_BIT1_ERROR) {
+			dev_info(dev->dev.parent, "bit1 error\n");
+			cf->data[2] |= CAN_ERR_PROT_BIT1;
+		}
+		if (lec_type & LEC_BIT0_ERROR) {
+			dev_info(dev->dev.parent, "bit0 error\n");
+			cf->data[2] |= CAN_ERR_PROT_BIT0;
+		}
+		if (lec_type & LEC_CRC_ERROR) {
+			dev_info(dev->dev.parent, "CRC error\n");
+			cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+					CAN_ERR_PROT_LOC_CRC_DEL);
+		}
+	}
+
+	netif_receive_skb(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += cf->can_dlc;
+
+	return 1;
+}
+
+static int c_can_poll(struct napi_struct *napi, int quota)
+{
+	u16 irqstatus;
+	int lec_type = 0;
+	int work_done = 0;
+	struct net_device *dev = napi->dev;
+	struct c_can_priv *priv = netdev_priv(dev);
+	enum c_can_bus_error_types error_type = C_CAN_NO_ERROR;
+
+	irqstatus = priv->read_reg(priv, &priv->reg_base->ir);
+
+	/* status events have the highest priority */
+	if (irqstatus == STATUS_INTERRUPT) {
+		priv->current_status = priv->read_reg(priv,
+					&priv->reg_base->status);
+
+		/* handle Tx/Rx events */
+		if (priv->current_status & STATUS_TXOK)
+			priv->write_reg(priv, &priv->reg_base->status,
+					(priv->current_status & ~STATUS_TXOK));
+
+		if (priv->current_status & STATUS_RXOK)
+			priv->write_reg(priv, &priv->reg_base->status,
+					(priv->current_status & ~STATUS_RXOK));
+
+		/* handle bus error events */
+		if (priv->current_status & STATUS_EWARN) {
+			dev_info(dev->dev.parent,
+					"entered error warning state\n");
+			error_type = C_CAN_ERROR_WARNING;
+		}
+		if ((priv->current_status & STATUS_EPASS) &&
+				(!(priv->last_status & STATUS_EPASS))) {
+			dev_info(dev->dev.parent,
+					"entered error passive state\n");
+			error_type = C_CAN_ERROR_PASSIVE;
+		}
+		if ((priv->current_status & STATUS_BOFF) &&
+				(!(priv->last_status & STATUS_BOFF))) {
+			dev_info(dev->dev.parent,
+					"entered bus off state\n");
+			error_type = C_CAN_BUS_OFF;
+		}
+		if (priv->current_status & STATUS_LEC_MASK)
+			lec_type = (priv->current_status & STATUS_LEC_MASK);
+
+		/* handle bus recovery events */
+		if ((!(priv->current_status & STATUS_EPASS)) &&
+				(priv->last_status & STATUS_EPASS)) {
+			dev_info(dev->dev.parent,
+					"left error passive state\n");
+			priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		}
+		if ((!(priv->current_status & STATUS_BOFF)) &&
+				(priv->last_status & STATUS_BOFF)) {
+			dev_info(dev->dev.parent,
+					"left bus off state\n");
+			priv->can.state = CAN_STATE_ERROR_ACTIVE;
+		}
+
+		priv->last_status = priv->current_status;
+
+		/* handle error on the bus */
+		if (error_type != C_CAN_NO_ERROR)
+			work_done += c_can_err(dev, error_type, lec_type);
+	} else if ((irqstatus > C_CAN_MSG_OBJ_RX_FIRST) &&
+			(irqstatus <= C_CAN_MSG_OBJ_RX_LAST)) {
+		/* handle events corresponding to receive message objects */
+		work_done += c_can_do_rx_poll(dev, (quota - work_done));
+		quota--;
+	} else if ((irqstatus > C_CAN_MSG_OBJ_TX_FIRST) &&
+			(irqstatus <= C_CAN_MSG_OBJ_TX_LAST)) {
+		/* handle events corresponding to transmit message objects */
+		c_can_do_tx(dev);
+	}
+
+	if (work_done < quota) {
+		napi_complete(napi);
+		/* enable all IRQs */
+		c_can_configure_interrupts(priv, ENABLE_ALL_INTERRUPTS);
+	}
+
+	return work_done;
+}
+
+static irqreturn_t c_can_isr(int irq, void *dev_id)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	/* disable all interrupts and schedule the NAPI */
+	c_can_configure_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+	napi_schedule(&priv->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int c_can_open(struct net_device *dev)
+{
+	int err;
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	/* open the can device */
+	err = open_candev(dev);
+	if (err) {
+		dev_err(dev->dev.parent, "failed to open can device\n");
+		return err;
+	}
+
+	/* register interrupt handler */
+	err = request_irq(dev->irq, &c_can_isr, priv->irq_flags, dev->name,
+				(void *)dev);
+	if (err < 0) {
+		dev_err(dev->dev.parent, "failed to attach interrupt\n");
+		goto exit_irq_fail;
+	}
+
+	/* start the c_can controller */
+	err = c_can_start(dev);
+	if (err)
+		goto exit_start_fail;
+	napi_enable(&priv->napi);
+
+	netif_start_queue(dev);
+
+	return 0;
+
+exit_start_fail:
+	free_irq(dev->irq, dev);
+exit_irq_fail:
+	close_candev(dev);
+	return err;
+}
+
+static int c_can_close(struct net_device *dev)
+{
+	struct c_can_priv *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+	napi_disable(&priv->napi);
+	c_can_stop(dev);
+	free_irq(dev->irq, dev);
+	close_candev(dev);
+
+	return 0;
+}
+
+static const struct net_device_ops c_can_netdev_ops = {
+	.ndo_open = c_can_open,
+	.ndo_stop = c_can_close,
+	.ndo_start_xmit = c_can_start_xmit,
+};
+
+static int c_can_probe(struct platform_device *pdev)
+{
+	int ret;
+	void __iomem *addr;
+	struct net_device *dev;
+	struct c_can_priv *priv;
+	struct resource *mem, *irq;
+	struct clk *clk;
+
+	/* get the appropriate clk */
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "no clock defined\n");
+		ret = -ENODEV;
+		goto exit;
+	}
+
+	/* get the platform data */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!mem || (irq <= 0)) {
+		ret = -ENODEV;
+		goto exit_free_clk;
+	}
+
+	if (!request_mem_region(mem->start, resource_size(mem), DRV_NAME)) {
+		dev_err(&pdev->dev, "resource unavailable\n");
+		ret = -ENODEV;
+		goto exit_free_clk;
+	}
+
+	addr = ioremap(mem->start, resource_size(mem));
+	if (!addr) {
+		dev_err(&pdev->dev, "failed to map can port\n");
+		ret = -ENOMEM;
+		goto exit_release_mem;
+	}
+
+	/* allocate the c_can device */
+	dev = alloc_candev(sizeof(struct c_can_priv), C_CAN_MSG_OBJ_TX_NUM);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto exit_iounmap;
+	}
+
+	priv = netdev_priv(dev);
+
+	priv->irq_flags = irq->flags;
+	priv->reg_base = addr;
+	priv->can.clock.freq = clk_get_rate(clk);
+	priv->clk = clk;
+
+	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+	case IORESOURCE_MEM_32BIT:
+		priv->read_reg = c_can_read_reg_aligned_to_32bit;
+		priv->write_reg = c_can_write_reg_aligned_to_32bit;
+		break;
+	case IORESOURCE_MEM_16BIT:
+	default:
+		priv->read_reg = c_can_read_reg_aligned_to_16bit;
+		priv->write_reg = c_can_write_reg_aligned_to_16bit;
+		break;
+	}
+
+	priv->dev = dev;
+	priv->can.bittiming_const = &c_can_bittiming_const;
+	priv->can.do_set_bittiming = c_can_set_bittiming;
+	priv->can.do_get_state = c_can_get_state;
+	priv->can.do_set_mode = c_can_set_mode;
+	priv->can.do_get_berr_counter = c_can_get_berr_counter;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT |
+					CAN_CTRLMODE_LOOPBACK |
+					CAN_CTRLMODE_LISTENONLY |
+					CAN_CTRLMODE_BERR_REPORTING;
+
+	netif_napi_add(dev, &priv->napi, c_can_poll, C_CAN_NAPI_WEIGHT);
+
+	dev->irq = irq->start;
+	dev->flags |= IFF_ECHO;	/* we support local echo */
+	dev->netdev_ops = &c_can_netdev_ops;
+	platform_set_drvdata(pdev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	ret = register_candev(dev);
+	if (ret) {
+		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+			DRV_NAME, ret);
+		goto exit_free_device;
+	}
+
+	dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
+		 DRV_NAME, priv->reg_base, dev->irq);
+	return 0;
+
+exit_free_device:
+	platform_set_drvdata(pdev, NULL);
+	free_candev(dev);
+exit_iounmap:
+	iounmap(addr);
+exit_release_mem:
+	release_mem_region(mem->start, resource_size(mem));
+exit_free_clk:
+	clk_put(clk);
+exit:
+	dev_err(&pdev->dev, "probe failed\n");
+
+	return ret;
+}
+
+static int c_can_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct c_can_priv *priv = netdev_priv(dev);
+	struct resource *mem;
+
+	/* disable all interrupts */
+	c_can_configure_interrupts(priv, DISABLE_ALL_INTERRUPTS);
+
+	unregister_candev(dev);
+	platform_set_drvdata(pdev, NULL);
+
+	free_candev(dev);
+	iounmap(priv->reg_base);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	clk_put(priv->clk);
+
+	return 0;
+}
+
+static struct platform_driver c_can_driver = {
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe		= c_can_probe,
+	.remove		= c_can_remove,
+};
+
+static int __init c_can_init(void)
+{
+	return platform_driver_register(&c_can_driver);
+}
+module_init(c_can_init);
+
+static void __exit c_can_exit(void)
+{
+	platform_driver_unregister(&c_can_driver);
+}
+module_exit(c_can_exit);
+
+MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch C_CAN controller");
-- 
1.6.0.2


^ permalink raw reply related

* Re: [*v2 PATCH 00/22] IPVS, Network Name Space aware
From: Hans Schillstrom @ 2010-12-15 10:32 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: horms@verge.net.au, daniel.lezcano@free.fr, wensong@linux-vs.org,
	lvs-devel@vger.kernel.org, netdev@vger.kernel.org,
	netfilter-devel@vger.kernel.org, hans@schillstrom.com
In-Reply-To: <alpine.LFD.2.00.1012150136410.2010@ja.ssi.bg>

On Wed, 2010-12-15 at 00:43 +0100, Julian Anastasov wrote:
> 	Hello,
> 
> On Mon, 13 Dec 2010, Hans Schillstrom wrote:
[snip]
> v2 PATCH 13/22 - ip_vs_est
>  	- estimation_timer: what protection is needed for for_each_net?
>  	It is rtnl for user context and RCU for softirq?
>  	May be est_timer must be per NS? Now may be rcu_read_lock is
>  	needed before for_each_net_rcu ? for_each_net can be called
>  	only under rtnl_lock?
> 
[snip]

In case of a common timer for all ns:

	rcu_read_lock();
	for_each_net_rcu(net) {
		...

	}
	rcu_read_unlock();

I guess it's better with a timer per netns ?
(then for_each_net() is not needed, and the locking can remain the same
as before the netns change.)


Regards
Hans Schillstrom <hans.schillstrom@ericsson.com>


^ permalink raw reply

* Re: [*v2 PATCH 00/22] IPVS, Network Name Space aware
From: Hans Schillstrom @ 2010-12-15 10:52 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: horms@verge.net.au, daniel.lezcano@free.fr, wensong@linux-vs.org,
	lvs-devel@vger.kernel.org, netdev@vger.kernel.org,
	netfilter-devel@vger.kernel.org, hans@schillstrom.com
In-Reply-To: <alpine.LFD.2.00.1012150136410.2010@ja.ssi.bg>

On Wed, 2010-12-15 at 00:43 +0100, Julian Anastasov wrote:
> 	Hello,
> 
> On Mon, 13 Dec 2010, Hans Schillstrom wrote:
[snip]
> >
> > Procfs ip_vs_stats is also changed to reflect the "per cpu"
> > ex.
> > # cat /proc/net/ip_vs_stats
> >       Total Incoming Outgoing         Incoming         Outgoing
> > CPU    Conns  Packets  Packets            Bytes            Bytes
> >  0        0        3        1               9D               34
> >  1        0        1        2               49               70
> >  2        0        1        2               34               76
> >  3        1        2        2               70               74
> >  ~        1        7        7              18A              18E
> >
> >     Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s
> >           0        0        0                0                0
> >
[snip]
> > Algorithm files are untouched except for lblc and lblcr.

> v2 PATCH 15/22 - ip_vs_stats
>  	- This was one of the hurdles for IPVS RCU conversion, the others
>  	being dest->svc->stats and scheduler state. But can this
>  	change break some scripts that parse /proc/net/ip_vs_stats ?
> 

Should I keep /proc/net/ip_vs_stats as it was before and add a new entry
like /proc/net/ip_vs_stats_percpu ?
(or maybe just skip the per cpu info ?)


Regards 
Hans Schillstrom <hans.schillstrom@ericsson.com>



^ permalink raw reply

* Re: [v3 PATCH 1/2] bonding: sync netpoll code with bridge
From: Cong Wang @ 2010-12-15 10:52 UTC (permalink / raw)
  To: Neil Horman
  Cc: linux-kernel, Jiri Pirko, netdev, David S. Miller,
	Eric W. Biederman, Herbert Xu, bonding-devel, Jay Vosburgh,
	Stephen Hemminger
In-Reply-To: <4D008643.5040500@redhat.com>

于 2010年12月09日 15:33, Cong Wang 写道:
> On 12/08/10 21:57, Neil Horman wrote:
>> On Wed, Dec 08, 2010 at 02:52:08AM -0500, Amerigo Wang wrote:
>>> -    bond_for_each_slave(bond, slave, i) {
>>> -        if ((slave->dev->priv_flags&  IFF_DISABLE_NETPOLL) ||
>>> -            !slave->dev->netdev_ops->ndo_poll_controller)
>>> -            ret = false;
>>> +    np = kmalloc(sizeof(*np), GFP_KERNEL);
>>> +    err = -ENOMEM;
>>> +    if (!np)
>>> +        goto out;
>>> +
>>> +    np->dev = slave->dev;
>>> +    err = __netpoll_setup(np);
>> Setting up our own netpoll instance on each slave worries me a bit.  The
>> implication here is that, by doing so, some frames will get entirely processed
>> by the slave.  Most notably arp frames.  That means anything that gets queued up
>> to the arp_tx queue in __netpoll_rx will get processed during that poll event,
>> and responded to with the mac of the slave device, rather than with the mac of
>> the bond device, which isn't always what you want.  I think if you go with this
>> route, you'll need to add code to netpoll_poll_dev, right before the call to
>> service_arp_queue, to check if IFF_SLAVE is set in priv_flags, and move the list
>> to the master device, or some such.
>
>
> Good point! Will fix i

Hi, Neil,

I think we should do that in bond_poll_controller() rather than netpoll_poll_dev(),
right? Since this is bond-specific. Does moving all arp_tx of slaves to their bond
address your concern?

Thanks!

^ permalink raw reply

* Re: [v3 PATCH 1/2] bonding: sync netpoll code with bridge
From: Neil Horman @ 2010-12-15 11:59 UTC (permalink / raw)
  To: Cong Wang
  Cc: Neil Horman, linux-kernel, Jiri Pirko, netdev, David S. Miller,
	Eric W. Biederman, Herbert Xu, bonding-devel, Jay Vosburgh,
	Stephen Hemminger
In-Reply-To: <4D089DEA.2060803@redhat.com>

On Wed, Dec 15, 2010 at 06:52:26PM +0800, Cong Wang wrote:
> 于 2010年12月09日 15:33, Cong Wang 写道:
> >On 12/08/10 21:57, Neil Horman wrote:
> >>On Wed, Dec 08, 2010 at 02:52:08AM -0500, Amerigo Wang wrote:
> >>>-    bond_for_each_slave(bond, slave, i) {
> >>>-        if ((slave->dev->priv_flags&  IFF_DISABLE_NETPOLL) ||
> >>>-            !slave->dev->netdev_ops->ndo_poll_controller)
> >>>-            ret = false;
> >>>+    np = kmalloc(sizeof(*np), GFP_KERNEL);
> >>>+    err = -ENOMEM;
> >>>+    if (!np)
> >>>+        goto out;
> >>>+
> >>>+    np->dev = slave->dev;
> >>>+    err = __netpoll_setup(np);
> >>Setting up our own netpoll instance on each slave worries me a bit.  The
> >>implication here is that, by doing so, some frames will get entirely processed
> >>by the slave.  Most notably arp frames.  That means anything that gets queued up
> >>to the arp_tx queue in __netpoll_rx will get processed during that poll event,
> >>and responded to with the mac of the slave device, rather than with the mac of
> >>the bond device, which isn't always what you want.  I think if you go with this
> >>route, you'll need to add code to netpoll_poll_dev, right before the call to
> >>service_arp_queue, to check if IFF_SLAVE is set in priv_flags, and move the list
> >>to the master device, or some such.
> >
> >
> >Good point! Will fix i
> 
> Hi, Neil,
> 
> I think we should do that in bond_poll_controller() rather than netpoll_poll_dev(),
> right? Since this is bond-specific. Does moving all arp_tx of slaves to their bond
> address your concern?
> 
Don't think that will work, because, since your using multiple netpoll instances
here, the slaves arp_tx queue will get serviced on the return from the slaves
netpoll_poll_dev call, prior to returning to the bond_poll_controller call.  In
other words, bond_poll_controller won't ever see any frames on the slaves arp_tx
queue to migrate, since they will have already been responded to by the slave
directly.
Neil

> Thanks!
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

^ permalink raw reply

* Re: [*v2 PATCH 00/22] IPVS, Network Name Space aware
From: Graeme Fowler @ 2010-12-15 12:15 UTC (permalink / raw)
  To: Hans Schillstrom
  Cc: Julian Anastasov, horms@verge.net.au, daniel.lezcano@free.fr,
	wensong@linux-vs.org, lvs-devel@vger.kernel.org,
	netdev@vger.kernel.org, netfilter-devel@vger.kernel.org,
	hans@schillstrom.com
In-Reply-To: <1292410332.4983.321.camel@seasc0214>

On Wed, 2010-12-15 at 11:52 +0100, Hans Schillstrom wrote:
> Should I keep /proc/net/ip_vs_stats as it was before and add a new entry
> like /proc/net/ip_vs_stats_percpu ?
> (or maybe just skip the per cpu info ?)

In my opinion you should keep the existing /proc/net/ip_vs_stats as it
is or you may find that you inadvertently break 3rd party code which
parses it.

Graeme



^ permalink raw reply

* Re: [PATCH 1/5] ifb: remove function declarations
From: jamal @ 2010-12-15 12:31 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, netdev
In-Reply-To: <1292251414-5154-1-git-send-email-xiaosuo@gmail.com>


Sorry - I am very distracted with work but will get back to you
on these patches. If i can respond to from a quick glance such
as this one, I will do now.

On Mon, 2010-12-13 at 22:43 +0800, Changli Gao wrote:
> Restructure to remove function declarations.
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>

Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>

cheers,
jamal


^ permalink raw reply


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