Netdev List
 help / color / mirror / Atom feed
* [net-next-2.6 PATCH 3/3] enic: Add support for port profile association on a enic SRIOV VF
From: Roopa Prabhu @ 2011-09-22 13:44 UTC (permalink / raw)
  To: netdev; +Cc: davem
In-Reply-To: <20110922134410.2145.72210.stgit@savbu-pc100.cisco.com>

From: Roopa Prabhu <roprabhu@cisco.com>

This patch touchs most of the enic port profile handling code.
Tried to break it into sub patches without success.

The patch mainly does the following:
- Port profile operations for a SRIOV VF are modified to work
  only via its PF
- Changes the port profile static struct in struct enic to a pointer.
  This is because a SRIOV PF has to now hold the port profile information
  for all its VF's
- Moved address registration for VF's during port profile ASSOCIATE time
- Most changes in port profile handling code are changes related to indexing
  into the port profile struct array of a PF for the VF port profile
  information

Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Signed-off-by: Sujith Sankar <ssujith@cisco.com>
Signed-off-by: Christian Benvenuti <benve@cisco.com>
Signed-off-by: David Wang <dwang2@cisco.com>
---
 drivers/net/ethernet/cisco/enic/enic.h      |    3 
 drivers/net/ethernet/cisco/enic/enic_main.c |  118 ++++++++++-------
 drivers/net/ethernet/cisco/enic/enic_pp.c   |  192 +++++++++++++++++++++------
 drivers/net/ethernet/cisco/enic/enic_pp.h   |   15 ++
 4 files changed, 232 insertions(+), 96 deletions(-)


diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 8c5cfb5..fe0c29a 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -96,7 +96,7 @@ struct enic {
 #ifdef CONFIG_PCI_IOV
 	u32 num_vfs;
 #endif
-	struct enic_port_profile pp;
+	struct enic_port_profile *pp;
 
 	/* work queue cache line section */
 	____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
@@ -130,5 +130,6 @@ static inline struct device *enic_get_dev(struct enic *enic)
 void enic_reset_addr_lists(struct enic *enic);
 int enic_sriov_enabled(struct enic *enic);
 int enic_is_valid_vf(struct enic *enic, int vf);
+int enic_is_dynamic(struct enic *enic);
 
 #endif /* _ENIC_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 154cb99..bf95348 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -122,7 +122,7 @@ static const struct enic_stat enic_rx_stats[] = {
 static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
 static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
 
-static int enic_is_dynamic(struct enic *enic)
+int enic_is_dynamic(struct enic *enic)
 {
 	return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
 }
@@ -1054,15 +1054,15 @@ static void enic_tx_timeout(struct net_device *netdev)
 static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
 	struct enic *enic = netdev_priv(netdev);
+	struct enic_port_profile *pp;
+	int err;
 
-	if (vf != PORT_SELF_VF)
-		return -EOPNOTSUPP;
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
 
-	/* Ignore the vf argument for now. We can assume the request
-	 * is coming on a vf.
-	 */
 	if (is_valid_ether_addr(mac)) {
-		memcpy(enic->pp.vf_mac, mac, ETH_ALEN);
+		memcpy(pp->vf_mac, mac, ETH_ALEN);
 		return 0;
 	} else
 		return -EINVAL;
@@ -1073,71 +1073,74 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
 {
 	struct enic *enic = netdev_priv(netdev);
 	struct enic_port_profile prev_pp;
+	struct enic_port_profile *pp;
 	int err = 0, restore_pp = 1;
 
-	/* don't support VFs, yet */
-	if (vf != PORT_SELF_VF)
-		return -EOPNOTSUPP;
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
 
 	if (!port[IFLA_PORT_REQUEST])
 		return -EOPNOTSUPP;
 
-	memcpy(&prev_pp, &enic->pp, sizeof(enic->pp));
-	memset(&enic->pp, 0, sizeof(enic->pp));
+	memcpy(&prev_pp, pp, sizeof(*enic->pp));
+	memset(pp, 0, sizeof(*enic->pp));
 
-	enic->pp.set |= ENIC_SET_REQUEST;
-	enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+	pp->set |= ENIC_SET_REQUEST;
+	pp->request = nla_get_u8(port[IFLA_PORT_REQUEST]);
 
 	if (port[IFLA_PORT_PROFILE]) {
-		enic->pp.set |= ENIC_SET_NAME;
-		memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+		pp->set |= ENIC_SET_NAME;
+		memcpy(pp->name, nla_data(port[IFLA_PORT_PROFILE]),
 			PORT_PROFILE_MAX);
 	}
 
 	if (port[IFLA_PORT_INSTANCE_UUID]) {
-		enic->pp.set |= ENIC_SET_INSTANCE;
-		memcpy(enic->pp.instance_uuid,
+		pp->set |= ENIC_SET_INSTANCE;
+		memcpy(pp->instance_uuid,
 			nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
 	}
 
 	if (port[IFLA_PORT_HOST_UUID]) {
-		enic->pp.set |= ENIC_SET_HOST;
-		memcpy(enic->pp.host_uuid,
+		pp->set |= ENIC_SET_HOST;
+		memcpy(pp->host_uuid,
 			nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
 	}
 
 	/* Special case handling: mac came from IFLA_VF_MAC */
 	if (!is_zero_ether_addr(prev_pp.vf_mac))
-		memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN);
+		memcpy(pp->mac_addr, prev_pp.vf_mac, ETH_ALEN);
 
-		if (is_zero_ether_addr(netdev->dev_addr))
-			random_ether_addr(netdev->dev_addr);
+	if (vf == PORT_SELF_VF && is_zero_ether_addr(netdev->dev_addr))
+		random_ether_addr(netdev->dev_addr);
 
-	err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp);
+	err = enic_process_set_pp_request(enic, vf, &prev_pp, &restore_pp);
 	if (err) {
 		if (restore_pp) {
 			/* Things are still the way they were: Implicit
 			 * DISASSOCIATE failed
 			 */
-			memcpy(&enic->pp, &prev_pp, sizeof(enic->pp));
+			memcpy(pp, &prev_pp, sizeof(*pp));
 		} else {
-			memset(&enic->pp, 0, sizeof(enic->pp));
-			memset(netdev->dev_addr, 0, ETH_ALEN);
+			memset(pp, 0, sizeof(*pp));
+			if (vf == PORT_SELF_VF)
+				memset(netdev->dev_addr, 0, ETH_ALEN);
 		}
 	} else {
 		/* Set flag to indicate that the port assoc/disassoc
 		 * request has been sent out to fw
 		 */
-		enic->pp.set |= ENIC_PORT_REQUEST_APPLIED;
+		pp->set |= ENIC_PORT_REQUEST_APPLIED;
 
 		/* If DISASSOCIATE, clean up all assigned/saved macaddresses */
-		if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) {
-			memset(enic->pp.mac_addr, 0, ETH_ALEN);
-			memset(netdev->dev_addr, 0, ETH_ALEN);
+		if (pp->request == PORT_REQUEST_DISASSOCIATE) {
+			memset(pp->mac_addr, 0, ETH_ALEN);
+			if (vf == PORT_SELF_VF)
+				memset(netdev->dev_addr, 0, ETH_ALEN);
 		}
 	}
 
-	memset(enic->pp.vf_mac, 0, ETH_ALEN);
+	memset(pp->vf_mac, 0, ETH_ALEN);
 
 	return err;
 }
@@ -1147,26 +1150,31 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
 {
 	struct enic *enic = netdev_priv(netdev);
 	u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
+	struct enic_port_profile *pp;
 	int err;
 
-	if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED))
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
+	if (!(pp->set & ENIC_PORT_REQUEST_APPLIED))
 		return -ENODATA;
 
-	err = enic_process_get_pp_request(enic, enic->pp.request, &response);
+	err = enic_process_get_pp_request(enic, vf, pp->request, &response);
 	if (err)
 		return err;
 
-	NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
+	NLA_PUT_U16(skb, IFLA_PORT_REQUEST, pp->request);
 	NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
-	if (enic->pp.set & ENIC_SET_NAME)
+	if (pp->set & ENIC_SET_NAME)
 		NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
-			enic->pp.name);
-	if (enic->pp.set & ENIC_SET_INSTANCE)
+			pp->name);
+	if (pp->set & ENIC_SET_INSTANCE)
 		NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
-			enic->pp.instance_uuid);
-	if (enic->pp.set & ENIC_SET_HOST)
+			pp->instance_uuid);
+	if (pp->set & ENIC_SET_HOST)
 		NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
-			enic->pp.host_uuid);
+			pp->host_uuid);
 
 	return 0;
 
@@ -1600,10 +1608,9 @@ static int enic_open(struct net_device *netdev)
 	for (i = 0; i < enic->rq_count; i++)
 		vnic_rq_enable(&enic->rq[i]);
 
-	if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
-		enic_dev_add_addr(enic, enic->pp.mac_addr);
-	else
+	if (!enic_is_dynamic(enic))
 		enic_dev_add_station_addr(enic);
+
 	enic_set_rx_mode(netdev);
 
 	netif_wake_queue(netdev);
@@ -1651,9 +1658,8 @@ static int enic_stop(struct net_device *netdev)
 
 	netif_carrier_off(netdev);
 	netif_tx_disable(netdev);
-	if (enic_is_dynamic(enic) && !is_zero_ether_addr(enic->pp.mac_addr))
-		enic_dev_del_addr(enic, enic->pp.mac_addr);
-	else
+
+	if (!enic_is_dynamic(enic))
 		enic_dev_del_station_addr(enic);
 
 	for (i = 0; i < enic->wq_count; i++) {
@@ -2143,6 +2149,9 @@ static const struct net_device_ops enic_netdev_ops = {
 	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,
 	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,
 	.ndo_tx_timeout		= enic_tx_timeout,
+	.ndo_set_vf_port	= enic_set_vf_port,
+	.ndo_get_vf_port	= enic_get_vf_port,
+	.ndo_set_vf_mac		= enic_set_vf_mac,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= enic_poll_controller,
 #endif
@@ -2254,6 +2263,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 	int using_dac = 0;
 	unsigned int i;
 	int err;
+	int num_pps = 1;
 #ifdef CONFIG_PCI_IOV
 	int pos = 0;
 #endif
@@ -2363,17 +2373,26 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 				goto err_out_vnic_unregister;
 			}
 			enic->priv_flags |= ENIC_SRIOV_ENABLED;
+			num_pps = enic->num_vfs;
 		}
 	}
 
 #endif
+	/* Allocate structure for port profiles */
+	enic->pp = kzalloc(num_pps * sizeof(*enic->pp), GFP_KERNEL);
+	if (!enic->pp) {
+		pr_err("port profile alloc failed, aborting\n");
+		err = -ENOMEM;
+		goto err_out_disable_sriov;
+	}
+
 	/* Issue device open to get device in known state
 	 */
 
 	err = enic_dev_open(enic);
 	if (err) {
 		dev_err(dev, "vNIC dev open failed, aborting\n");
-		goto err_out_disable_sriov;
+		goto err_out_free_pp;
 	}
 
 	/* Setup devcmd lock
@@ -2497,6 +2516,8 @@ err_out_dev_deinit:
 	enic_dev_deinit(enic);
 err_out_dev_close:
 	vnic_dev_close(enic->vdev);
+err_out_free_pp:
+	kfree(enic->pp);
 err_out_disable_sriov:
 #ifdef CONFIG_PCI_IOV
 	if (enic_sriov_enabled(enic)) {
@@ -2537,6 +2558,7 @@ static void __devexit enic_remove(struct pci_dev *pdev)
 			enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
 		}
 #endif
+		kfree(enic->pp);
 		vnic_dev_unregister(enic->vdev);
 		enic_iounmap(enic);
 		pci_release_regions(pdev);
diff --git a/drivers/net/ethernet/cisco/enic/enic_pp.c b/drivers/net/ethernet/cisco/enic/enic_pp.c
index ffaa75d..22bf03a 100644
--- a/drivers/net/ethernet/cisco/enic/enic_pp.c
+++ b/drivers/net/ethernet/cisco/enic/enic_pp.c
@@ -29,10 +29,47 @@
 #include "enic_res.h"
 #include "enic.h"
 #include "enic_dev.h"
+#include "enic_pp.h"
 
-static int enic_set_port_profile(struct enic *enic)
+/*
+ * Checks validity of vf index that came in
+ * port profile request
+ */
+int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
+{
+	if (vf != PORT_SELF_VF) {
+#ifdef CONFIG_PCI_IOV
+		if (enic_sriov_enabled(enic)) {
+			if (vf < 0 || vf >= enic->num_vfs) {
+				*err = -EINVAL;
+				goto err_out;
+			}
+		} else {
+			*err = -EOPNOTSUPP;
+			goto err_out;
+		}
+#else
+		*err = -EOPNOTSUPP;
+		goto err_out;
+#endif
+	}
+
+	if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
+		*err = -EOPNOTSUPP;
+		goto err_out;
+	}
+
+	*err = 0;
+	return 1;
+
+err_out:
+	return 0;
+}
+
+static int enic_set_port_profile(struct enic *enic, int vf)
 {
 	struct net_device *netdev = enic->netdev;
+	struct enic_port_profile *pp;
 	struct vic_provinfo *vp;
 	const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
 	const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
@@ -41,7 +78,11 @@ static int enic_set_port_profile(struct enic *enic)
 	u8 *client_mac;
 	int err;
 
-	if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
+	if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
 		return -EINVAL;
 
 	vp = vic_provinfo_alloc(GFP_KERNEL, oui,
@@ -51,12 +92,18 @@ static int enic_set_port_profile(struct enic *enic)
 
 	VIC_PROVINFO_ADD_TLV(vp,
 		VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
-		strlen(enic->pp.name) + 1, enic->pp.name);
+		strlen(pp->name) + 1, pp->name);
 
-	if (!is_zero_ether_addr(enic->pp.mac_addr))
-		client_mac = enic->pp.mac_addr;
-	else
+	if (!is_zero_ether_addr(pp->mac_addr)) {
+		client_mac = pp->mac_addr;
+	} else if (vf == PORT_SELF_VF) {
 		client_mac = netdev->dev_addr;
+	} else {
+		netdev_err(netdev, "Cannot find pp mac address "
+			"for VF %d\n", vf);
+		err = -EINVAL;
+		goto add_tlv_failure;
+	}
 
 	VIC_PROVINFO_ADD_TLV(vp,
 		VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
@@ -67,15 +114,15 @@ static int enic_set_port_profile(struct enic *enic)
 		VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
 		sizeof(client_mac_str), client_mac_str);
 
-	if (enic->pp.set & ENIC_SET_INSTANCE) {
-		sprintf(uuid_str, "%pUB", enic->pp.instance_uuid);
+	if (pp->set & ENIC_SET_INSTANCE) {
+		sprintf(uuid_str, "%pUB", pp->instance_uuid);
 		VIC_PROVINFO_ADD_TLV(vp,
 			VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
 			sizeof(uuid_str), uuid_str);
 	}
 
-	if (enic->pp.set & ENIC_SET_HOST) {
-		sprintf(uuid_str, "%pUB", enic->pp.host_uuid);
+	if (pp->set & ENIC_SET_HOST) {
+		sprintf(uuid_str, "%pUB", pp->host_uuid);
 		VIC_PROVINFO_ADD_TLV(vp,
 			VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
 			sizeof(uuid_str), uuid_str);
@@ -85,7 +132,9 @@ static int enic_set_port_profile(struct enic *enic)
 		VIC_GENERIC_PROV_TLV_OS_TYPE,
 		sizeof(os_type), &os_type);
 
-	err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp));
+	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
+		vic_provinfo_size(vp));
+	err = enic_dev_status_to_errno(err);
 
 add_tlv_failure:
 	vic_provinfo_free(vp);
@@ -93,15 +142,16 @@ add_tlv_failure:
 	return err;
 }
 
-static int enic_unset_port_profile(struct enic *enic)
+static int enic_unset_port_profile(struct enic *enic, int vf)
 {
 	int err;
 
-	err = enic_vnic_dev_deinit(enic);
+	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
 	if (err)
 		return enic_dev_status_to_errno(err);
 
-	enic_reset_addr_lists(enic);
+	if (vf == PORT_SELF_VF)
+		enic_reset_addr_lists(enic);
 
 	return 0;
 }
@@ -115,17 +165,18 @@ static int enic_are_pp_different(struct enic_port_profile *pp1,
 		!!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN);
 }
 
-static int enic_pp_preassociate(struct enic *enic,
+static int enic_pp_preassociate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_disassociate(struct enic *enic,
+static int enic_pp_disassociate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_preassociate_rr(struct enic *enic,
+static int enic_pp_preassociate_rr(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp);
-static int enic_pp_associate(struct enic *enic,
+static int enic_pp_associate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp);
 
-static int (*enic_pp_handlers[])(struct enic *enic,
-		struct enic_port_profile *prev_state, int *restore_pp) = {
+static int (*enic_pp_handlers[])(struct enic *enic, int vf,
+		struct enic_port_profile *prev_state,
+		int *restore_pp) = {
 	[PORT_REQUEST_PREASSOCIATE]	= enic_pp_preassociate,
 	[PORT_REQUEST_PREASSOCIATE_RR]	= enic_pp_preassociate_rr,
 	[PORT_REQUEST_ASSOCIATE]	= enic_pp_associate,
@@ -135,28 +186,49 @@ static int (*enic_pp_handlers[])(struct enic *enic,
 static const int enic_pp_handlers_count =
 			sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers);
 
-static int enic_pp_preassociate(struct enic *enic,
+static int enic_pp_preassociate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp)
 {
 	return -EOPNOTSUPP;
 }
 
-static int enic_pp_disassociate(struct enic *enic,
+static int enic_pp_disassociate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp)
 {
-	return enic_unset_port_profile(enic);
+	struct net_device *netdev = enic->netdev;
+	struct enic_port_profile *pp;
+	int err;
+
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
+	/* Deregister mac addresses */
+	if (!is_zero_ether_addr(pp->mac_addr))
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
+			pp->mac_addr);
+	else if (!is_zero_ether_addr(netdev->dev_addr))
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
+			netdev->dev_addr);
+
+	return enic_unset_port_profile(enic, vf);
 }
 
-static int enic_pp_preassociate_rr(struct enic *enic,
+static int enic_pp_preassociate_rr(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp)
 {
+	struct enic_port_profile *pp;
 	int err;
 	int active = 0;
 
-	if (enic->pp.request != PORT_REQUEST_ASSOCIATE) {
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
+	if (pp->request != PORT_REQUEST_ASSOCIATE) {
 		/* If pre-associate is not part of an associate.
 		We always disassociate first */
-		err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic,
+		err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
 			prev_pp, restore_pp);
 		if (err)
 			return err;
@@ -166,29 +238,39 @@ static int enic_pp_preassociate_rr(struct enic *enic,
 
 	*restore_pp = 0;
 
-	err = enic_set_port_profile(enic);
+	err = enic_set_port_profile(enic, vf);
 	if (err)
 		return err;
 
 	/* If pre-associate is not part of an associate. */
-	if (enic->pp.request != PORT_REQUEST_ASSOCIATE)
-		err = enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+	if (pp->request != PORT_REQUEST_ASSOCIATE) {
+		/* Enable device as standby */
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
+			active);
+		err = enic_dev_status_to_errno(err);
+	}
 
 	return err;
 }
 
-static int enic_pp_associate(struct enic *enic,
+static int enic_pp_associate(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp)
 {
+	struct net_device *netdev = enic->netdev;
+	struct enic_port_profile *pp;
 	int err;
 	int active = 1;
 
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
 	/* Check if a pre-associate was called before */
 	if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
 		(prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
-			enic_are_pp_different(prev_pp, &enic->pp))) {
+			enic_are_pp_different(prev_pp, pp))) {
 		err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
-			enic, prev_pp, restore_pp);
+			enic, vf, prev_pp, restore_pp);
 		if (err)
 			return err;
 
@@ -196,28 +278,48 @@ static int enic_pp_associate(struct enic *enic,
 	}
 
 	err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
-			enic, prev_pp, restore_pp);
+			enic, vf, prev_pp, restore_pp);
 	if (err)
 		return err;
 
 	*restore_pp = 0;
 
-	return enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+	/* Enable device as active */
+	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
+	err = enic_dev_status_to_errno(err);
+	if (err)
+		return err;
+
+	/* Register mac address */
+	if (!is_zero_ether_addr(pp->mac_addr))
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
+			pp->mac_addr);
+	else if (!is_zero_ether_addr(netdev->dev_addr))
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
+			netdev->dev_addr);
+
+	return 0;
 }
 
-int enic_process_set_pp_request(struct enic *enic,
+int enic_process_set_pp_request(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp)
 {
-	if (enic->pp.request < enic_pp_handlers_count
-		&& enic_pp_handlers[enic->pp.request])
-		return enic_pp_handlers[enic->pp.request](enic,
-			prev_pp, restore_pp);
-	else
+	struct enic_port_profile *pp;
+	int err;
+
+	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
+	if (err)
+		return err;
+
+	if (pp->request >= enic_pp_handlers_count
+		|| !enic_pp_handlers[pp->request])
 		return -EOPNOTSUPP;
+
+	return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
 }
 
-int enic_process_get_pp_request(struct enic *enic, int request,
-	u16 *response)
+int enic_process_get_pp_request(struct enic *enic, int vf,
+	int request, u16 *response)
 {
 	int err, status = ERR_SUCCESS;
 
@@ -225,11 +327,13 @@ int enic_process_get_pp_request(struct enic *enic, int request,
 
 	case PORT_REQUEST_PREASSOCIATE_RR:
 	case PORT_REQUEST_ASSOCIATE:
-		err = enic_dev_enable2_done(enic, &status);
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
+			vnic_dev_enable2_done, &status);
 		break;
 
 	case PORT_REQUEST_DISASSOCIATE:
-		err = enic_dev_deinit_done(enic, &status);
+		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
+			vnic_dev_deinit_done, &status);
 		break;
 
 	default:
diff --git a/drivers/net/ethernet/cisco/enic/enic_pp.h b/drivers/net/ethernet/cisco/enic/enic_pp.h
index 699e365..a09ff39 100644
--- a/drivers/net/ethernet/cisco/enic/enic_pp.h
+++ b/drivers/net/ethernet/cisco/enic/enic_pp.h
@@ -19,9 +19,18 @@
 #ifndef _ENIC_PP_H_
 #define _ENIC_PP_H_
 
-int enic_process_set_pp_request(struct enic *enic,
+#define ENIC_PP_BY_INDEX(enic, vf, pp, err) \
+	do { \
+		if (enic_is_valid_pp_vf(enic, vf, err)) \
+			pp = (vf == PORT_SELF_VF) ? enic->pp : enic->pp + vf; \
+		else \
+			pp = NULL; \
+	} while (0)
+
+int enic_process_set_pp_request(struct enic *enic, int vf,
 	struct enic_port_profile *prev_pp, int *restore_pp);
-int enic_process_get_pp_request(struct enic *enic, int request,
-	u16 *response);
+int enic_process_get_pp_request(struct enic *enic, int vf,
+	int request, u16 *response);
+int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err);
 
 #endif /* _ENIC_PP_H_ */

^ permalink raw reply related

* [PATCH net-next] ehea: Remove sleep at .ndo_get_stats
From: brenohl @ 2011-09-22 14:10 UTC (permalink / raw)
  To: davem; +Cc: netdev, Breno Leitao

Currently ehea ndo_get_stats can sleep in two places, in a hcall
and in a GFP_KERNEL alloc, which is not correct.
This patch creates a workqueue that grabs the information from time
to time from the hardware, and place it into the device structure,
so that, .ndo_get_stats quickly returns the device structure statistics
block.

Signed-off-by: Breno Leitao <leitao@linux.vnet.ibm.com>
---
 drivers/net/ehea/ehea.h      |    1 +
 drivers/net/ehea/ehea_main.c |   20 +++++++++++++++++---
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 7dd5e6a..05c39ae 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -459,6 +459,7 @@ struct ehea_port {
 	struct ehea_mc_list *mc_list;	 /* Multicast MAC addresses */
 	struct ehea_eq *qp_eq;
 	struct work_struct reset_task;
+	struct work_struct stats_task;
 	struct mutex port_lock;
 	char int_aff_name[EHEA_IRQ_NAME_SIZE];
 	int allmulti;			 /* Indicates IFF_ALLMULTI state */
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index be2cb4a..7465553 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -330,6 +330,15 @@ out:
 static struct net_device_stats *ehea_get_stats(struct net_device *dev)
 {
 	struct ehea_port *port = netdev_priv(dev);
+
+	return &port->stats;
+}
+
+static void ehea_update_stats(struct work_struct *work)
+{
+	struct ehea_port *port =
+		container_of(work, struct ehea_port, stats_task);
+	struct net_device *dev = port->netdev;
 	struct net_device_stats *stats = &port->stats;
 	struct hcp_ehea_port_cb2 *cb2;
 	u64 hret, rx_packets, tx_packets, rx_bytes = 0, tx_bytes = 0;
@@ -340,7 +349,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
 	cb2 = (void *)get_zeroed_page(GFP_KERNEL);
 	if (!cb2) {
 		netdev_err(dev, "no mem for cb2\n");
-		goto out;
+		return;
 	}
 
 	hret = ehea_h_query_ehea_port(port->adapter->handle,
@@ -375,8 +384,6 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
 
 out_herr:
 	free_page((unsigned long)cb2);
-out:
-	return stats;
 }
 
 static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
@@ -789,6 +796,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
 	ehea_refill_rq2(pr, processed_rq2);
 	ehea_refill_rq3(pr, processed_rq3);
 
+	schedule_work(&port->stats_task);
+
 	return processed;
 }
 
@@ -953,6 +962,7 @@ static int ehea_poll(struct napi_struct *napi, int budget)
 		rx += ehea_proc_rwqes(dev, pr, budget - rx);
 	}
 
+	ehea_update_stats(dev);
 	pr->poll_counter++;
 	return rx;
 }
@@ -2651,6 +2661,7 @@ static int ehea_open(struct net_device *dev)
 	}
 
 	mutex_unlock(&port->port_lock);
+	schedule_work(&port->stats_task);
 
 	return ret;
 }
@@ -2690,6 +2701,7 @@ static int ehea_stop(struct net_device *dev)
 
 	set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
 	cancel_work_sync(&port->reset_task);
+	cancel_work_sync(&port->stats_task);
 	mutex_lock(&port->port_lock);
 	netif_stop_queue(dev);
 	port_napi_disable(port);
@@ -3235,6 +3247,7 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
 		dev->features |= NETIF_F_LRO;
 
 	INIT_WORK(&port->reset_task, ehea_reset_port);
+	INIT_WORK(&port->stats_task, ehea_update_stats);
 
 	init_waitqueue_head(&port->swqe_avail_wq);
 	init_waitqueue_head(&port->restart_wq);
@@ -3278,6 +3291,7 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
 	struct ehea_adapter *adapter = port->adapter;
 
 	cancel_work_sync(&port->reset_task);
+	cancel_work_sync(&port->stats_task);
 	unregister_netdev(port->netdev);
 	ehea_unregister_port(port);
 	kfree(port->mc_list);
-- 
1.7.1

^ permalink raw reply related

* Introducing open source MSTP daemon
From: Vitalii Demianets @ 2011-09-22 14:27 UTC (permalink / raw)
  To: bridge, netdev
  Cc: Srinivas M.A., Stephen Hemminger, Alex Rozin, Michael Rozhavsky

Good day!
I am happy to introduce open source MSTP daemon:
http://sourceforge.net/p/mstpd

Of course due to current limitations of the Linux bridge code, namely:
 - no integration with VLAN code
 - no support of different FIDs (independent learning)
 - no support of the per-MSTI port states
this daemon is not very useful for the bare Linux box. It can work only with 
support of specialized driver which talks to the MSTP-aware hardware (most of 
the today ethernet switching parts are MSTP-aware and support FIDs and 
per-MSTI port states).
Nevertheless I hope to find some interest in my work. Maybe it will stimulate 
in some way the integration of the Linux bridge and VLAN code, who knows? 
>From the IEEE point of view they are already merged, see 802.1Q-2005 which 
incorporates previous editions of 802.1q and 802.1d and 802.1w/s.

Once again, all interested are welcome. Please review, criticize, test, 
modify, patch, deploy and do other things :) Any kind of feedback is 
extremely welcome :)

-- 
Vitalii Demianets

^ permalink raw reply

* niu: eth0: Transmit timed out, resetting
From: Hans-Juergen Schnitzer @ 2011-09-22 14:27 UTC (permalink / raw)
  To: netdev

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

Hi,

we have installed Scientific Linux 6.1 (Kernel
2.6.32-131.12.1.el6.x86_64) on a server with a Sun Neptune 10g card.
Shortly after transmitting data we get the error

niu: eth0: Transmit timed out, resetting

and the system stops to respond. This behaviour was already reported
before on this list and I was wondering if there is a fix available.

Thank you,
Hans Schnitzer



[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/x-pkcs7-signature, Size: 5750 bytes --]

^ permalink raw reply

* Re: [PATCH v3 2/7] socket: initial cgroup code.
From: Balbir Singh @ 2011-09-22 15:09 UTC (permalink / raw)
  To: Greg Thelen
  Cc: Glauber Costa, linux-kernel, paul, lizf, kamezawa.hiroyu,
	ebiederm, davem, netdev, linux-mm, kirill
In-Reply-To: <CAHH2K0Z_2LJPL0sLVHqkh_6b_BLQnknULTB9a9WfEuibk5kONg@mail.gmail.com>

On Thu, Sep 22, 2011 at 11:30 AM, Greg Thelen <gthelen@google.com> wrote:
> On Wed, Sep 21, 2011 at 11:59 AM, Glauber Costa <glommer@parallels.com> wrote:
>> Right now I am working under the assumption that tasks are long lived inside
>> the cgroup. Migration potentially introduces some nasty locking problems in
>> the mem_schedule path.
>>
>> Also, unless I am missing something, the memcg already has the policy of
>> not carrying charges around, probably because of this very same complexity.
>>
>> True that at least it won't EBUSY you... But I think this is at least a way
>> to guarantee that the cgroup under our nose won't disappear in the middle of
>> our allocations.
>
> Here's the memcg user page behavior using the same pattern:
>
> 1. user page P is allocate by task T in memcg M1
> 2. T is moved to memcg M2.  The P charge is left behind still charged
> to M1 if memory.move_charge_at_immigrate=0; or the charge is moved to
> M2 if memory.move_charge_at_immigrate=1.
> 3. rmdir M1 will try to reclaim P (if P was left in M1).  If unable to
> reclaim, then P is recharged to parent(M1).
>

We also have some magic in page_referenced() to remove pages
referenced from different containers. What we do is try not to
penalize a cgroup if another cgroup is referencing this page and the
page under consideration is being reclaimed from the cgroup that
touched it.

Balbir Singh

^ permalink raw reply

* Re: [PATCH net-next] ehea: Remove sleep at .ndo_get_stats
From: Eric Dumazet @ 2011-09-22 15:14 UTC (permalink / raw)
  To: brenohl; +Cc: davem, netdev, Breno Leitao
In-Reply-To: <1316700657-14980-1-git-send-email-brenohl@br.ibm.com>

Le jeudi 22 septembre 2011 à 11:10 -0300, brenohl@br.ibm.com a écrit :
> Currently ehea ndo_get_stats can sleep in two places, in a hcall
> and in a GFP_KERNEL alloc, which is not correct.
> This patch creates a workqueue that grabs the information from time
> to time from the hardware, and place it into the device structure,
> so that, .ndo_get_stats quickly returns the device structure statistics
> block.
> 
> Signed-off-by: Breno Leitao <leitao@linux.vnet.ibm.com>
> ---


Hmm... trigerring a work queue everytime NAPI is run ? That seems very
expensive to me, if for example no one wants device stats at all.

I read ehea correctly, this blocking suff is only used to compute
stats->multicast and stats->rx_errors. 

They probably could be updated once per second, nobody will complain.
(So use a workqueue, and trigger the job once per second, not once per
incoming packet)

Also, you dont provide a safe ndo_get_stats() implementation.

Think that several process might read your device stats in //

So the memset(stats, 0, sizeof(*stats)) is wrong :
You can clear stats that are currently read by another thread.

This makes SNMP readers read intermediate null values, and they dont
like this.

Fix is real easy : remove the memset(stats, 0, sizeof(*stats)) :

You only write on some fields, other fields are already 0

^ permalink raw reply

* Re: [PATCH v3 6/7] tcp buffer limitation: per-cgroup limit
From: Greg Thelen @ 2011-09-22 15:44 UTC (permalink / raw)
  To: Kirill A. Shutemov
  Cc: Glauber Costa, linux-kernel, paul, lizf, kamezawa.hiroyu,
	ebiederm, davem, netdev, linux-mm
In-Reply-To: <20110922095803.GA4530@shutemov.name>

On Thu, Sep 22, 2011 at 2:58 AM, Kirill A. Shutemov
<kirill@shutemov.name> wrote:
> On Wed, Sep 21, 2011 at 11:01:46PM -0700, Greg Thelen wrote:
>> On Sun, Sep 18, 2011 at 5:56 PM, Glauber Costa <glommer@parallels.com> wrote:
>> > +static inline bool mem_cgroup_is_root(struct mem_cgroup *mem)
>> > +{
>> > +       return (mem == root_mem_cgroup);
>> > +}
>> > +
>>
>> Why are you adding a copy of mem_cgroup_is_root().  I see one already
>> in v3.0.  Was it deleted in a previous patch?
>
> mem_cgroup_is_root() moved up in the file.

Got it.  Thanks.

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

^ permalink raw reply

* Hello
From: Jun Huan @ 2011-09-22 14:10 UTC (permalink / raw)


I have a Project for you, Please contact me for more details

^ permalink raw reply

* routing table error in 2.6.39 ..
From: ratheesh kannoth @ 2011-09-22 15:55 UTC (permalink / raw)
  To: user-mode-linux-user, user-mode-linux-devel, netdev

I built UML  (user mode linux ) for 2.6.38 and 2.6.39 kernels.

in 2.6.38 routing  table is  correct. But in 2.6.39 default gw appears
on top of the routing table. same problem persist in 3.0.0 also.

is it a known problem or fixed in higher versions ?

-Ratheesh

^ permalink raw reply

* Re: [PATCH v2 net-next] af_unix: dont send SCM_CREDENTIALS by default
From: tim @ 2011-09-22 16:15 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Valdis.Kletnieks, Tim Chen, David Miller, zheng.z.yan, yanzheng,
	netdev, sfr, jirislaby, sedat.dilek, alex.shi
In-Reply-To: <1316492170.2455.43.camel@edumazet-laptop>

On Tue, 2011-09-20 at 06:16 +0200, Eric Dumazet wrote:
> Le lundi 19 septembre 2011 à 22:10 -0400, Valdis.Kletnieks@vt.edu a
> écrit :
> > On Mon, 19 Sep 2011 14:39:58 PDT, Tim Chen said:
> > > Do we have to worry about the case where peer socket changes its flag
> > > to SOCK_PASSCRED while packets are in flight?  If there isn't such
> > > pathological use case, the patch looks fine to me.
> > 
> > I wouldn't think so - if you're sending a packet, and retroactively trying to
> > change the flag and expect it to work, your program is too ugly to live.  After
> > all, if the scheduler had cut off your timeslice and scheduledthe receiving
> > process before you set the flag, that packet would be delivered and done with
> > anyhow, and no amount of wishing will set that flag on an already-delivered
> > packet.
> > 
> > What *is* worth checking is that we DTRT if a process/thread is doing a send on
> > one CPU, and another process/thread with a shared file descriptor for that
> > socket is diddling the flag.  But if we just define it as "atomic op to change
> > the flag and other observers get whatever value their CPU sees at that
> > instant", I'm OK with that too.. ;)
> > 
> 
> Note : The man page does states :
> 
> "To receive a struct ucred message the SO_PASSCRED option  must  be
> enabled  on  the socket."
> 
> But it doesnt say if the SO_PASSCRED option must be enabled before the
> sender sends its message, or before receiver attempts to read it.
> 
> Once a message is queued on an unix socket, flipping SO_PASSCRED cant
> change its content (adding or removing credentials), since sender might
> already have disappeared.
> 
> So current code includes credentials in all sent messages, just in case
> receiver actually fetch credentials.
> 
> There are probably programs that assume they can set SO_PASSCRED right
> before calling recvmsg(). Are we taking risk to break them, or are we
> gentle and provide a sysctl option to ease the transition, I dont
> know...
> 

Should we reconsider the original approach of reducing the
pid/credential references, with your fixes to correct its flaws in the
streaming msg case?

Tim

^ permalink raw reply

* Re: [PATCH net-next v2] candev: allow SJW user setting for bittiming calculation
From: Oliver Hartkopp @ 2011-09-22 16:26 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: SocketCAN Core Mailing List, Linux Netdev List, David Miller
In-Reply-To: <4E7B331F.3070801-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>

On 09/22/11 15:07, Wolfgang Grandegger wrote:

> Hi Oliver,
> 
> On 09/22/2011 12:28 PM, Oliver Hartkopp wrote:
>> This patch adds support for SJW user settings to not set the synchronization
>> jump width (SJW) to 1 in any case when using the in-kernel bittiming
>> calculation.
>>
>> The ip-tool from iproute2 already supports to pass the user defined SJW
>> value. The given SJW value is sanitized with the controller specific sjw_max
>> and the calculated tseg2 value. As the SJW can have values up to 4 providing
>> this value will lead to the maximum possible SJW automatically. A higher SJW
>> allows higher controller oscillator tolerances.

(..)


> As I already said, I expected "bt->sjw" to be always 0 when
> can_calc_bittiming() is called. But the software somehow allows to
> preset "bt->sjw", which is not intended as the help of the ip utility shows:


What was the technical reason for this 'not intended' that time?

> I actually hesitate to extend can_calc_bittiming(). I suggest using an
> external tool to calculate proper bit-timing parameters and set them
> with "ip link set DEVICE type can tq ...".


Yes, i know the possibility to specify the bittiming via time-quanta (tq).

But i think the in-kernel bittiming calculation is pretty good and solves most
usual cases. For me it's just an additional requirement to specify SJW as
MIN(tseg2, max_sjw) to extend the clock source tolerance - which can be
provided as an additional option to the bittiming calculation without pain
(IMO). If i can 'tune' the sample point, why should i not have any influence
to the synchronization jump width generation then?

And btw. a help text can really be changed easily ;-)

-        [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
+        [ bitrate BITRATE [ sample-point SAMPLE-POINT] [sjw SJW] ] |

Regards,
Oliver

^ permalink raw reply

* RE: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag API.
From: Bhavesh Davda @ 2011-09-22 16:30 UTC (permalink / raw)
  To: Ian Campbell, netdev@vger.kernel.org; +Cc: VMware, Inc.
In-Reply-To: <1316678008-16842-14-git-send-email-ian.campbell@citrix.com>

These changes look sane. What about frag->page_offset and frag->size, are there APIs to access those as well?

[sorry can't pull from git.kernel.org at the moment to answer my own quesion]

- Bhavesh
 
Bhavesh P. Davda

> -----Original Message-----
> From: pv-drivers-bounces@vmware.com [mailto:pv-drivers-bounces@vmware.com] On
> Behalf Of Ian Campbell
> Sent: Thursday, September 22, 2011 12:53 AM
> To: netdev@vger.kernel.org
> Cc: VMware, Inc.; Ian Campbell
> Subject: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag API.
> 
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Cc: Shreyas Bhatewara <sbhatewara@vmware.com>
> Cc: "VMware, Inc." <pv-drivers@vmware.com>
> Cc: netdev@vger.kernel.org
> ---
>  drivers/net/vmxnet3/vmxnet3_drv.c |    8 ++++----
>  1 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c
> b/drivers/net/vmxnet3/vmxnet3_drv.c
> index 759c1a4..57e7c66 100644
> --- a/drivers/net/vmxnet3/vmxnet3_drv.c
> +++ b/drivers/net/vmxnet3/vmxnet3_drv.c
> @@ -654,7 +654,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct
> Vmxnet3_RxCompDesc *rcd,
> 
>  	BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS);
> 
> -	frag->page = rbi->page;
> +	__skb_frag_set_page(frag, rbi->page);
>  	frag->page_offset = 0;
>  	frag->size = rcd->len;
>  	skb->data_len += frag->size;
> @@ -748,9 +748,9 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx
> *ctx,
> 
>  		tbi = tq->buf_info + tq->tx_ring.next2fill;
>  		tbi->map_type = VMXNET3_MAP_PAGE;
> -		tbi->dma_addr = pci_map_page(adapter->pdev, frag->page,
> -					     frag->page_offset, frag->size,
> -					     PCI_DMA_TODEVICE);
> +		tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
> +						 0, frag->size,
> +						 PCI_DMA_TODEVICE);
> 
>  		tbi->len = frag->size;
> 
> --
> 1.7.2.5
> 
> _______________________________________________
> Pv-drivers mailing list
> Pv-drivers@vmware.com
> http://mailman2.vmware.com/mailman/listinfo/pv-drivers

^ permalink raw reply

* Re: Introducing open source MSTP daemon
From: David Lamparter @ 2011-09-22 16:39 UTC (permalink / raw)
  To: Vitalii Demianets
  Cc: bridge, netdev, Srinivas M.A., Stephen Hemminger, Alex Rozin,
	Michael Rozhavsky
In-Reply-To: <201109221727.33010.vitas@nppfactor.kiev.ua>

On Thu, Sep 22, 2011 at 05:27:32PM +0300, Vitalii Demianets wrote:
> Good day!
> I am happy to introduce open source MSTP daemon:
> http://sourceforge.net/p/mstpd
> 
> Of course due to current limitations of the Linux bridge code, namely:
>  - no integration with VLAN code
>  - no support of different FIDs (independent learning)
>  - no support of the per-MSTI port states

Yes... Linux kernel bridging code only implements 802.1D, even the mac
table is one-for-all-VLANs.

> this daemon is not very useful for the bare Linux box. It can work only with 
> support of specialized driver which talks to the MSTP-aware hardware (most of 
> the today ethernet switching parts are MSTP-aware and support FIDs and 
> per-MSTI port states).
> Nevertheless I hope to find some interest in my work. Maybe it will stimulate 
> in some way the integration of the Linux bridge and VLAN code, who knows? 
> From the IEEE point of view they are already merged, see 802.1Q-2005 which 
> incorporates previous editions of 802.1q and 802.1d and 802.1w/s.
> 
> Once again, all interested are welcome. Please review, criticize, test, 
> modify, patch, deploy and do other things :) Any kind of feedback is 
> extremely welcome :)

Very cool!

The code looks quite good to me (i've only looked at 2 files though ;).
Minor nitpicks:
 - hmac_md5 & epoll could maybe come from an external library. you're
   the 3810583th person to have code for that... libevent?
   OpenSSL/gnutls?
 - libnetlink.c is a copy from iproute2? since it is a fresh clean SVN,
   it's not easy to know whether you made changes. Can you put a note
   which version this is? Or maybe you can link it externally?
 - the "assign" macro and "boolFalse" in mstp.c are weird. I understand
   you want stricter type checking, but this makes the code somewhat
   odd to read. Maybe external tools can be used to do this checking
   (sparse, cppcheck, llvm's static analysis, ...)
 - what coding style is it? it's neither Linux kernel nor GNU :) - maybe
   reformat to Linux kernel style while it is still new.

I assume it works with current Linux kernel bridge code on a RSTP level?
The code looks considerably more maintainable than rstpd :) - I will try
running it later!


-David

^ permalink raw reply

* Re: Introducing open source MSTP daemon
From: David Lamparter @ 2011-09-22 16:45 UTC (permalink / raw)
  To: David Lamparter
  Cc: Vitalii Demianets, bridge, netdev, Srinivas M.A.,
	Stephen Hemminger, Alex Rozin, Michael Rozhavsky
In-Reply-To: <20110922163939.GB1012103@jupiter.n2.diac24.net>

On Thu, Sep 22, 2011 at 06:39:40PM +0200, David Lamparter wrote:
>  - what coding style is it? it's neither Linux kernel nor GNU :) - maybe
>    reformat to Linux kernel style while it is still new.

Oh, it's GNU. I shouldn't look at source code in a web browser, stupid
me - Sorry, forget I asked.

-David

^ permalink raw reply

* RE: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag API.
From: Ian Campbell @ 2011-09-22 16:46 UTC (permalink / raw)
  To: Bhavesh Davda; +Cc: netdev@vger.kernel.org, VMware, Inc.
In-Reply-To: <B07832953588294D802727FF264E276A13EB817FBD@exch-mbx-112.vmware.com>

On Thu, 2011-09-22 at 17:30 +0100, Bhavesh Davda wrote:
> These changes look sane. What about frag->page_offset and frag->size, are there APIs to access those as well?

You can go at those directly.

The important part here is to abstract away the access to the ->page
variable so we can change how the reference counting works.

So unless people think there is a compelling reason to hide away size
and offset I wasn't planning on doing anything like that.

Ian.

> 
> [sorry can't pull from git.kernel.org at the moment to answer my own quesion]
> 
> - Bhavesh
>  
> Bhavesh P. Davda
> 
> > -----Original Message-----
> > From: pv-drivers-bounces@vmware.com [mailto:pv-drivers-bounces@vmware.com] On
> > Behalf Of Ian Campbell
> > Sent: Thursday, September 22, 2011 12:53 AM
> > To: netdev@vger.kernel.org
> > Cc: VMware, Inc.; Ian Campbell
> > Subject: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag API.
> > 
> > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> > Cc: Shreyas Bhatewara <sbhatewara@vmware.com>
> > Cc: "VMware, Inc." <pv-drivers@vmware.com>
> > Cc: netdev@vger.kernel.org
> > ---
> >  drivers/net/vmxnet3/vmxnet3_drv.c |    8 ++++----
> >  1 files changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c
> > b/drivers/net/vmxnet3/vmxnet3_drv.c
> > index 759c1a4..57e7c66 100644
> > --- a/drivers/net/vmxnet3/vmxnet3_drv.c
> > +++ b/drivers/net/vmxnet3/vmxnet3_drv.c
> > @@ -654,7 +654,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct
> > Vmxnet3_RxCompDesc *rcd,
> > 
> >  	BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS);
> > 
> > -	frag->page = rbi->page;
> > +	__skb_frag_set_page(frag, rbi->page);
> >  	frag->page_offset = 0;
> >  	frag->size = rcd->len;
> >  	skb->data_len += frag->size;
> > @@ -748,9 +748,9 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx
> > *ctx,
> > 
> >  		tbi = tq->buf_info + tq->tx_ring.next2fill;
> >  		tbi->map_type = VMXNET3_MAP_PAGE;
> > -		tbi->dma_addr = pci_map_page(adapter->pdev, frag->page,
> > -					     frag->page_offset, frag->size,
> > -					     PCI_DMA_TODEVICE);
> > +		tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
> > +						 0, frag->size,
> > +						 PCI_DMA_TODEVICE);
> > 
> >  		tbi->len = frag->size;
> > 
> > --
> > 1.7.2.5
> > 
> > _______________________________________________
> > Pv-drivers mailing list
> > Pv-drivers@vmware.com
> > http://mailman2.vmware.com/mailman/listinfo/pv-drivers

^ permalink raw reply

* RE: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag API.
From: Bhavesh Davda @ 2011-09-22 16:49 UTC (permalink / raw)
  To: Ian Campbell; +Cc: netdev@vger.kernel.org, VMware, Inc.
In-Reply-To: <1316709993.23371.81.camel@zakaz.uk.xensource.com>

Okay.

Signed-off-by: Bhavesh Davda <bhavesh@vmware.com>

- Bhavesh
 
Bhavesh P. Davda

> -----Original Message-----
> From: Ian Campbell [mailto:Ian.Campbell@eu.citrix.com]
> Sent: Thursday, September 22, 2011 9:47 AM
> To: Bhavesh Davda
> Cc: netdev@vger.kernel.org; VMware, Inc.
> Subject: RE: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag
> API.
> 
> On Thu, 2011-09-22 at 17:30 +0100, Bhavesh Davda wrote:
> > These changes look sane. What about frag->page_offset and frag->size, are
> there APIs to access those as well?
> 
> You can go at those directly.
> 
> The important part here is to abstract away the access to the ->page
> variable so we can change how the reference counting works.
> 
> So unless people think there is a compelling reason to hide away size
> and offset I wasn't planning on doing anything like that.
> 
> Ian.
> 
> >
> > [sorry can't pull from git.kernel.org at the moment to answer my own
> quesion]
> >
> > - Bhavesh
> >
> > Bhavesh P. Davda
> >
> > > -----Original Message-----
> > > From: pv-drivers-bounces@vmware.com [mailto:pv-drivers-bounces@vmware.com]
> On
> > > Behalf Of Ian Campbell
> > > Sent: Thursday, September 22, 2011 12:53 AM
> > > To: netdev@vger.kernel.org
> > > Cc: VMware, Inc.; Ian Campbell
> > > Subject: [Pv-drivers] [PATCH 14/14] vmxnet3: convert to SKB paged frag
> API.
> > >
> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> > > Cc: Shreyas Bhatewara <sbhatewara@vmware.com>
> > > Cc: "VMware, Inc." <pv-drivers@vmware.com>
> > > Cc: netdev@vger.kernel.org
> > > ---
> > >  drivers/net/vmxnet3/vmxnet3_drv.c |    8 ++++----
> > >  1 files changed, 4 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c
> > > b/drivers/net/vmxnet3/vmxnet3_drv.c
> > > index 759c1a4..57e7c66 100644
> > > --- a/drivers/net/vmxnet3/vmxnet3_drv.c
> > > +++ b/drivers/net/vmxnet3/vmxnet3_drv.c
> > > @@ -654,7 +654,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct
> > > Vmxnet3_RxCompDesc *rcd,
> > >
> > >  	BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS);
> > >
> > > -	frag->page = rbi->page;
> > > +	__skb_frag_set_page(frag, rbi->page);
> > >  	frag->page_offset = 0;
> > >  	frag->size = rcd->len;
> > >  	skb->data_len += frag->size;
> > > @@ -748,9 +748,9 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct
> vmxnet3_tx_ctx
> > > *ctx,
> > >
> > >  		tbi = tq->buf_info + tq->tx_ring.next2fill;
> > >  		tbi->map_type = VMXNET3_MAP_PAGE;
> > > -		tbi->dma_addr = pci_map_page(adapter->pdev, frag->page,
> > > -					     frag->page_offset, frag->size,
> > > -					     PCI_DMA_TODEVICE);
> > > +		tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
> > > +						 0, frag->size,
> > > +						 PCI_DMA_TODEVICE);
> > >
> > >  		tbi->len = frag->size;
> > >
> > > --
> > > 1.7.2.5
> > >
> > > _______________________________________________
> > > Pv-drivers mailing list
> > > Pv-drivers@vmware.com
> > > http://mailman2.vmware.com/mailman/listinfo/pv-drivers
> 


^ permalink raw reply

* Re: [PATCH net-next v2] candev: allow SJW user setting for bittiming calculation
From: Wolfgang Grandegger @ 2011-09-22 18:10 UTC (permalink / raw)
  To: Oliver Hartkopp
  Cc: SocketCAN Core Mailing List, Linux Netdev List, David Miller
In-Reply-To: <4E7B61C8.8020506-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>

On 09/22/2011 06:26 PM, Oliver Hartkopp wrote:
> On 09/22/11 15:07, Wolfgang Grandegger wrote:
> 
>> Hi Oliver,
>>
>> On 09/22/2011 12:28 PM, Oliver Hartkopp wrote:
>>> This patch adds support for SJW user settings to not set the synchronization
>>> jump width (SJW) to 1 in any case when using the in-kernel bittiming
>>> calculation.
>>>
>>> The ip-tool from iproute2 already supports to pass the user defined SJW
>>> value. The given SJW value is sanitized with the controller specific sjw_max
>>> and the calculated tseg2 value. As the SJW can have values up to 4 providing
>>> this value will lead to the maximum possible SJW automatically. A higher SJW
>>> allows higher controller oscillator tolerances.
> 
> (..)
> 
> 
>> As I already said, I expected "bt->sjw" to be always 0 when
>> can_calc_bittiming() is called. But the software somehow allows to
>> preset "bt->sjw", which is not intended as the help of the ip utility shows:
> 
> 
> What was the technical reason for this 'not intended' that time?

Fiddling with SJW is something for *expert* only. You need to know
what's going on the bus (electrically). To be clear, I'm not such an expert.

>> I actually hesitate to extend can_calc_bittiming(). I suggest using an
>> external tool to calculate proper bit-timing parameters and set them
>> with "ip link set DEVICE type can tq ...".
> 
> 
> Yes, i know the possibility to specify the bittiming via time-quanta (tq).

This is what we called the "expert mode".

> But i think the in-kernel bittiming calculation is pretty good and solves most
> usual cases. For me it's just an additional requirement to specify SJW as

What's your reason to increase SJW? Likely because you get bus errors
with the standard settings. How should it be set? Likely you need to
fiddle with other parameters as well. For sure, no business for a normal
CAN user.

> MIN(tseg2, max_sjw) to extend the clock source tolerance - which can be
> provided as an additional option to the bittiming calculation without pain
> (IMO). If i can 'tune' the sample point, why should i not have any influence
> to the synchronization jump width generation then?

Bitrate and sample point is something obvious for normal users.

> And btw. a help text can really be changed easily ;-)
> 
> -        [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
> +        [ bitrate BITRATE [ sample-point SAMPLE-POINT] [sjw SJW] ] |

Well, I have stronger arguments against it ;-).

Any other opinions or suggestions?

Wolfgang.

^ permalink raw reply

* Re: routing table error in 2.6.39 ..
From: David Miller @ 2011-09-22 18:21 UTC (permalink / raw)
  To: ratheesh.ksz; +Cc: user-mode-linux-user, user-mode-linux-devel, netdev
In-Reply-To: <CAGZFCEHtyE1MutMmhKefFm9Xx5rri1j7DR7L=cFU3KUg7ejs4g@mail.gmail.com>

From: ratheesh kannoth <ratheesh.ksz@gmail.com>
Date: Thu, 22 Sep 2011 21:25:47 +0530

> in 2.6.38 routing  table is  correct. But in 2.6.39 default gw appears
> on top of the routing table. same problem persist in 3.0.0 also.

You cannot depend upon the order in which routing table entries
are listed by the kernel.

The table internally is correct, and lookups will match using the
proper longest-matching-prefix algorithm.

^ permalink raw reply

* pull request: batman-adv 2011-09-22 (regression fix)
From: Marek Lindner @ 2011-09-22 18:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n

Hi David,

our testers have discovered a regression in the current linux-3.1
code base. It increases latency of payload traffic by a factor of
4-5. Therefore we propose a patch that hopefully can be included 
before linux 3.1 final has been released. We kept it as short as 
possible to avoid introducing last minute bugs.

Once you pulled the patch you will run into a merge conflict
with net-next:
++<<<<<<< HEAD
 + orig_node = transtable_search(bat_priv, ethhdr->h_source,
 +                               ethhdr->h_dest);
 + if (is_multicast_ether_addr(ethhdr->h_dest) ||
 + (orig_node && orig_node->gw_flags)) {
++=======
+ orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+ do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
+ if (do_bcast || (orig_node && orig_node->gw_flags)) {
++>>>>>>> batman-adv/maint

The correct merge result would be:
+======
orig_node = transtable_search(bat_priv, ethhdr->h_source,
                              ethhdr->h_dest);
do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
if (do_bcast || (orig_node && orig_node->gw_flags)) {
+======

Let me know if there is a better way to address the merge conflict.

Thanks,
Marek

The following changes since commit 322a8b034003c0d46d39af85bf24fee27b902f48:

  Linux 3.1-rc1 (2011-08-07 18:23:30 -0700)

are available in the git repository at:
  git://git.open-mesh.org/linux-merge.git batman-adv/maint

Antonio Quartulli (1):
      batman-adv: do_bcast has to be true for broadcast packets only

 net/batman-adv/soft-interface.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

^ permalink raw reply

* [PATCH] batman-adv: do_bcast has to be true for broadcast packets only
From: Marek Lindner @ 2011-09-22 18:57 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Antonio Quartulli, Marek Lindner
In-Reply-To: <1316717836-19374-1-git-send-email-lindner_marek@yahoo.de>

From: Antonio Quartulli <ordex@autistici.org>

corrects a critical bug of the GW feature. This bug made all the unicast
packets destined to a GW to be sent as broadcast. This bug is present even if
the sender GW feature is configured as OFF. It's an urgent bug fix and should
be committed as soon as possible.

This was a regression introduced by 43676ab590c3f8686fd047d34c3e33803eef71f0

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
 net/batman-adv/soft-interface.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 3e2f91f..05dd351 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -565,7 +565,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct orig_node *orig_node = NULL;
 	int data_len = skb->len, ret;
 	short vid = -1;
-	bool do_bcast = false;
+	bool do_bcast;
 
 	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
 		goto dropped;
@@ -598,15 +598,15 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	tt_local_add(soft_iface, ethhdr->h_source);
 
 	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
-	if (is_multicast_ether_addr(ethhdr->h_dest) ||
-				(orig_node && orig_node->gw_flags)) {
+	do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
+	if (do_bcast ||	(orig_node && orig_node->gw_flags)) {
 		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
 
-		if (ret == 0)
-			do_bcast = true;
+		if (ret)
+			do_bcast = false;
 	}
 
 	/* ethernet packet should be broadcasted */
-- 
1.7.5.4

^ permalink raw reply related

* Re: [PATCH net-next v2] candev: allow SJW user setting for bittiming calculation
From: Oliver Hartkopp @ 2011-09-22 19:41 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: SocketCAN Core Mailing List, Linux Netdev List
In-Reply-To: <4E7B7A30.4030707-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>

Hi Wolfgang,

i put Pavel and Andrey into CC, maybe they also have an opinion about this.
I just talked to a specialist who told me, that a higher SJW is better - if
possible. And if an expert told me so and i had a simple config interface to
fullfill it, it would be great for me ;-)

Here is a link to the patch and this discussion:

http://patchwork.ozlabs.org/patch/115932/

Regards,
Oliver

On 09/22/11 20:10, Wolfgang Grandegger wrote:

> On 09/22/2011 06:26 PM, Oliver Hartkopp wrote:
>> On 09/22/11 15:07, Wolfgang Grandegger wrote:
>>
>>> Hi Oliver,
>>>
>>> On 09/22/2011 12:28 PM, Oliver Hartkopp wrote:
>>>> This patch adds support for SJW user settings to not set the synchronization
>>>> jump width (SJW) to 1 in any case when using the in-kernel bittiming
>>>> calculation.
>>>>
>>>> The ip-tool from iproute2 already supports to pass the user defined SJW
>>>> value. The given SJW value is sanitized with the controller specific sjw_max
>>>> and the calculated tseg2 value. As the SJW can have values up to 4 providing
>>>> this value will lead to the maximum possible SJW automatically. A higher SJW
>>>> allows higher controller oscillator tolerances.
>>
>> (..)
>>
>>
>>> As I already said, I expected "bt->sjw" to be always 0 when
>>> can_calc_bittiming() is called. But the software somehow allows to
>>> preset "bt->sjw", which is not intended as the help of the ip utility shows:
>>
>>
>> What was the technical reason for this 'not intended' that time?
> 
> Fiddling with SJW is something for *expert* only. You need to know
> what's going on the bus (electrically). To be clear, I'm not such an expert.
> 
>>> I actually hesitate to extend can_calc_bittiming(). I suggest using an
>>> external tool to calculate proper bit-timing parameters and set them
>>> with "ip link set DEVICE type can tq ...".
>>
>>
>> Yes, i know the possibility to specify the bittiming via time-quanta (tq).
> 
> This is what we called the "expert mode".
> 
>> But i think the in-kernel bittiming calculation is pretty good and solves most
>> usual cases. For me it's just an additional requirement to specify SJW as
> 
> What's your reason to increase SJW? Likely because you get bus errors
> with the standard settings. How should it be set? Likely you need to
> fiddle with other parameters as well. For sure, no business for a normal
> CAN user.
> 
>> MIN(tseg2, max_sjw) to extend the clock source tolerance - which can be
>> provided as an additional option to the bittiming calculation without pain
>> (IMO). If i can 'tune' the sample point, why should i not have any influence
>> to the synchronization jump width generation then?
> 
> Bitrate and sample point is something obvious for normal users.
> 
>> And btw. a help text can really be changed easily ;-)
>>
>> -        [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
>> +        [ bitrate BITRATE [ sample-point SAMPLE-POINT] [sjw SJW] ] |
> 
> Well, I have stronger arguments against it ;-).
> 
> Any other opinions or suggestions?
> 
> Wolfgang.
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 0/14] skb fragment API: convert network drivers (part III)
From: David Miller @ 2011-09-22 20:05 UTC (permalink / raw)
  To: Ian.Campbell; +Cc: netdev
In-Reply-To: <1316677996.23371.10.camel@zakaz.uk.xensource.com>

From: Ian Campbell <Ian.Campbell@citrix.com>
Date: Thu, 22 Sep 2011 08:53:16 +0100

> The following series converts the third batch of network drivers to the
> SKB pages fragment API introduced in 131ea6675c76. I expect there will
> be ~4 similarly sized batches to convert all the drivers over.
> 
> This is part of my series to enable visibility into SKB paged fragment's
> lifecycles, [0] contains some more background and rationale but
> basically the completed series will allow entities which inject pages
> into the networking stack to receive a notification when the stack has
> really finished with those pages (i.e. including retransmissions,
> clones, pull-ups etc) and not just when the original skb is finished
> with, which is beneficial to many subsystems which wish to inject pages
> into the network stack without giving up full ownership of those page's
> lifecycle. It implements something broadly along the lines of what was
> described in [1].

ALl applied, thanks Ian.

^ permalink raw reply

* [PATCH next 0/4] Pull request for 'davem-next.r8169' branch
From: Francois Romieu @ 2011-09-22 21:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, Realtek linux nic maintainers, Hayes Wang

Please pull from branch 'davem-next.r8169' in repository

git://violet.fr.zoreil.com/romieu/linux davem-next.r8169

to get the changes below.

The series includes the remaining part of Hayes's recent patches as
well as some jumbo frames changes.

The pci_write_config_byte(pdev, 0x79, ... should be replaced with some
rtl_tx_performance_tweak variant. Feel free to peel the top-most patch
if you want me to respin it with the jumbo changes patch.

Distance from 'davem-next' (8decf868790b48a727d7e7ca164f2bcd3c1389c0)
---------------------------------------------------------------------

d58d46b5d85139d18eb939aa7279c160bab70484
deb9d93c89d311714a60809b28160e538e1cbb43
c2218925f3a653ac6c39e62eb0e10232d2b44dab
3090bd9a3102331ed981280ef05ee5433ce978d7

Diffstat
--------

 drivers/net/ethernet/realtek/r8169.c |  487 ++++++++++++++++++++++++++++++----
 1 files changed, 430 insertions(+), 57 deletions(-)

Shortlog
--------

Francois Romieu (2):
      r8169: expand received packet length indication.
      r8169: jumbo fixes.

Hayes Wang (2):
      r8169: define the early size for 8111evl
      r8169: support new chips of RTL8111F

Patch
-----

diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 6eb9f4e..2ce6070 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -42,6 +42,8 @@
 #define FIRMWARE_8168E_1	"rtl_nic/rtl8168e-1.fw"
 #define FIRMWARE_8168E_2	"rtl_nic/rtl8168e-2.fw"
 #define FIRMWARE_8168E_3	"rtl_nic/rtl8168e-3.fw"
+#define FIRMWARE_8168F_1	"rtl_nic/rtl8168f-1.fw"
+#define FIRMWARE_8168F_2	"rtl_nic/rtl8168f-2.fw"
 #define FIRMWARE_8105E_1	"rtl_nic/rtl8105e-1.fw"
 
 #ifdef RTL8169_DEBUG
@@ -133,6 +135,8 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_32,
 	RTL_GIGA_MAC_VER_33,
 	RTL_GIGA_MAC_VER_34,
+	RTL_GIGA_MAC_VER_35,
+	RTL_GIGA_MAC_VER_36,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -141,84 +145,110 @@ enum rtl_tx_desc_version {
 	RTL_TD_1	= 1,
 };
 
-#define _R(NAME,TD,FW) \
-	{ .name = NAME, .txd_version = TD, .fw_name = FW }
+#define JUMBO_1K	ETH_DATA_LEN
+#define JUMBO_4K	(4*1024 - ETH_HLEN - 2)
+#define JUMBO_6K	(6*1024 - ETH_HLEN - 2)
+#define JUMBO_7K	(7*1024 - ETH_HLEN - 2)
+#define JUMBO_9K	(9*1024 - ETH_HLEN - 2)
+
+#define _R(NAME,TD,FW,SZ,B) {	\
+	.name = NAME,		\
+	.txd_version = TD,	\
+	.fw_name = FW,		\
+	.jumbo_max = SZ,	\
+	.jumbo_tx_csum = B	\
+}
 
 static const struct {
 	const char *name;
 	enum rtl_tx_desc_version txd_version;
 	const char *fw_name;
+	u16 jumbo_max;
+	bool jumbo_tx_csum;
 } rtl_chip_infos[] = {
 	/* PCI devices. */
 	[RTL_GIGA_MAC_VER_01] =
-		_R("RTL8169",		RTL_TD_0, NULL),
+		_R("RTL8169",		RTL_TD_0, NULL, JUMBO_7K, true),
 	[RTL_GIGA_MAC_VER_02] =
-		_R("RTL8169s",		RTL_TD_0, NULL),
+		_R("RTL8169s",		RTL_TD_0, NULL, JUMBO_7K, true),
 	[RTL_GIGA_MAC_VER_03] =
-		_R("RTL8110s",		RTL_TD_0, NULL),
+		_R("RTL8110s",		RTL_TD_0, NULL, JUMBO_7K, true),
 	[RTL_GIGA_MAC_VER_04] =
-		_R("RTL8169sb/8110sb",	RTL_TD_0, NULL),
+		_R("RTL8169sb/8110sb",	RTL_TD_0, NULL, JUMBO_7K, true),
 	[RTL_GIGA_MAC_VER_05] =
-		_R("RTL8169sc/8110sc",	RTL_TD_0, NULL),
+		_R("RTL8169sc/8110sc",	RTL_TD_0, NULL, JUMBO_7K, true),
 	[RTL_GIGA_MAC_VER_06] =
-		_R("RTL8169sc/8110sc",	RTL_TD_0, NULL),
+		_R("RTL8169sc/8110sc",	RTL_TD_0, NULL, JUMBO_7K, true),
 	/* PCI-E devices. */
 	[RTL_GIGA_MAC_VER_07] =
-		_R("RTL8102e",		RTL_TD_1, NULL),
+		_R("RTL8102e",		RTL_TD_1, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_08] =
-		_R("RTL8102e",		RTL_TD_1, NULL),
+		_R("RTL8102e",		RTL_TD_1, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_09] =
-		_R("RTL8102e",		RTL_TD_1, NULL),
+		_R("RTL8102e",		RTL_TD_1, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_10] =
-		_R("RTL8101e",		RTL_TD_0, NULL),
+		_R("RTL8101e",		RTL_TD_0, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_11] =
-		_R("RTL8168b/8111b",	RTL_TD_0, NULL),
+		_R("RTL8168b/8111b",	RTL_TD_0, NULL, JUMBO_4K, false),
 	[RTL_GIGA_MAC_VER_12] =
-		_R("RTL8168b/8111b",	RTL_TD_0, NULL),
+		_R("RTL8168b/8111b",	RTL_TD_0, NULL, JUMBO_4K, false),
 	[RTL_GIGA_MAC_VER_13] =
-		_R("RTL8101e",		RTL_TD_0, NULL),
+		_R("RTL8101e",		RTL_TD_0, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_14] =
-		_R("RTL8100e",		RTL_TD_0, NULL),
+		_R("RTL8100e",		RTL_TD_0, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_15] =
-		_R("RTL8100e",		RTL_TD_0, NULL),
+		_R("RTL8100e",		RTL_TD_0, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_16] =
-		_R("RTL8101e",		RTL_TD_0, NULL),
+		_R("RTL8101e",		RTL_TD_0, NULL, JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_17] =
-		_R("RTL8168b/8111b",	RTL_TD_0, NULL),
+		_R("RTL8168b/8111b",	RTL_TD_1, NULL, JUMBO_4K, false),
 	[RTL_GIGA_MAC_VER_18] =
-		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL),
+		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_19] =
-		_R("RTL8168c/8111c",	RTL_TD_1, NULL),
+		_R("RTL8168c/8111c",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_20] =
-		_R("RTL8168c/8111c",	RTL_TD_1, NULL),
+		_R("RTL8168c/8111c",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_21] =
-		_R("RTL8168c/8111c",	RTL_TD_1, NULL),
+		_R("RTL8168c/8111c",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_22] =
-		_R("RTL8168c/8111c",	RTL_TD_1, NULL),
+		_R("RTL8168c/8111c",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_23] =
-		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL),
+		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_24] =
-		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL),
+		_R("RTL8168cp/8111cp",	RTL_TD_1, NULL, JUMBO_6K, false),
 	[RTL_GIGA_MAC_VER_25] =
-		_R("RTL8168d/8111d",	RTL_TD_1, FIRMWARE_8168D_1),
+		_R("RTL8168d/8111d",	RTL_TD_1, FIRMWARE_8168D_1,
+							JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_26] =
-		_R("RTL8168d/8111d",	RTL_TD_1, FIRMWARE_8168D_2),
+		_R("RTL8168d/8111d",	RTL_TD_1, FIRMWARE_8168D_2,
+							JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_27] =
-		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL),
+		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL, JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_28] =
-		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL),
+		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL, JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_29] =
-		_R("RTL8105e",		RTL_TD_1, FIRMWARE_8105E_1),
+		_R("RTL8105e",		RTL_TD_1, FIRMWARE_8105E_1,
+							JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_30] =
-		_R("RTL8105e",		RTL_TD_1, FIRMWARE_8105E_1),
+		_R("RTL8105e",		RTL_TD_1, FIRMWARE_8105E_1,
+							JUMBO_1K, true),
 	[RTL_GIGA_MAC_VER_31] =
-		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL),
+		_R("RTL8168dp/8111dp",	RTL_TD_1, NULL, JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_32] =
-		_R("RTL8168e/8111e",	RTL_TD_1, FIRMWARE_8168E_1),
+		_R("RTL8168e/8111e",	RTL_TD_1, FIRMWARE_8168E_1,
+							JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_33] =
-		_R("RTL8168e/8111e",	RTL_TD_1, FIRMWARE_8168E_2),
+		_R("RTL8168e/8111e",	RTL_TD_1, FIRMWARE_8168E_2,
+							JUMBO_9K, false),
 	[RTL_GIGA_MAC_VER_34] =
-		_R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3)
+		_R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
+							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_35] =
+		_R("RTL8168f/8111f",	RTL_TD_1, FIRMWARE_8168F_1,
+							JUMBO_9K, false),
+	[RTL_GIGA_MAC_VER_36] =
+		_R("RTL8168f/8111f",	RTL_TD_1, FIRMWARE_8168F_2,
+							JUMBO_9K, false),
 };
 #undef _R
 
@@ -311,6 +341,7 @@ enum rtl_registers {
 	MaxTxPacketSize	= 0xec,	/* 8101/8168. Unit of 128 bytes. */
 
 #define TxPacketMax	(8064 >> 7)
+#define EarlySize	0x27
 
 	FuncEvent	= 0xf0,
 	FuncEventMask	= 0xf4,
@@ -460,8 +491,12 @@ enum rtl_register_content {
 	/* Config3 register p.25 */
 	MagicPacket	= (1 << 5),	/* Wake up when receives a Magic Packet */
 	LinkUp		= (1 << 4),	/* Wake up when the cable connection is re-established */
+	Jumbo_En0	= (1 << 2),	/* 8168 only. Reserved in the 8168b */
 	Beacon_en	= (1 << 0),	/* 8168 only. Reserved in the 8168b */
 
+	/* Config4 register */
+	Jumbo_En1	= (1 << 1),	/* 8168 only. Reserved in the 8168b */
+
 	/* Config5 register p.27 */
 	BWF		= (1 << 6),	/* Accept Broadcast wakeup frame */
 	MWF		= (1 << 5),	/* Accept Multicast wakeup frame */
@@ -670,6 +705,11 @@ struct rtl8169_private {
 		void (*up)(struct rtl8169_private *);
 	} pll_power_ops;
 
+	struct jumbo_ops {
+		void (*enable)(struct rtl8169_private *);
+		void (*disable)(struct rtl8169_private *);
+	} jumbo_ops;
+
 	int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
 	int (*get_settings)(struct net_device *, struct ethtool_cmd *);
 	void (*phy_reset_enable)(struct rtl8169_private *tp);
@@ -714,6 +754,8 @@ MODULE_FIRMWARE(FIRMWARE_8168E_1);
 MODULE_FIRMWARE(FIRMWARE_8168E_2);
 MODULE_FIRMWARE(FIRMWARE_8168E_3);
 MODULE_FIRMWARE(FIRMWARE_8105E_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_2);
 
 static int rtl8169_open(struct net_device *dev);
 static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -732,6 +774,19 @@ static void rtl8169_down(struct net_device *dev);
 static void rtl8169_rx_clear(struct rtl8169_private *tp);
 static int rtl8169_poll(struct napi_struct *napi, int budget);
 
+static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
+{
+	int cap = pci_pcie_cap(pdev);
+
+	if (cap) {
+		u16 ctl;
+
+		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+	}
+}
+
 static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
@@ -1202,6 +1257,19 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
 			     ERIAR_EXGMAC);
 		rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
 			     ERIAR_EXGMAC);
+	} else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+		   tp->mac_version == RTL_GIGA_MAC_VER_36) {
+		if (RTL_R8(PHYstatus) & _1000bpsF) {
+			rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+				      0x00000011, ERIAR_EXGMAC);
+			rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+				      0x00000005, ERIAR_EXGMAC);
+		} else {
+			rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+				      0x0000001f, ERIAR_EXGMAC);
+			rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+				      0x0000003f, ERIAR_EXGMAC);
+		}
 	}
 }
 
@@ -1487,9 +1555,15 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
 {
+	struct rtl8169_private *tp = netdev_priv(dev);
+
 	if (dev->mtu > TD_MSS_MAX)
 		features &= ~NETIF_F_ALL_TSO;
 
+	if (dev->mtu > JUMBO_1K &&
+	    !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
+		features &= ~NETIF_F_IP_CSUM;
+
 	return features;
 }
 
@@ -1741,6 +1815,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		u32 val;
 		int mac_version;
 	} mac_info[] = {
+		/* 8168F family. */
+		{ 0x7cf00000, 0x48100000,	RTL_GIGA_MAC_VER_36 },
+		{ 0x7cf00000, 0x48000000,	RTL_GIGA_MAC_VER_35 },
+
 		/* 8168E family. */
 		{ 0x7c800000, 0x2c800000,	RTL_GIGA_MAC_VER_34 },
 		{ 0x7cf00000, 0x2c200000,	RTL_GIGA_MAC_VER_33 },
@@ -2875,6 +2953,97 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
+{
+	static const struct phy_reg phy_reg_init[] = {
+		/* Channel estimation fine tune */
+		{ 0x1f, 0x0003 },
+		{ 0x09, 0xa20f },
+		{ 0x1f, 0x0000 },
+
+		/* Modify green table for giga & fnet */
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0x8b55 },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b5e },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b67 },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b70 },
+		{ 0x06, 0x0000 },
+		{ 0x1f, 0x0000 },
+		{ 0x1f, 0x0007 },
+		{ 0x1e, 0x0078 },
+		{ 0x17, 0x0000 },
+		{ 0x19, 0x00fb },
+		{ 0x1f, 0x0000 },
+
+		/* Modify green table for 10M */
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0x8b79 },
+		{ 0x06, 0xaa00 },
+		{ 0x1f, 0x0000 },
+
+		/* Disable hiimpedance detection (RTCT) */
+		{ 0x1f, 0x0003 },
+		{ 0x01, 0x328a },
+		{ 0x1f, 0x0000 }
+	};
+
+	rtl_apply_firmware(tp);
+
+	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	/* For 4-corner performance improve */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b80);
+	rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* PHY auto speed down */
+	rtl_writephy(tp, 0x1f, 0x0007);
+	rtl_writephy(tp, 0x1e, 0x002d);
+	rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+	/* Improve 10M EEE waveform */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b86);
+	rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* Improve 2-pair detection performance */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b85);
+	rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
+{
+	rtl_apply_firmware(tp);
+
+	/* For 4-corner performance improve */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b80);
+	rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* PHY auto speed down */
+	rtl_writephy(tp, 0x1f, 0x0007);
+	rtl_writephy(tp, 0x1e, 0x002d);
+	rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+	/* Improve 10M EEE waveform */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b86);
+	rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -2999,6 +3168,12 @@ static void rtl_hw_phy_config(struct net_device *dev)
 	case RTL_GIGA_MAC_VER_34:
 		rtl8168e_2_hw_phy_config(tp);
 		break;
+	case RTL_GIGA_MAC_VER_35:
+		rtl8168f_1_hw_phy_config(tp);
+		break;
+	case RTL_GIGA_MAC_VER_36:
+		rtl8168f_2_hw_phy_config(tp);
+		break;
 
 	default:
 		break;
@@ -3483,8 +3658,8 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
 	r8168_phy_power_up(tp);
 }
 
-static void rtl_pll_power_op(struct rtl8169_private *tp,
-			     void (*op)(struct rtl8169_private *))
+static void rtl_generic_op(struct rtl8169_private *tp,
+			   void (*op)(struct rtl8169_private *))
 {
 	if (op)
 		op(tp);
@@ -3492,12 +3667,12 @@ static void rtl_pll_power_op(struct rtl8169_private *tp,
 
 static void rtl_pll_power_down(struct rtl8169_private *tp)
 {
-	rtl_pll_power_op(tp, tp->pll_power_ops.down);
+	rtl_generic_op(tp, tp->pll_power_ops.down);
 }
 
 static void rtl_pll_power_up(struct rtl8169_private *tp)
 {
-	rtl_pll_power_op(tp, tp->pll_power_ops.up);
+	rtl_generic_op(tp, tp->pll_power_ops.up);
 }
 
 static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
@@ -3534,6 +3709,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_32:
 	case RTL_GIGA_MAC_VER_33:
 	case RTL_GIGA_MAC_VER_34:
+	case RTL_GIGA_MAC_VER_35:
+	case RTL_GIGA_MAC_VER_36:
 		ops->down	= r8168_pll_power_down;
 		ops->up		= r8168_pll_power_up;
 		break;
@@ -3586,6 +3763,150 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
 	tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
 }
 
+static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	rtl_generic_op(tp, tp->jumbo_ops.enable);
+}
+
+static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	rtl_generic_op(tp, tp->jumbo_ops.disable);
+}
+
+static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+	RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
+	rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
+}
+
+static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+	RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
+	rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
+}
+
+static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+}
+
+static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+}
+
+static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct pci_dev *pdev = tp->pci_dev;
+
+	RTL_W8(MaxTxPacketSize, 0x3f);
+	RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
+	RTL_W8(Config4, RTL_R8(Config4) | 0x01);
+	pci_write_config_byte(pdev, 0x79, 0x20);
+}
+
+static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+	struct pci_dev *pdev = tp->pci_dev;
+
+	RTL_W8(MaxTxPacketSize, 0x0c);
+	RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
+	RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
+	pci_write_config_byte(pdev, 0x79, 0x50);
+}
+
+static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	rtl_tx_performance_tweak(tp->pci_dev,
+		(0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	rtl_tx_performance_tweak(tp->pci_dev,
+		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	r8168b_0_hw_jumbo_enable(tp);
+
+	RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
+}
+
+static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
+{
+	void __iomem *ioaddr = tp->mmio_addr;
+
+	r8168b_0_hw_jumbo_disable(tp);
+
+	RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
+{
+	struct jumbo_ops *ops = &tp->jumbo_ops;
+
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_11:
+		ops->disable	= r8168b_0_hw_jumbo_disable;
+		ops->enable	= r8168b_0_hw_jumbo_enable;
+		break;
+	case RTL_GIGA_MAC_VER_12:
+	case RTL_GIGA_MAC_VER_17:
+		ops->disable	= r8168b_1_hw_jumbo_disable;
+		ops->enable	= r8168b_1_hw_jumbo_enable;
+		break;
+	case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
+	case RTL_GIGA_MAC_VER_19:
+	case RTL_GIGA_MAC_VER_20:
+	case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
+	case RTL_GIGA_MAC_VER_22:
+	case RTL_GIGA_MAC_VER_23:
+	case RTL_GIGA_MAC_VER_24:
+	case RTL_GIGA_MAC_VER_25:
+	case RTL_GIGA_MAC_VER_26:
+		ops->disable	= r8168c_hw_jumbo_disable;
+		ops->enable	= r8168c_hw_jumbo_enable;
+		break;
+	case RTL_GIGA_MAC_VER_27:
+	case RTL_GIGA_MAC_VER_28:
+		ops->disable	= r8168dp_hw_jumbo_disable;
+		ops->enable	= r8168dp_hw_jumbo_enable;
+		break;
+	case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
+	case RTL_GIGA_MAC_VER_32:
+	case RTL_GIGA_MAC_VER_33:
+	case RTL_GIGA_MAC_VER_34:
+		ops->disable	= r8168e_hw_jumbo_disable;
+		ops->enable	= r8168e_hw_jumbo_enable;
+		break;
+
+	/*
+	 * No action needed for jumbo frames with 8169.
+	 * No jumbo for 810x at all.
+	 */
+	default:
+		ops->disable	= NULL;
+		ops->enable	= NULL;
+		break;
+	}
+}
+
 static void rtl_hw_reset(struct rtl8169_private *tp)
 {
 	void __iomem *ioaddr = tp->mmio_addr;
@@ -3730,6 +4051,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	rtl_init_mdio_ops(tp);
 	rtl_init_pll_power_ops(tp);
+	rtl_init_jumbo_ops(tp);
 
 	rtl8169_print_mac_version(tp);
 
@@ -3813,6 +4135,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n",
 		   rtl_chip_infos[chipset].name, dev->base_addr, dev->dev_addr,
 		   (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
+	if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
+		netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
+			   "tx checksumming: %s]\n",
+			   rtl_chip_infos[chipset].jumbo_max,
+			   rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
+	}
 
 	if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
 	    tp->mac_version == RTL_GIGA_MAC_VER_28 ||
@@ -4008,7 +4336,9 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	    tp->mac_version == RTL_GIGA_MAC_VER_31) {
 		while (RTL_R8(TxPoll) & NPQ)
 			udelay(20);
-	} else if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
+	} else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_36) {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
 		while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
 			udelay(100);
@@ -4167,19 +4497,6 @@ static void rtl_hw_start_8169(struct net_device *dev)
 	RTL_W16(IntrMask, tp->intr_event);
 }
 
-static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
-{
-	int cap = pci_pcie_cap(pdev);
-
-	if (cap) {
-		u16 ctl;
-
-		pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
-		ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
-		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
-	}
-}
-
 static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
 {
 	u32 csi;
@@ -4479,7 +4796,50 @@ static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev)
 	rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
 		     ERIAR_EXGMAC);
 
-	RTL_W8(MaxTxPacketSize, 0x27);
+	RTL_W8(MaxTxPacketSize, EarlySize);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+	/* Adjust EEE LED frequency */
+	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+	RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
+	RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+	RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
+}
+
+static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static const struct ephy_info e_info_8168f_1[] = {
+		{ 0x06, 0x00c0,	0x0020 },
+		{ 0x08, 0x0001,	0x0002 },
+		{ 0x09, 0x0000,	0x0080 },
+		{ 0x19, 0x0000,	0x0224 }
+	};
+
+	rtl_csi_access_enable_1(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
+		     ERIAR_EXGMAC);
+
+	RTL_W8(MaxTxPacketSize, EarlySize);
 
 	rtl_disable_clock_request(pdev);
 
@@ -4588,6 +4948,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
 		rtl_hw_start_8168e_2(ioaddr, pdev);
 		break;
 
+	case RTL_GIGA_MAC_VER_35:
+	case RTL_GIGA_MAC_VER_36:
+		rtl_hw_start_8168f_1(ioaddr, pdev);
+		break;
+
 	default:
 		printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
 			dev->name, tp->mac_version);
@@ -4759,9 +5124,17 @@ static void rtl_hw_start_8101(struct net_device *dev)
 
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
 {
-	if (new_mtu < ETH_ZLEN || new_mtu > SafeMtu)
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	if (new_mtu < ETH_ZLEN ||
+	    new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
 		return -EINVAL;
 
+	if (new_mtu > ETH_DATA_LEN)
+		rtl_hw_jumbo_enable(tp);
+	else
+		rtl_hw_jumbo_disable(tp);
+
 	dev->mtu = new_mtu;
 	netdev_update_features(dev);
 
@@ -5356,7 +5729,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
 		} else {
 			struct sk_buff *skb;
 			dma_addr_t addr = le64_to_cpu(desc->addr);
-			int pkt_size = (status & 0x00001FFF) - 4;
+			int pkt_size = (status & 0x00003fff) - 4;
 
 			/*
 			 * The driver does not support incoming fragmented
-- 
Ueimor

^ permalink raw reply related

* [PATCH next 1/4] r8169: define the early size for 8111evl
From: Francois Romieu @ 2011-09-22 21:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, Realtek linux nic maintainers, Hayes Wang
In-Reply-To: <20110922210202.GA16362@electric-eye.fr.zoreil.com>

For RTL8111EVL, the register of MaxTxPacketSize doesn't acctually
limit the tx size. It influnces the feature of early tx.

Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
 drivers/net/ethernet/realtek/r8169.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 6eb9f4e..44b40ea 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -311,6 +311,7 @@ enum rtl_registers {
 	MaxTxPacketSize	= 0xec,	/* 8101/8168. Unit of 128 bytes. */
 
 #define TxPacketMax	(8064 >> 7)
+#define EarlySize	0x27
 
 	FuncEvent	= 0xf0,
 	FuncEventMask	= 0xf4,
@@ -4479,7 +4480,7 @@ static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev)
 	rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
 		     ERIAR_EXGMAC);
 
-	RTL_W8(MaxTxPacketSize, 0x27);
+	RTL_W8(MaxTxPacketSize, EarlySize);
 
 	rtl_disable_clock_request(pdev);
 
-- 
1.7.6

^ permalink raw reply related

* [PATCH next 2/4] r8169: support new chips of RTL8111F
From: Francois Romieu @ 2011-09-22 21:03 UTC (permalink / raw)
  To: davem; +Cc: netdev, Realtek linux nic maintainers, Hayes Wang
In-Reply-To: <20110922210202.GA16362@electric-eye.fr.zoreil.com>

Support new chips of RTL8111F.

Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
 drivers/net/ethernet/realtek/r8169.c |  180 +++++++++++++++++++++++++++++++++-
 1 files changed, 178 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 44b40ea..9a5965e 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -42,6 +42,8 @@
 #define FIRMWARE_8168E_1	"rtl_nic/rtl8168e-1.fw"
 #define FIRMWARE_8168E_2	"rtl_nic/rtl8168e-2.fw"
 #define FIRMWARE_8168E_3	"rtl_nic/rtl8168e-3.fw"
+#define FIRMWARE_8168F_1	"rtl_nic/rtl8168f-1.fw"
+#define FIRMWARE_8168F_2	"rtl_nic/rtl8168f-2.fw"
 #define FIRMWARE_8105E_1	"rtl_nic/rtl8105e-1.fw"
 
 #ifdef RTL8169_DEBUG
@@ -133,6 +135,8 @@ enum mac_version {
 	RTL_GIGA_MAC_VER_32,
 	RTL_GIGA_MAC_VER_33,
 	RTL_GIGA_MAC_VER_34,
+	RTL_GIGA_MAC_VER_35,
+	RTL_GIGA_MAC_VER_36,
 	RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -218,7 +222,11 @@ static const struct {
 	[RTL_GIGA_MAC_VER_33] =
 		_R("RTL8168e/8111e",	RTL_TD_1, FIRMWARE_8168E_2),
 	[RTL_GIGA_MAC_VER_34] =
-		_R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3)
+		_R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3),
+	[RTL_GIGA_MAC_VER_35] =
+		_R("RTL8168f/8111f",	RTL_TD_1, FIRMWARE_8168F_1),
+	[RTL_GIGA_MAC_VER_36] =
+		_R("RTL8168f/8111f",	RTL_TD_1, FIRMWARE_8168F_2)
 };
 #undef _R
 
@@ -715,6 +723,8 @@ MODULE_FIRMWARE(FIRMWARE_8168E_1);
 MODULE_FIRMWARE(FIRMWARE_8168E_2);
 MODULE_FIRMWARE(FIRMWARE_8168E_3);
 MODULE_FIRMWARE(FIRMWARE_8105E_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_1);
+MODULE_FIRMWARE(FIRMWARE_8168F_2);
 
 static int rtl8169_open(struct net_device *dev);
 static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -1203,6 +1213,19 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
 			     ERIAR_EXGMAC);
 		rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
 			     ERIAR_EXGMAC);
+	} else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+		   tp->mac_version == RTL_GIGA_MAC_VER_36) {
+		if (RTL_R8(PHYstatus) & _1000bpsF) {
+			rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+				      0x00000011, ERIAR_EXGMAC);
+			rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+				      0x00000005, ERIAR_EXGMAC);
+		} else {
+			rtl_eri_write(ioaddr, 0x1bc, ERIAR_MASK_1111,
+				      0x0000001f, ERIAR_EXGMAC);
+			rtl_eri_write(ioaddr, 0x1dc, ERIAR_MASK_1111,
+				      0x0000003f, ERIAR_EXGMAC);
+		}
 	}
 }
 
@@ -1742,6 +1765,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
 		u32 val;
 		int mac_version;
 	} mac_info[] = {
+		/* 8168F family. */
+		{ 0x7cf00000, 0x48100000,	RTL_GIGA_MAC_VER_36 },
+		{ 0x7cf00000, 0x48000000,	RTL_GIGA_MAC_VER_35 },
+
 		/* 8168E family. */
 		{ 0x7c800000, 0x2c800000,	RTL_GIGA_MAC_VER_34 },
 		{ 0x7cf00000, 0x2c200000,	RTL_GIGA_MAC_VER_33 },
@@ -2876,6 +2903,97 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
 	rtl_writephy(tp, 0x1f, 0x0000);
 }
 
+static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
+{
+	static const struct phy_reg phy_reg_init[] = {
+		/* Channel estimation fine tune */
+		{ 0x1f, 0x0003 },
+		{ 0x09, 0xa20f },
+		{ 0x1f, 0x0000 },
+
+		/* Modify green table for giga & fnet */
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0x8b55 },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b5e },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b67 },
+		{ 0x06, 0x0000 },
+		{ 0x05, 0x8b70 },
+		{ 0x06, 0x0000 },
+		{ 0x1f, 0x0000 },
+		{ 0x1f, 0x0007 },
+		{ 0x1e, 0x0078 },
+		{ 0x17, 0x0000 },
+		{ 0x19, 0x00fb },
+		{ 0x1f, 0x0000 },
+
+		/* Modify green table for 10M */
+		{ 0x1f, 0x0005 },
+		{ 0x05, 0x8b79 },
+		{ 0x06, 0xaa00 },
+		{ 0x1f, 0x0000 },
+
+		/* Disable hiimpedance detection (RTCT) */
+		{ 0x1f, 0x0003 },
+		{ 0x01, 0x328a },
+		{ 0x1f, 0x0000 }
+	};
+
+	rtl_apply_firmware(tp);
+
+	rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+	/* For 4-corner performance improve */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b80);
+	rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* PHY auto speed down */
+	rtl_writephy(tp, 0x1f, 0x0007);
+	rtl_writephy(tp, 0x1e, 0x002d);
+	rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+	/* Improve 10M EEE waveform */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b86);
+	rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* Improve 2-pair detection performance */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b85);
+	rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
+{
+	rtl_apply_firmware(tp);
+
+	/* For 4-corner performance improve */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b80);
+	rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+
+	/* PHY auto speed down */
+	rtl_writephy(tp, 0x1f, 0x0007);
+	rtl_writephy(tp, 0x1e, 0x002d);
+	rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+	rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+	/* Improve 10M EEE waveform */
+	rtl_writephy(tp, 0x1f, 0x0005);
+	rtl_writephy(tp, 0x05, 0x8b86);
+	rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+	rtl_writephy(tp, 0x1f, 0x0000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
 	static const struct phy_reg phy_reg_init[] = {
@@ -3000,6 +3118,12 @@ static void rtl_hw_phy_config(struct net_device *dev)
 	case RTL_GIGA_MAC_VER_34:
 		rtl8168e_2_hw_phy_config(tp);
 		break;
+	case RTL_GIGA_MAC_VER_35:
+		rtl8168f_1_hw_phy_config(tp);
+		break;
+	case RTL_GIGA_MAC_VER_36:
+		rtl8168f_2_hw_phy_config(tp);
+		break;
 
 	default:
 		break;
@@ -3535,6 +3659,8 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_32:
 	case RTL_GIGA_MAC_VER_33:
 	case RTL_GIGA_MAC_VER_34:
+	case RTL_GIGA_MAC_VER_35:
+	case RTL_GIGA_MAC_VER_36:
 		ops->down	= r8168_pll_power_down;
 		ops->up		= r8168_pll_power_up;
 		break;
@@ -4009,7 +4135,9 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
 	    tp->mac_version == RTL_GIGA_MAC_VER_31) {
 		while (RTL_R8(TxPoll) & NPQ)
 			udelay(20);
-	} else if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
+	} else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+	           tp->mac_version == RTL_GIGA_MAC_VER_36) {
 		RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
 		while (!(RTL_R32(TxConfig) & TXCFG_EMPTY))
 			udelay(100);
@@ -4495,6 +4623,49 @@ static void rtl_hw_start_8168e_2(void __iomem *ioaddr, struct pci_dev *pdev)
 	RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
 }
 
+static void rtl_hw_start_8168f_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+	static const struct ephy_info e_info_8168f_1[] = {
+		{ 0x06, 0x00c0,	0x0020 },
+		{ 0x08, 0x0001,	0x0002 },
+		{ 0x09, 0x0000,	0x0080 },
+		{ 0x19, 0x0000,	0x0224 }
+	};
+
+	rtl_csi_access_enable_1(ioaddr);
+
+	rtl_ephy_init(ioaddr, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
+
+	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+	rtl_eri_write(ioaddr, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
+	rtl_eri_write(ioaddr, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
+	rtl_w1w0_eri(ioaddr, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00,
+		     ERIAR_EXGMAC);
+
+	RTL_W8(MaxTxPacketSize, EarlySize);
+
+	rtl_disable_clock_request(pdev);
+
+	RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+	RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
+
+	/* Adjust EEE LED frequency */
+	RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+	RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
+	RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+	RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -4589,6 +4760,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
 		rtl_hw_start_8168e_2(ioaddr, pdev);
 		break;
 
+	case RTL_GIGA_MAC_VER_35:
+	case RTL_GIGA_MAC_VER_36:
+		rtl_hw_start_8168f_1(ioaddr, pdev);
+		break;
+
 	default:
 		printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
 			dev->name, tp->mac_version);
-- 
1.7.6

^ 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