Netdev List
 help / color / mirror / Atom feed
* [net-next  09/15] igb: Fix get_fw_version function for all parts
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

This patch fixes issues found with older parts and older NVM tools in the
display of the version in ethtool.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/e1000_defines.h | 28 +++++----
 drivers/net/ethernet/intel/igb/e1000_nvm.c     | 80 ++++++++++++++++++--------
 drivers/net/ethernet/intel/igb/e1000_nvm.h     |  1 +
 drivers/net/ethernet/intel/igb/igb_main.c      | 28 ++++++---
 4 files changed, 93 insertions(+), 44 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 4522198..60559af 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -671,20 +671,26 @@
 #define NVM_INIT_CTRL_4            0x0013
 #define NVM_LED_1_CFG              0x001C
 #define NVM_LED_0_2_CFG            0x001F
-
-/* NVM version defines */
 #define NVM_ETRACK_WORD            0x0042
+#define NVM_ETRACK_HIWORD          0x0043
 #define NVM_COMB_VER_OFF           0x0083
 #define NVM_COMB_VER_PTR           0x003d
-#define NVM_MAJOR_MASK             0xF000
-#define NVM_MINOR_MASK             0x0FF0
-#define NVM_BUILD_MASK             0x000F
-#define NVM_COMB_VER_MASK          0x00FF
-#define NVM_MAJOR_SHIFT                12
-#define NVM_MINOR_SHIFT                 4
-#define NVM_COMB_VER_SHFT               8
-#define NVM_VER_INVALID            0xFFFF
-#define NVM_ETRACK_SHIFT               16
+
+/* NVM version defines */
+#define NVM_MAJOR_MASK			0xF000
+#define NVM_MINOR_MASK			0x0FF0
+#define NVM_IMAGE_ID_MASK		0x000F
+#define NVM_COMB_VER_MASK		0x00FF
+#define NVM_MAJOR_SHIFT			12
+#define NVM_MINOR_SHIFT			4
+#define NVM_COMB_VER_SHFT		8
+#define NVM_VER_INVALID			0xFFFF
+#define NVM_ETRACK_SHIFT		16
+#define NVM_ETRACK_VALID		0x8000
+#define NVM_NEW_DEC_MASK		0x0F00
+#define NVM_HEX_CONV			16
+#define NVM_HEX_TENS			10
+
 #define NVM_ETS_CFG			0x003E
 #define NVM_ETS_LTHRES_DELTA_MASK	0x07C0
 #define NVM_ETS_LTHRES_DELTA_SHIFT	6
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index 7f9cd7c..a7db7f3 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -709,11 +709,16 @@ out:
  **/
 void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
 {
-	u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset;
-	u16 fw_version;
+	u16 eeprom_verh, eeprom_verl, etrack_test, fw_version;
+	u8 q, hval, rem, result;
+	u16 comb_verh, comb_verl, comb_offset;
 
 	memset(fw_vers, 0, sizeof(struct e1000_fw_version));
 
+	/* basic eeprom version numbers and bits used vary by part and by tool
+	 * used to create the nvm images. Check which data format we have.
+	 */
+	hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test);
 	switch (hw->mac.type) {
 	case e1000_i211:
 		igb_read_invm_version(hw, fw_vers);
@@ -721,30 +726,30 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
 	case e1000_82575:
 	case e1000_82576:
 	case e1000_82580:
-	case e1000_i354:
-	case e1000_i350:
-	case e1000_i210:
+		/* Use this format, unless EETRACK ID exists,
+		 * then use alternate format
+		 */
+		if ((etrack_test &  NVM_MAJOR_MASK) != NVM_ETRACK_VALID) {
+			hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
+			fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
+					      >> NVM_MAJOR_SHIFT;
+			fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK)
+					      >> NVM_MINOR_SHIFT;
+			fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK);
+			goto etrack_id;
+		}
 		break;
-	default:
-		return;
-	}
-	/* basic eeprom version numbers */
-	hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
-	fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT;
-	fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK);
-
-	/* etrack id */
-	hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl);
-	hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh);
-	fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | eeprom_verl;
-
-	switch (hw->mac.type) {
 	case e1000_i210:
-	case e1000_i354:
+		if (!(igb_get_flash_presence_i210(hw))) {
+			igb_read_invm_version(hw, fw_vers);
+			return;
+		}
+		/* fall through */
 	case e1000_i350:
 		/* find combo image version */
 		hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
-		if ((comb_offset != 0x0) && (comb_offset != NVM_VER_INVALID)) {
+		if ((comb_offset != 0x0) &&
+		    (comb_offset != NVM_VER_INVALID)) {
 
 			hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset
 					 + 1), 1, &comb_verh);
@@ -760,15 +765,42 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
 				fw_vers->or_major =
 					comb_verl >> NVM_COMB_VER_SHFT;
 				fw_vers->or_build =
-					((comb_verl << NVM_COMB_VER_SHFT)
-					| (comb_verh >> NVM_COMB_VER_SHFT));
+					(comb_verl << NVM_COMB_VER_SHFT)
+					| (comb_verh >> NVM_COMB_VER_SHFT);
 				fw_vers->or_patch =
 					comb_verh & NVM_COMB_VER_MASK;
 			}
 		}
 		break;
 	default:
-		break;
+		return;
+	}
+	hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
+	fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
+			      >> NVM_MAJOR_SHIFT;
+
+	/* check for old style version format in newer images*/
+	if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) {
+		eeprom_verl = (fw_version & NVM_COMB_VER_MASK);
+	} else {
+		eeprom_verl = (fw_version & NVM_MINOR_MASK)
+				>> NVM_MINOR_SHIFT;
+	}
+	/* Convert minor value to hex before assigning to output struct
+	 * Val to be converted will not be higher than 99, per tool output
+	 */
+	q = eeprom_verl / NVM_HEX_CONV;
+	hval = q * NVM_HEX_TENS;
+	rem = eeprom_verl % NVM_HEX_CONV;
+	result = hval + rem;
+	fw_vers->eep_minor = result;
+
+etrack_id:
+	if ((etrack_test &  NVM_MAJOR_MASK) == NVM_ETRACK_VALID) {
+		hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl);
+		hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh);
+		fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT)
+			| eeprom_verl;
 	}
 	return;
 }
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h
index 6bfc0c4..433b741 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.h
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h
@@ -44,6 +44,7 @@ struct e1000_fw_version {
 	u32 etrack_id;
 	u16 eep_major;
 	u16 eep_minor;
+	u16 eep_build;
 
 	u8 invm_major;
 	u8 invm_minor;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index a53c77b..7f6cf65 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1931,12 +1931,17 @@ void igb_set_fw_version(struct igb_adapter *adapter)
 	igb_get_fw_version(hw, &fw);
 
 	switch (hw->mac.type) {
+	case e1000_i210:
 	case e1000_i211:
-		snprintf(adapter->fw_version, sizeof(adapter->fw_version),
-			 "%2d.%2d-%d",
-			 fw.invm_major, fw.invm_minor, fw.invm_img_type);
-		break;
-
+		if (!(igb_get_flash_presence_i210(hw))) {
+			snprintf(adapter->fw_version,
+				 sizeof(adapter->fw_version),
+				 "%2d.%2d-%d",
+				 fw.invm_major, fw.invm_minor,
+				 fw.invm_img_type);
+			break;
+		}
+		/* fall through */
 	default:
 		/* if option is rom valid, display its version too */
 		if (fw.or_valid) {
@@ -1946,11 +1951,16 @@ void igb_set_fw_version(struct igb_adapter *adapter)
 				 fw.eep_major, fw.eep_minor, fw.etrack_id,
 				 fw.or_major, fw.or_build, fw.or_patch);
 		/* no option rom */
-		} else {
+		} else if (fw.etrack_id != 0X0000) {
 			snprintf(adapter->fw_version,
-				 sizeof(adapter->fw_version),
-				 "%d.%d, 0x%08x",
-				 fw.eep_major, fw.eep_minor, fw.etrack_id);
+			    sizeof(adapter->fw_version),
+			    "%d.%d, 0x%08x",
+			    fw.eep_major, fw.eep_minor, fw.etrack_id);
+		} else {
+		snprintf(adapter->fw_version,
+		    sizeof(adapter->fw_version),
+		    "%d.%d.%d",
+		    fw.eep_major, fw.eep_minor, fw.eep_build);
 		}
 		break;
 	}
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  10/15] igb: Add macro for size of RETA indirection table
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Laura Mihaela Vasilescu, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Laura Mihaela Vasilescu <laura.vasilescu@rosedu.org>

RETA indirection table is used to assign the received data to a CPU
in order to maintain an efficient distribution of network receive
processing across multiple CPUs.

This patch removes the hard-coded value for the size of the indirection
table and defines a new macro.

Signed-off-by: Laura Mihaela Vasilescu <laura.vasilescu@rosedu.org>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/igb.h      | 2 ++
 drivers/net/ethernet/intel/igb/igb_main.c | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 15ea8dc..5a2659b 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -343,6 +343,8 @@ struct hwmon_buff {
 	};
 #endif
 
+#define IGB_RETA_SIZE	128
+
 /* board specific private data structure */
 struct igb_adapter {
 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 7f6cf65..1acd9c0 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3157,7 +3157,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
 	 * we are generating the results for n and n+2 and then interleaving
 	 * those with the results with n+1 and n+3.
 	 */
-	for (j = 0; j < 32; j++) {
+	for (j = 0; j < IGB_RETA_SIZE / 4; j++) {
 		/* first pass generates n and n+2 */
 		u32 base = ((j * 0x00040004) + 0x00020000) * num_rx_queues;
 		u32 reta = (base & 0x07800780) >> (7 - shift);
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  12/15] e1000e: cleanup whitespace in recent commit
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

Commit c96ddb0b moved a define from one file to another but missed using
proper indentation/whitespace.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/hw.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index b799fd9..b7f3843 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -233,7 +233,8 @@ union e1000_rx_desc_extended {
 #define MAX_PS_BUFFERS 4
 
 /* Number of packet split data buffers (not including the header buffer) */
-#define PS_PAGE_BUFFERS			(MAX_PS_BUFFERS - 1)
+#define PS_PAGE_BUFFERS	(MAX_PS_BUFFERS - 1)
+
 /* Receive Descriptor - Packet Split */
 union e1000_rx_desc_packet_split {
 	struct {
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  11/15] igb: Expose RSS indirection table for ethtool
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Laura Mihaela Vasilescu, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Laura Mihaela Vasilescu <laura.vasilescu@rosedu.org>

This patch adds the ethtool callbacks necessary to change the RETA
indirection table from userspace.

In order to achieve this, we add the indirection table field (rss_indir_tbl)
in the board specific data structure (struct igb_adapter) to preserve the
values across hardware resets.

The indirection table must be initialized with default values in the
following cases:
	* at module init time
	* when the number of RX queues changes.
For this reason we add a new field (rss_indir_tbl_init) in igb_adapter
that keeps track of the number of RX queues. Whenever the number of RX
queues changes, the rss_indir_tbl is modified and initialized with default
values. The rss_indir_tbl_init is updated accordingly.

Signed-off-by: Laura Mihaela Vasilescu <laura.vasilescu@rosedu.org>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/igb.h         |  3 +
 drivers/net/ethernet/intel/igb/igb_ethtool.c | 87 ++++++++++++++++++++++++++++
 drivers/net/ethernet/intel/igb/igb_main.c    | 28 +++------
 3 files changed, 97 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 5a2659b..c1fae7a 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -446,6 +446,8 @@ struct igb_adapter {
 	struct i2c_algo_bit_data i2c_algo;
 	struct i2c_adapter i2c_adap;
 	struct i2c_client *i2c_client;
+	u32 rss_indir_tbl_init;
+	u8 rss_indir_tbl[IGB_RETA_SIZE];
 };
 
 #define IGB_FLAG_HAS_MSI		(1 << 0)
@@ -482,6 +484,7 @@ extern int igb_up(struct igb_adapter *);
 extern void igb_down(struct igb_adapter *);
 extern void igb_reinit_locked(struct igb_adapter *);
 extern void igb_reset(struct igb_adapter *);
+extern void igb_write_rss_indir_tbl(struct igb_adapter *);
 extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
 extern int igb_setup_tx_resources(struct igb_ring *);
 extern int igb_setup_rx_resources(struct igb_ring *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 03137e2..036221d 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2784,6 +2784,90 @@ static void igb_ethtool_complete(struct net_device *netdev)
 	pm_runtime_put(&adapter->pdev->dev);
 }
 
+static u32 igb_get_rxfh_indir_size(struct net_device *netdev)
+{
+	return IGB_RETA_SIZE;
+}
+
+static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	for (i = 0; i < IGB_RETA_SIZE; i++)
+		indir[i] = adapter->rss_indir_tbl[i];
+
+	return 0;
+}
+
+void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 reg = E1000_RETA(0);
+	u32 shift = 0;
+	int i = 0;
+
+	switch (hw->mac.type) {
+	case e1000_82575:
+		shift = 6;
+		break;
+	case e1000_82576:
+		/* 82576 supports 2 RSS queues for SR-IOV */
+		if (adapter->vfs_allocated_count)
+			shift = 3;
+		break;
+	default:
+		break;
+	}
+
+	while (i < IGB_RETA_SIZE) {
+		u32 val = 0;
+		int j;
+
+		for (j = 3; j >= 0; j--) {
+			val <<= 8;
+			val |= adapter->rss_indir_tbl[i + j];
+		}
+
+		wr32(reg, val << shift);
+		reg += 4;
+		i += 4;
+	}
+}
+
+static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int i;
+	u32 num_queues;
+
+	num_queues = adapter->rss_queues;
+
+	switch (hw->mac.type) {
+	case e1000_82576:
+		/* 82576 supports 2 RSS queues for SR-IOV */
+		if (adapter->vfs_allocated_count)
+			num_queues = 2;
+		break;
+	default:
+		break;
+	}
+
+	/* Verify user input. */
+	for (i = 0; i < IGB_RETA_SIZE; i++)
+		if (indir[i] > num_queues)
+			return -EINVAL;
+
+
+	for (i = 0; i < IGB_RETA_SIZE; i++)
+		adapter->rss_indir_tbl[i] = indir[i];
+
+	igb_write_rss_indir_tbl(adapter);
+
+	return 0;
+}
+
 static const struct ethtool_ops igb_ethtool_ops = {
 	.get_settings		= igb_get_settings,
 	.set_settings		= igb_set_settings,
@@ -2817,6 +2901,9 @@ static const struct ethtool_ops igb_ethtool_ops = {
 	.set_eee		= igb_set_eee,
 	.get_module_info	= igb_get_module_info,
 	.get_module_eeprom	= igb_get_module_eeprom,
+	.get_rxfh_indir_size	= igb_get_rxfh_indir_size,
+	.get_rxfh_indir		= igb_get_rxfh_indir,
+	.set_rxfh_indir		= igb_set_rxfh_indir,
 	.begin			= igb_ethtool_begin,
 	.complete		= igb_ethtool_complete,
 };
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 1acd9c0..df33c4b 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3126,7 +3126,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 	u32 mrqc, rxcsum;
-	u32 j, num_rx_queues, shift = 0;
+	u32 j, num_rx_queues;
 	static const u32 rsskey[10] = { 0xDA565A6D, 0xC20E5B25, 0x3D256741,
 					0xB08FA343, 0xCB2BCAD0, 0xB4307BAE,
 					0xA32DCB77, 0x0CF23080, 0x3BB7426A,
@@ -3139,35 +3139,21 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
 	num_rx_queues = adapter->rss_queues;
 
 	switch (hw->mac.type) {
-	case e1000_82575:
-		shift = 6;
-		break;
 	case e1000_82576:
 		/* 82576 supports 2 RSS queues for SR-IOV */
-		if (adapter->vfs_allocated_count) {
-			shift = 3;
+		if (adapter->vfs_allocated_count)
 			num_rx_queues = 2;
-		}
 		break;
 	default:
 		break;
 	}
 
-	/* Populate the indirection table 4 entries at a time.  To do this
-	 * we are generating the results for n and n+2 and then interleaving
-	 * those with the results with n+1 and n+3.
-	 */
-	for (j = 0; j < IGB_RETA_SIZE / 4; j++) {
-		/* first pass generates n and n+2 */
-		u32 base = ((j * 0x00040004) + 0x00020000) * num_rx_queues;
-		u32 reta = (base & 0x07800780) >> (7 - shift);
-
-		/* second pass generates n+1 and n+3 */
-		base += 0x00010001 * num_rx_queues;
-		reta |= (base & 0x07800780) << (1 + shift);
-
-		wr32(E1000_RETA(j), reta);
+	if (adapter->rss_indir_tbl_init != num_rx_queues) {
+		for (j = 0; j < IGB_RETA_SIZE; j++)
+			adapter->rss_indir_tbl[j] = (j * num_rx_queues) / IGB_RETA_SIZE;
+		adapter->rss_indir_tbl_init = num_rx_queues;
 	}
+	igb_write_rss_indir_tbl(adapter);
 
 	/* Disable raw packet checksumming so that RSS hash is placed in
 	 * descriptor on writeback.  No need to enable TCP/UDP/IP checksum
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  13/15] e1000e: Add code to check for failure of pci_disable_link_state call
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

This patch attempts to work around a problem found with some systems where
the call to pci_diable_link_state_locked() fails.  As a result, ASPM is not,
in fact, disabled.  Changing disable ASPM code to check if state actually
is disabled after the call and, if not, try another way to disable it.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Acked-by: Bruce W. Allan <bruce.w.allan@intel.com>
Tested-by: Pavel Machek <pavel@ucw.cz>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 85 +++++++++++++++++++++---------
 1 file changed, 59 insertions(+), 26 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index e6d2c0f..59c0c54 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -64,8 +64,6 @@ static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
-static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
-
 static const struct e1000_info *e1000_info_tbl[] = {
 	[board_82571]		= &e1000_82571_info,
 	[board_82572]		= &e1000_82572_info,
@@ -6019,38 +6017,73 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
 	return 0;
 }
 
-#ifdef CONFIG_PCIEASPM
-static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
+/**
+ * e1000e_disable_aspm - Disable ASPM states
+ * @pdev: pointer to PCI device struct
+ * @state: bit-mask of ASPM states to disable
+ *
+ * Some devices *must* have certain ASPM states disabled per hardware errata.
+ **/
+static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 {
+	struct pci_dev *parent = pdev->bus->self;
+	u16 aspm_dis_mask = 0;
+	u16 pdev_aspmc, parent_aspmc;
+
+	switch (state) {
+	case PCIE_LINK_STATE_L0S:
+	case PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1:
+		aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L0S;
+		/* fall-through - can't have L1 without L0s */
+	case PCIE_LINK_STATE_L1:
+		aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L1;
+		break;
+	default:
+		return;
+	}
+
+	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
+	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
+
+	if (parent) {
+		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
+					  &parent_aspmc);
+		parent_aspmc &= PCI_EXP_LNKCTL_ASPMC;
+	}
+
+	/* Nothing to do if the ASPM states to be disabled already are */
+	if (!(pdev_aspmc & aspm_dis_mask) &&
+	    (!parent || !(parent_aspmc & aspm_dis_mask)))
+		return;
+
+	dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
+		 (aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L0S) ?
+		 "L0s" : "",
+		 (aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L1) ?
+		 "L1" : "");
+
+#ifdef CONFIG_PCIEASPM
 	pci_disable_link_state_locked(pdev, state);
-}
-#else
-static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
-{
-	u16 aspm_ctl = 0;
 
-	if (state & PCIE_LINK_STATE_L0S)
-		aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
-	if (state & PCIE_LINK_STATE_L1)
-		aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
+	/* Double-check ASPM control.  If not disabled by the above, the
+	 * BIOS is preventing that from happening (or CONFIG_PCIEASPM is
+	 * not enabled); override by writing PCI config space directly.
+	 */
+	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
+	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
+
+	if (!(aspm_dis_mask & pdev_aspmc))
+		return;
+#endif
 
 	/* Both device and parent should have the same ASPM setting.
 	 * Disable ASPM in downstream component first and then upstream.
 	 */
-	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
-
-	if (pdev->bus->self)
-		pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
-					   aspm_ctl);
-}
-#endif
-static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
-{
-	dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
-		 (state & PCIE_LINK_STATE_L0S) ? "L0s" : "",
-		 (state & PCIE_LINK_STATE_L1) ? "L1" : "");
+	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_dis_mask);
 
-	__e1000e_disable_aspm(pdev, state);
+	if (parent)
+		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
+					   aspm_dis_mask);
 }
 
 #ifdef CONFIG_PM
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  14/15] e1000e: Avoid kernel crash during shutdown
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Li Zhang, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Li Zhang <zhlcindy@gmail.com>

While doing shutdown on the PCI device, the corresponding callback
function e1000e_shutdown() is trying to clear those correctable
errors on the upstream P2P bridge. Unfortunately, we don't have
the upstream P2P bridge under some cases (e.g. PCI-passthrou for
KVM on Power). That leads to kernel crash eventually.

The patch adds one more check on that to avoid kernel crash.

Signed-off-by: Li Zhang <zhlcindy@gmail.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 59c0c54..e87e9b0 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5999,11 +5999,18 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
 	 * correctable error when the MAC transitions from D0 to D3.  To
 	 * prevent this we need to mask off the correctable errors on the
 	 * downstream port of the pci-e switch.
+	 *
+	 * We don't have the associated upstream bridge while assigning
+	 * the PCI device into guest. For example, the KVM on power is
+	 * one of the cases.
 	 */
 	if (adapter->flags & FLAG_IS_QUAD_PORT) {
 		struct pci_dev *us_dev = pdev->bus->self;
 		u16 devctl;
 
+		if (!us_dev)
+			return 0;
+
 		pcie_capability_read_word(us_dev, PCI_EXP_DEVCTL, &devctl);
 		pcie_capability_write_word(us_dev, PCI_EXP_DEVCTL,
 					   (devctl & ~PCI_EXP_DEVCTL_CERE));
-- 
1.8.3.1

^ permalink raw reply related

* [net-next  15/15] e1000e: resolve checkpatch JIFFIES_COMPARISON warning
From: Jeff Kirsher @ 2013-08-21  8:23 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1377073416-7872-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

WARNING:JIFFIES_COMPARISON: Comparing jiffies is almost always wrong;
prefer time_after, time_before and friends

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/ethtool.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index e4ebd7d..a8633b8 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -1665,7 +1665,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
 			ret_val = 13;	/* ret_val is the same as mis-compare */
 			break;
 		}
-		if (jiffies >= (time + 20)) {
+		if (time_after(jiffies, time + 20)) {
 			ret_val = 14;	/* error code for time out error */
 			break;
 		}
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 1/2] hso: Earlier catch of error condition
From: Daniel Gimpelevich @ 2013-08-21  8:43 UTC (permalink / raw)
  To: gregkh, j.dumon, linux-usb, netdev, linux-kernel

There is no need to get an interface specification if we know it's the
wrong one. 

Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
---
 drivers/net/usb/hso.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cba1d46..5fb36ed 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2886,6 +2886,11 @@ static int hso_probe(struct usb_interface *interface,
 	struct hso_shared_int *shared_int;
 	struct hso_device *tmp_dev = NULL;
 
+	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
+		dev_err(&interface->dev, "Not our interface\n");
+		return -ENODEV;
+	}
+
 	if_num = interface->altsetting->desc.bInterfaceNumber;
 
 	/* Get the interface/port specification from either driver_info or from
@@ -2895,10 +2900,6 @@ static int hso_probe(struct usb_interface *interface,
 	else
 		port_spec = hso_get_config_data(interface);
 
-	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
-		dev_err(&interface->dev, "Not our interface\n");
-		return -ENODEV;
-	}
 	/* Check if we need to switch to alt interfaces prior to port
 	 * configuration */
 	if (interface->num_altsetting > 1)
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 2/2] hso: Fix stack corruption on some architectures
From: Daniel Gimpelevich @ 2013-08-21  8:43 UTC (permalink / raw)
  To: gregkh, j.dumon, linux-usb, netdev, linux-kernel

As Sergei Shtylyov explained in the #mipslinux IRC channel: 
[Mon 2013-08-19 12:28:21 PM PDT] <headless> guys, are you sure it's not "DMA off stack" case?
[Mon 2013-08-19 12:28:35 PM PDT] <headless> it's a known stack corruptor on non-coherent arches
[Mon 2013-08-19 12:31:48 PM PDT] <DonkeyHotei> headless: for usb/ehci?
[Mon 2013-08-19 12:34:11 PM PDT] <DonkeyHotei> headless: explain
[Mon 2013-08-19 12:35:38 PM PDT] <headless> usb_control_msg() (or other such func) should not use buffer on stack. DMA from/to stack is prohibited
[Mon 2013-08-19 12:35:58 PM PDT] <headless> and EHCI uses DMA on control xfers (as well as all the others)

Signed-off-by: Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
---
 drivers/net/usb/hso.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 5fb36ed..86292e6 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2816,13 +2816,16 @@ exit:
 static int hso_get_config_data(struct usb_interface *interface)
 {
 	struct usb_device *usbdev = interface_to_usbdev(interface);
-	u8 config_data[17];
+	u8 *config_data = kmalloc(17, GFP_KERNEL);
 	u32 if_num = interface->altsetting->desc.bInterfaceNumber;
 	s32 result;
 
+	if (!config_data)
+		return -ENOMEM;
 	if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			    0x86, 0xC0, 0, 0, config_data, 17,
 			    USB_CTRL_SET_TIMEOUT) != 0x11) {
+		kfree(config_data);
 		return -EIO;
 	}
 
@@ -2873,6 +2876,7 @@ static int hso_get_config_data(struct usb_interface *interface)
 	if (config_data[16] & 0x1)
 		result |= HSO_INFO_CRC_BUG;
 
+	kfree(config_data);
 	return result;
 }
 
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH] Fix stack corruption on some architectures
From: Daniel Gimpelevich @ 2013-08-21  8:43 UTC (permalink / raw)
  To: David Miller; +Cc: j.dumon, gregkh, linux-usb, netdev, linux-kernel
In-Reply-To: <20130820.232959.1851816659900265372.davem@davemloft.net>

On Tue, 2013-08-20 at 23:29 -0700, David Miller wrote: 
> Please submit this with a more appropriate subject line.
> 
> After '[PATCH] ' there should be a subsystem or driver name
> prefix, followed up a semicolon.  Here it could be "hso: ",
> so something like:
> 
> [PATCH] hso: Fix stack corruption on some architectures.

Resent.

^ permalink raw reply

* Re: [PATCH net-next] ip6_tunnel: ensure to always have a link local address
From: Bjørn Mork @ 2013-08-21  9:02 UTC (permalink / raw)
  To: nicolas.dichtel; +Cc: David Miller, netdev, yoshfuji
In-Reply-To: <52146EE9.1060101@6wind.com>

Nicolas Dichtel <nicolas.dichtel@6wind.com> writes:
> Le 21/08/2013 08:48, David Miller a écrit :
>
>> Applied, but this brings up an issue I keep noticing.
>>
>> We talk about eth_random_addr() and "uniqueness" together all the
>> time, but the former never implies the latter.
>>
>> And we're going to run into situations where any conflicts generated
>> by this random address generater will cause reall failures.
>>
>> Therefore we'll have to create a system to prevent them.  Probably
>> using some simple table that keeps track of the addresses we've
>> generated.
>>
> Ok, I will look at this.

Are eth_random_addr() collisions really any different than interfaces
having the same address for other reasons? Reality is that we never can
trust a mac address to be truly unique, regardless of source.  And most
of the time it doesn't matter.  There is no problem with two interfaces
having the same link local address as long as they are on different
links, for example.

What's important is that we deal with collisions gracefully in cases
where they do matter, allowing an administrator to fix the issue.  I
believe we already do that on DAD failure with any mac address derived
link local address, disabling IPv6 and logging the reason. 


Bjørn

^ permalink raw reply

* [PATCH next] drivers: net: can: c_can: add type cast from 'unsigned int' to 'int'
From: Chen Gang @ 2013-08-21  9:09 UTC (permalink / raw)
  To: wg, mkl, anilkumar, Tony Lindgren, jg1.han
  Cc: David Miller, linux-can, netdev

'priv->instance' may less than zero, so need a type cast, the related
warnings (allmodconfig, "EXTRA_CFLAGS=-W"):

  drivers/net/can/c_can/c_can_platform.c:198:3: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]


Signed-off-by: Chen Gang <gang.chen@asianux.com>
---
 drivers/net/can/c_can/c_can_platform.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index c6f838d..294ced3 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -195,7 +195,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
 
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res);
-		if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
+		if (IS_ERR(priv->raminit_ctrlreg) || (int)priv->instance < 0)
 			dev_info(&pdev->dev, "control memory is not used for raminit\n");
 		else
 			priv->raminit = c_can_hw_raminit;
-- 
1.7.7.6

^ permalink raw reply related

* linux-next: build warning after merge of the net-next tree
From: Stephen Rothwell @ 2013-08-21  9:10 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: linux-next, linux-kernel, dingtianhong

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

Hi all,

After merging the net-next tree, today's linux-next build (i386 defconfig
and probably others) produced this warning:

net/ipv6/addrconf.c: In function 'addrconf_notify':
net/ipv6/addrconf.c:2793:22: warning: 'link_dev' may be used uninitialized in this function [-Wuninitialized]
net/ipv6/addrconf.c:2802:21: note: 'link_dev' was declared here

Introduced by commit df8372ca747f ("ipv6: fix checkpatch errors in
net/ipv6/addrconf.c").  It looks like here are some missing braces.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

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

^ permalink raw reply

* (unknown), 
From: gcb @ 2013-08-21  9:10 UTC (permalink / raw)
  To: smith.larry22


My wife and I won the Euro Millions Lottery of 41 Million British Pounds and we have decided to donate 1.5 million British Pounds to 6 individuals worldwide as our own charity project. Your email address was among the emails which were submitted to us by the Google, Inc as a web user, which was used for the draw with an electronic balloting system your email address came out as the 4th lucky beneficiary world wide.
To verify, please see our interview by visiting the web page below: http://www.dailymail.co.uk/news/article-2091124/EuroMillions-winners-Gareth-Catherine-Bull-scoop-41MILLION-lotto-jackpot.html
Send the below information for urgent processing.
Full Name:
Mobile No:
Age:
Country:
Send your response to

Congratulations once again,
Best Regards,
Gareth & Catherine Bull
gcb.foundation@postafiok.hu

^ permalink raw reply

* Re: [PATCH next] drivers: net: can: c_can: add type cast from 'unsigned int' to 'int'
From: Marc Kleine-Budde @ 2013-08-21  9:45 UTC (permalink / raw)
  To: Chen Gang
  Cc: wg, anilkumar, Tony Lindgren, jg1.han, David Miller, linux-can,
	netdev
In-Reply-To: <521483CD.8050907@asianux.com>

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

On 08/21/2013 11:09 AM, Chen Gang wrote:
> 'priv->instance' may less than zero, so need a type cast, the related
> warnings (allmodconfig, "EXTRA_CFLAGS=-W"):
> 
>   drivers/net/can/c_can/c_can_platform.c:198:3: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]

Tnx, I've tweaked the commit message a bit, will send a v2.

Marc
-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply

* sun4i_handle_irq: WARNING at net/ipv4/tcp_input.c:2711 tcp_fastretrans_alert
From: Richard GENOUD @ 2013-08-21  9:47 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: Stefan Roese, linux-arm-kernel, linux-kernel, netdev

Hi Maxime, Stephan

I just realise that, *sometimes*, I have some warnings on my cubieboard
(6 since the 22 of july, and the board is runnning 24/24).
It has happened also on 3.10 + emac patches.
Here it is:
[27224.060000] ------------[ cut here ]------------
[27224.070000] WARNING: CPU: 0 PID: 0 at net/ipv4/tcp_input.c:2711 tcp_fastretrans_alert+0x717/0x734()
[27224.080000] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc6-00010-g54f11ec #8
[27224.080000] [<c000f231>] (unwind_backtrace+0x1/0x98) from [<c000e2b7>] (show_stack+0xb/0xc)
[27224.090000] [<c000e2b7>] (show_stack+0xb/0xc) from [<c0013cd3>] (warn_slowpath_common+0x43/0x5c)
[27224.100000] [<c0013cd3>] (warn_slowpath_common+0x43/0x5c) from [<c0013d6d>] (warn_slowpath_null+0x11/0x14)
[27224.110000] [<c0013d6d>] (warn_slowpath_null+0x11/0x14) from [<c015eadf>] (tcp_fastretrans_alert+0x717/0x734)
[27224.120000] [<c015eadf>] (tcp_fastretrans_alert+0x717/0x734) from [<c015f32b>] (tcp_ack+0x6af/0x984)
[27224.130000] [<c015f32b>] (tcp_ack+0x6af/0x984) from [<c015fcab>] (tcp_rcv_established+0x93/0x3ec)
[27224.140000] [<c015fcab>] (tcp_rcv_established+0x93/0x3ec) from [<c0165621>] (tcp_v4_do_rcv+0xa1/0x160)
[27224.150000] [<c0165621>] (tcp_v4_do_rcv+0xa1/0x160) from [<c0167129>] (tcp_v4_rcv+0x4e9/0x500)
[27224.160000] [<c0167129>] (tcp_v4_rcv+0x4e9/0x500) from [<c015025d>] (ip_local_deliver_finish+0x79/0x180)
[27224.170000] [<c015025d>] (ip_local_deliver_finish+0x79/0x180) from [<c01500a1>] (ip_rcv_finish+0xc9/0x20c)
[27224.180000] [<c01500a1>] (ip_rcv_finish+0xc9/0x20c) from [<c0129493>] (__netif_receive_skb_core+0x287/0x3dc)
[27224.190000] [<c0129493>] (__netif_receive_skb_core+0x287/0x3dc) from [<c0129a8b>] (process_backlog+0x5b/0xd0)
[27224.200000] [<c0129a8b>] (process_backlog+0x5b/0xd0) from [<c012bc6f>] (net_rx_action+0x5f/0xe8)
[27224.200000] [<c012bc6f>] (net_rx_action+0x5f/0xe8) from [<c0015fc9>] (__do_softirq+0x91/0x134)
[27224.210000] [<c0015fc9>] (__do_softirq+0x91/0x134) from [<c0016251>] (irq_exit+0x59/0x80)
[27224.220000] [<c0016251>] (irq_exit+0x59/0x80) from [<c000d00d>] (handle_IRQ+0x21/0x54)
[27224.230000] [<c000d00d>] (handle_IRQ+0x21/0x54) from [<c00083ef>] (sun4i_handle_irq+0x1f/0x30)
[27224.240000] [<c00083ef>] (sun4i_handle_irq+0x1f/0x30) from [<c000ea1b>] (__irq_svc+0x3b/0x5c)
[27224.250000] Exception stack(0xc0287f70 to 0xc0287fb8)
[27224.250000] 7f60:                                     00000000 00000000 00000000 00000000
[27224.260000] 7f80: c0286000 c02ad7fd 00000001 c02ad7fd c028e084 413fc082 00000000 00000000
[27224.270000] 7fa0: 01000000 c0287fb8 c000d115 c000d116 40000033 ffffffff
[27224.270000] [<c000ea1b>] (__irq_svc+0x3b/0x5c) from [<c000d116>] (arch_cpu_idle+0x16/0x1c)
[27224.280000] [<c000d116>] (arch_cpu_idle+0x16/0x1c) from [<c002e69d>] (cpu_startup_entry+0x35/0xa0)
[27224.290000] [<c002e69d>] (cpu_startup_entry+0x35/0xa0) from [<c026f75f>] (start_kernel+0x1af/0x1f0)
[27224.300000] ---[ end trace 15641276e08fba8a ]---

Best regards,
Richard

^ permalink raw reply

* Re: [systemd-devel] [PATCH] netns: unix: only allow to find out unix socket in same net namespace
From: Kay Sievers @ 2013-08-21  9:51 UTC (permalink / raw)
  To: Gao feng
  Cc: systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	libvir-list-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA, Linux Containers,
	Eric W. Biederman, lxc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <52146AC2.5070409-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org>

On Wed, Aug 21, 2013 at 9:22 AM, Gao feng <gaofeng-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org> wrote:
> On 08/21/2013 03:06 PM, Eric W. Biederman wrote:

>> I suspect libvirt should simply not share /run or any other normally
>> writable directory with the host.  Sharing /run /var/run or even /tmp
>> seems extremely dubious if you want some kind of containment, and
>> without strange things spilling through.

Right, /run or /var cannot be shared. It's not only about sockets,
many other things will also go really wrong that way.

> right now I only take note of the unix socket /run/systemd/private,
> but there may have many similar unix sockets, they can exist in any
> path. the strange problems will still happen.
>
> anyway, I will send a patch to setup a fresh tmpfs for the /run directory of
> container first.

This is what systemd-nspawn does for a container setup:
  http://cgit.freedesktop.org/systemd/systemd/tree/src/nspawn/nspawn.c#n350

Kay

^ permalink raw reply

* Re: [systemd-devel] [PATCH] netns: unix: only allow to find out unix socket in same net namespace
From: Daniel P. Berrange @ 2013-08-21  9:56 UTC (permalink / raw)
  To: Kay Sievers
  Cc: systemd-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	libvir-list-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA, Linux Containers,
	lxc-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, Eric W. Biederman
In-Reply-To: <CAPXgP120YUEVnFiD0uPnqeO4x=5oRvHL79-cX5CnmEWc3d5mvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Wed, Aug 21, 2013 at 11:51:53AM +0200, Kay Sievers wrote:
> On Wed, Aug 21, 2013 at 9:22 AM, Gao feng <gaofeng-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org> wrote:
> > On 08/21/2013 03:06 PM, Eric W. Biederman wrote:
> 
> >> I suspect libvirt should simply not share /run or any other normally
> >> writable directory with the host.  Sharing /run /var/run or even /tmp
> >> seems extremely dubious if you want some kind of containment, and
> >> without strange things spilling through.
> 
> Right, /run or /var cannot be shared. It's not only about sockets,
> many other things will also go really wrong that way.

Libvirt already allows the app defining the container config to
set private mounts for any directory including /run and /var.

If an admin or app wants to run systemd inside a container, it is
their responsibility to ensure they setup the filesystem in a
suitable manner. Libvirt is not going to enforce use of a private
/run or /var, since that's a policy decision for a specific
use case.


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

^ permalink raw reply

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
From: liujunliang_ljl @ 2013-08-21 10:02 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: gregkh, linux-usb, netdev, linux-kernel, sunhecheng
In-Reply-To: <201308201850095789331@163.com>

Dear Ben :

		1,  please give me email address of David Miller, and Thanks a lot.

		2,  please check the new sr9700 device driver which is checked by the script tools
			
				scripts/checkpatch.pl 
			and the attachment file is the result of scripts/checkpatch.pl patch-commit-20130821

			I'm sorry that I'm still finding the way to signed-off

		3, Thanks again for your correct suggestion and Please check the new device driver patch.
		
[PATCH] :  
  
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * 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/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */




2013-08-21 



liujunliang_ljl 



发件人: Ben Hutchings 
发送时间: 2013-08-20  21:36:50 
收件人: liujunliang_ljl 
抄送: gregkh; linux-usb; netdev; linux-kernel; sunhecheng 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
On Tue, 2013-08-20 at 18:50 +0800, liujunliang_ljl wrote:
> Dear Gregkh & all :
> 
>  I am the software engineer Liu Junliang from ShenZhen CoreChips high technology company, on the market of SR9700 chip is designed and owned by us. 
>         SR9700 is a type of USB to Ethernet Converter and is compatible with USB 1.1 protocol, We want to merge SR9700 device driver into the Linux Kernel. The following is the Linux 3.10.7 version patch for SR9700, Please give us the assessment and support.
>         Thanks a lot.
As this is a net driver, the relevant maintainer is David Miller and not
Greg.
There are some style errors here which can be found using
scripts/checkpatch.pl.  You'll need to fix those and re-submit.  I'll
point out some more problems inline.
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
> +{
> + struct usbnet *dev = netdev_priv(net);
> + __le16 *ebuf = (__le16 *) data;
> + int i;
> +
> + /* access is 16bit */
> + if ((eeprom->offset % 2) || (eeprom->len % 2))
> + return -EINVAL;
You're really supposed to handle these cases by shifting as necessary.
> + for (i = 0; i < eeprom->len / 2; i++) {
> + if (sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]) < 0)
> + return -EINVAL;
You should pass up the error code, not substitute -EINVAL.
[...]
> +static void sr9700_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
> +{
> + /* Inherit standard device info */
> + usbnet_get_drvinfo(net, info);
> + info->eedump_len = SR_EEPROM_LEN;
You don't need to set eedump_len; the ethtool core will set it after
calling sr9700_get_eeprom_len().  So you don't need your own
implementation of get_drvinfo at all.
[...]
> +static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
> +{
[...]
> + /* read MAC */
> + if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
> + printk(KERN_ERR "Error reading MAC address\n");
> + ret = -ENODEV;
> + goto out;
> + }
[...]
I think this should read the MAC address from EEPROM and copy it to both
dev_addr to perm_addr.  MAC address changes should not persist if the
driver is reloaded.
Ben.
-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related

* Re: [PATCH next] drivers: net: can: c_can: add type cast from 'unsigned int' to 'int'
From: Chen Gang @ 2013-08-21 10:04 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: wg, anilkumar, Tony Lindgren, jg1.han, David Miller, linux-can,
	netdev
In-Reply-To: <52148C1E.3020709@pengutronix.de>

On 08/21/2013 05:45 PM, Marc Kleine-Budde wrote:
> On 08/21/2013 11:09 AM, Chen Gang wrote:
>> 'priv->instance' may less than zero, so need a type cast, the related
>> warnings (allmodconfig, "EXTRA_CFLAGS=-W"):
>>
>>   drivers/net/can/c_can/c_can_platform.c:198:3: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
> 
> Tnx, I've tweaked the commit message a bit, will send a v2.
> 

OK, thanks.

> Marc
> 


-- 
Chen Gang

^ permalink raw reply

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
From: liujunliang_ljl @ 2013-08-21 10:06 UTC (permalink / raw)
  To: Francois Romieu; +Cc: gregkh, sunhecheng, linux-usb, netdev, linux-kernel
In-Reply-To: <20130820204606.GB26241@electric-eye.fr.zoreil.com>

Dear Francois Romieu :

	1, all the format problems have been fixed
	
	2, sr9700.h registers definition is re-written

	3, Thanks for your detail checking and I have beed scripts/checkpatch.pl the patch and please check it.

[PATCH] :
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * 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/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */



2013-08-21 



liujunliang_ljl 



发件人: Francois Romieu 
发送时间: 2013-08-21  04:46:12 
收件人: liujunliang_ljl 
抄送: gregkh; sunhecheng; linux-usb; netdev; linux-kernel 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
liujunliang_ljl <liujunliang_ljl@163.com> :
[...]
> We want to merge SR9700 device driver into the Linux Kernel. The following
> is the Linux 3.10.7 version patch for SR9700, Please give us the assessment
> and support.
Welcome. Go ahead.
[...]
> diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
> new file mode 100644
> index 0000000..6a6429a
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + int err;
> +
> + err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
> + 0, reg, data, length);
err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
      length);
> + if(err != length && err >= 0)
         ^^ missing space
> + err = -EINVAL;
> + return err;
> +}
> +
> +static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + int err;
> +
> + err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + 0, reg, data, length);
See above.
> + if (err >= 0 && err < length)
> + err = -EINVAL;
> + 
> + return err;
> +}
> +
> +static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
> +{
> + return sr_read(dev, reg, 1, value);
> +}
> +
> +static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
> +{
> + return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +        value, reg, NULL, 0);
Sic.
> +}
> +
> +static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + 0, reg, data, length);
Sic.
> +}
> +
> +static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
> +{
> + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + value, reg, NULL, 0);
Sic.
> +}
> +
> +static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
> +{
> + int ret, i;
> +
> + mutex_lock(&dev->phy_mutex);
> +
> + sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> + sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
> +
> + for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> + u8 tmp = 0;
> +
> + udelay(1);
> + ret = sr_read_reg(dev, EPCR, &tmp);
> + if (ret < 0)
> + goto out;
goto out_unlock;
> +
> + /* ready */
> + if ((tmp & 1) == 0)
if ((tmp & EPCR_ERRE) == 0)
> + break;
> + }
> +
> + if (i >= SR_SHARE_TIMEOUT) {
> + netdev_err(dev->net, "%s read timed out!", phy ? "phy" : "eeprom");
> + ret = -EIO;
> + goto out;
> + }
> +
> + sr_write_reg(dev, EPCR, 0x0);
> + ret = sr_read(dev, EPDR, 2, value);
> +
> + netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d",
> +        phy, reg, *value, ret);
> +
> + out:
   ^ please remove space.
> + mutex_unlock(&dev->phy_mutex);
> + return ret;
> +}
> +
> +static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
> +{
> + int ret, i;
> +
> + mutex_lock(&dev->phy_mutex);
> +
> + ret = sr_write(dev, EPDR, 2, &value);
> + if (ret < 0)
> + goto out;
> +
> + sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> + sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
> +
> + for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> + u8 tmp = 0;
> +
> + udelay(1);
> + ret = sr_read_reg(dev, EPCR, &tmp);
> + if (ret < 0)
> + goto out;
> +
> + /* ready */
> + if ((tmp & 1) == 0)
> + break;
> + }
The 11 lines above are identical in sr_share_read_word. Please refactor.
[...]
> +static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
> +{
> + struct usbnet *dev = netdev_priv(netdev);
> +
> + __le16 res;
Excess empty line.
> + int rc = 0;
> +
> + if (phy_id) {
> + netdev_dbg(dev->net, "Only internal phy supported");
> + return 0;
> + }
> +
> + /* Access NSR_LINKST bit for link status instead of MII_BMSR */
> + if(loc == MII_BMSR){
         ^^               ^^
Missing spaces.
> + u8 value;
Excess tabs and missing empty line.
> + sr_read_reg(dev, NSR, &value);
> + if(value & NSR_LINKST) {
Excess tabs, missing spaces, useless "{".
> + rc = 1;
> + }
> + }
> + sr_share_read_word(dev, 1, loc, &res);
> + if(rc == 1)
> + return (le16_to_cpu(res) | BMSR_LSTATUS);
> + else
> + return (le16_to_cpu(res) & ~BMSR_LSTATUS);
Excess "(" (aka "return is not a function").
[...]
> +/*-------------------------------------------------------------------------------------------*/
Just say no.
[...]
> +static void sr9700_set_multicast(struct net_device *net)
> +{
> + struct usbnet *dev = netdev_priv(net);
> + /* We use the 20 byte dev->data for our 8 byte filter buffer
> +  * to avoid allocating memory that is tricky to free later */
> + u8 *hashes = (u8 *) & dev->data;
                             ^extraneous space
> + u8 rx_ctl = 0x31; // enable, disable_long, disable_crc
u8 rx_ctl = RCR_ALL | RCR_DIS_CRC | RCR_DIS_LONG;
> +
> + memset(hashes, 0x00, SR_MCAST_SIZE);
> + hashes[SR_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
Use #define.
> +
> +        if (net->flags & IFF_PROMISC) {
   ^^^^^^^^ should use tab, not space
> +                rx_ctl |= 0x02;
   ^^^... sic
> +        } else if (net->flags & IFF_ALLMULTI ||
> +                   netdev_mc_count(net) > SR_MCAST_MAX) {
> +                rx_ctl |= 0x04;
> +        } else if (!netdev_mc_empty(net)) {
> +                struct netdev_hw_addr *ha;
> + 
> +                netdev_for_each_mc_addr(ha, net) {
> +                        u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
> +                        hashes[crc >> 3] |= 1 << (crc & 0x7);
> +                }
> +        }
   ^^^... etc.
> +
> + sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
> + sr_write_reg_async(dev, RCR, rx_ctl);
> +}
> +
> +static int sr9700_set_mac_address(struct net_device *net, void *p)
> +{
> + struct sockaddr *addr = p;
> + struct usbnet *dev = netdev_priv(net);
Long declaration lines first please.
> +
> + if (!is_valid_ether_addr(addr->sa_data)) {
> + dev_err(&net->dev, "not setting invalid mac address %pM\n",
> + addr->sa_data);
dev_err(&net->dev, "not setting invalid mac address %pM\n",
addr->sa_data);
[...]
> +static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +{
> + int len;
> + struct sk_buff *sr_skb;
> +
> + /* format:
> +    b0: rx status
> +    b1: packet length (incl crc) low
> +    b2: packet length (incl crc) high
> +    b3..n-4: packet data
> +    bn-3..bn: ethernet crc
> +  */
> +
> + if (unlikely(skb->len < SR_RX_OVERHEAD)) {
> + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
> + return 0;
> + }
> +
> + /*
> +  * Each packet contains multiple skbs
> +  */
> + while (skb->len > SR_RX_OVERHEAD)
> + {
K&R please.
[...]
> +static struct usb_driver sr9700_usb_driver = {
> + .name = "sr9700",
> + .id_table = products,
> + .probe = usbnet_probe,
> + .disconnect = usbnet_disconnect,
> + .suspend = usbnet_suspend,
> + .resume = usbnet_resume,
> + .disable_hub_initiated_lpm = 1,
Use <tab>=.
[...]
> diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
> new file mode 100644
> index 0000000..d9fe82d
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.h
> @@ -0,0 +1,152 @@
> +/*
> + * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
> + *
> + * Author : liujl <liujunliang_ljl@163.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + */
> +
> +/* sr9700 spec. register table on android platform */
> +/* Registers */
> +#define NCR 0x00
> +#define NSR 0x01
[...]
> +/* Bit definition for registers */
> +// Network Control Reg
> +#define NCR_RST (1 << 0)
> +#define NCR_LBK (3 << 1)
> +#define NCR_FDX (1 << 3)
> +#define NCR_WAKEEN (1 << 6)
You may group these with the register declarations above. Use an
offset to improve readability and separate registers from fields.
See drivers/net/ethernet/broadcom/tg3.h for instance.
-- 
Ueimor

^ permalink raw reply related

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
From: liujunliang_ljl @ 2013-08-21 10:07 UTC (permalink / raw)
  To: Joe Perches, Francois Romieu
  Cc: gregkh, sunhecheng, linux-usb, netdev, linux-kernel
In-Reply-To: <1377032302.2016.75.camel@joe-AO722>

Dear Joe :

		Thanks a lot and I have been fixed all the problems mentioned above. please check the following patch and thanks again. 

[PATCH] :
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * 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/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */





2013-08-21 



liujunliang_ljl 



发件人: Joe Perches 
发送时间: 2013-08-21  04:58:27 
收件人: Francois Romieu 
抄送: liujunliang_ljl; gregkh; sunhecheng; linux-usb; netdev; linux-kernel 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
On Tue, 2013-08-20 at 22:46 +0200, Francois Romieu wrote:
> liujunliang_ljl <liujunliang_ljl@163.com> :
> > + if (i >= SR_SHARE_TIMEOUT) {
> > + netdev_err(dev->net, "%s read timed out!", phy ? "phy" : "eeprom");
netdev_<level>, like almost all other printk
messages needs a terminating "\n" newline to
avoid any possible message interleaving by other
printks.
> > + if (!is_valid_ether_addr(addr->sa_data)) {
> > + dev_err(&net->dev, "not setting invalid mac address %pM\n",
> > + addr->sa_data);
> 
>  dev_err(&net->dev, "not setting invalid mac address %pM\n",
>  addr->sa_data);
prefer netdev_<level> to dev_<level> where possible.

^ permalink raw reply related

* [PATCH 0/2] net: can: use platform_set_drvdata()
From: Libo Chen @ 2013-08-21 10:14 UTC (permalink / raw)
  To: wg, mkl; +Cc: davem, linux-can, lizefan, netdev, linux-kernel, libo.chen

Use the wrapper functions for getting and setting the driver data using
platform_device instead of using dev_set_drvdata() with &pdev->dev,
so we can directly pass a struct platform_device.

Libo Chen (2):
  net: can: at91_can: use platform_set_drvdata()
  net: can: flexcan: use platform_set_drvdata()

 drivers/net/can/at91_can.c |    2 +-
 drivers/net/can/flexcan.c  |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)



^ permalink raw reply

* [PATCH 1/2] net: can: at91_can: use platform_set_drvdata()
From: Libo Chen @ 2013-08-21 10:15 UTC (permalink / raw)
  To: wg, mkl; +Cc: davem, linux-can, netdev, linux-kernel, lizefan, libo.chen

Use the wrapper functions for getting and setting the driver data using
platform_device instead of using dev_set_drvdata() with &pdev->dev,
so we can directly pass a struct platform_device.

Signed-off-by: Libo Chen <libo.chen@huawei.com>
---
 drivers/net/can/at91_can.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index dbbe97a..3b1ff61 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1355,7 +1355,7 @@ static int at91_can_probe(struct platform_device *pdev)
 	if (at91_is_sam9263(priv))
 		dev->sysfs_groups[0] = &at91_sysfs_attr_group;
 
-	dev_set_drvdata(&pdev->dev, dev);
+	platform_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	err = register_candev(dev);
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/2] net: can: flexcan: use platform_set_drvdata()
From: Libo Chen @ 2013-08-21 10:15 UTC (permalink / raw)
  To: wg, mkl; +Cc: linux-can, davem, netdev, linux-kernel, lizefan, libo.chen

Use the wrapper functions for getting and setting the driver data using
platform_device instead of using dev_set_drvdata() with &pdev->dev,
so we can directly pass a struct platform_device.

Signed-off-by: Libo Chen <libo.chen@huawei.com>
---
 drivers/net/can/flexcan.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 7b0be09..9978de7 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -1087,7 +1087,7 @@ static int flexcan_probe(struct platform_device *pdev)
 
 	netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
 
-	dev_set_drvdata(&pdev->dev, dev);
+	platform_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	err = register_flexcandev(dev);
-- 
1.7.1

^ permalink raw reply related


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