All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/11] s390/qeth: updates 2020-05-05
@ 2020-05-05 16:25 Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 01/11] s390/qeth: keep track of LP2LP capability for csum offload Julian Wiedmann
                   ` (10 more replies)
  0 siblings, 11 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

Hi Dave,

please apply the following patch series for qeth to netdev's net-next
tree.

This primarily adds infrastructure to deal with HW offloads when the
packets get forwarded over the adapter's internal switch.
Aside from that, just some minor tweaking for the TX code and support
for ethtool-driven reset.

Thanks,
Julian

Julian Wiedmann (11):
  s390/qeth: keep track of LP2LP capability for csum offload
  s390/qeth: process local address events
  s390/qeth: add debugfs file for local IP addresses
  s390/qeth: extract helpers for next-hop lookup
  s390/qeth: don't use restricted offloads for local traffic
  s390/qeth: merge TX skb mapping code
  s390/qeth: indicate contiguous TX buffer elements
  s390/qeth: set TX IRQ marker on last buffer in a group
  s390/qeth: return error when starting a reset fails
  s390/qeth: allow reset via ethtool
  s390/qeth: clean up Kconfig help text

 drivers/s390/net/Kconfig          |   9 +-
 drivers/s390/net/qeth_core.h      |  49 +++-
 drivers/s390/net/qeth_core_main.c | 465 +++++++++++++++++++++++++-----
 drivers/s390/net/qeth_core_mpc.h  |  25 ++
 drivers/s390/net/qeth_core_sys.c  |  15 +-
 drivers/s390/net/qeth_ethtool.c   |  16 +
 drivers/s390/net/qeth_l2_main.c   |   2 +
 drivers/s390/net/qeth_l3_main.c   |  19 +-
 8 files changed, 502 insertions(+), 98 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH net-next 01/11] s390/qeth: keep track of LP2LP capability for csum offload
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 02/11] s390/qeth: process local address events Julian Wiedmann
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

When enabling TX CSO, make a note of whether the device has support for
LP2LP offloading. This will become relevant in subsequent patches.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core.h      |  3 +++
 drivers/s390/net/qeth_core_main.c | 23 ++++++++++++++---------
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index e0b26310ecab..2ac7771394d8 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -688,6 +688,9 @@ struct qeth_card_info {
 	u8 promisc_mode:1;
 	u8 use_v1_blkt:1;
 	u8 is_vm_nic:1;
+	/* no bitfield, we take a pointer on these two: */
+	u8 has_lp2lp_cso_v6;
+	u8 has_lp2lp_cso_v4;
 	enum qeth_card_types type;
 	enum qeth_link_types link_type;
 	int broadcast_capable;
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index f7689461c242..ef96890eea5c 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -6300,7 +6300,7 @@ static int qeth_set_csum_off(struct qeth_card *card, enum qeth_ipa_funcs cstype,
 }
 
 static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
-			    enum qeth_prot_versions prot)
+			    enum qeth_prot_versions prot, u8 *lp2lp)
 {
 	u32 required_features = QETH_IPA_CHECKSUM_UDP | QETH_IPA_CHECKSUM_TCP;
 	struct qeth_cmd_buffer *iob;
@@ -6352,8 +6352,11 @@ static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
 
 	dev_info(&card->gdev->dev, "HW Checksumming (%sbound IPv%d) enabled\n",
 		 cstype == IPA_INBOUND_CHECKSUM ? "in" : "out", prot);
-	if (!qeth_ipa_caps_enabled(&caps, QETH_IPA_CHECKSUM_LP2LP) &&
-	    cstype == IPA_OUTBOUND_CHECKSUM)
+
+	if (lp2lp)
+		*lp2lp = qeth_ipa_caps_enabled(&caps, QETH_IPA_CHECKSUM_LP2LP);
+
+	if (lp2lp && !*lp2lp)
 		dev_warn(&card->gdev->dev,
 			 "Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n",
 			 QETH_CARD_IFNAME(card));
@@ -6361,9 +6364,9 @@ static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
 }
 
 static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype,
-			     enum qeth_prot_versions prot)
+			     enum qeth_prot_versions prot, u8 *lp2lp)
 {
-	return on ? qeth_set_csum_on(card, cstype, prot) :
+	return on ? qeth_set_csum_on(card, cstype, prot, lp2lp) :
 		    qeth_set_csum_off(card, cstype, prot);
 }
 
@@ -6451,13 +6454,13 @@ static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on)
 
 	if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
 		rc_ipv4 = qeth_set_ipa_csum(card, on, IPA_INBOUND_CHECKSUM,
-					    QETH_PROT_IPV4);
+					    QETH_PROT_IPV4, NULL);
 	if (!qeth_is_supported6(card, IPA_INBOUND_CHECKSUM_V6))
 		/* no/one Offload Assist available, so the rc is trivial */
 		return rc_ipv4;
 
 	rc_ipv6 = qeth_set_ipa_csum(card, on, IPA_INBOUND_CHECKSUM,
-				    QETH_PROT_IPV6);
+				    QETH_PROT_IPV6, NULL);
 
 	if (on)
 		/* enable: success if any Assist is active */
@@ -6504,13 +6507,15 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features)
 
 	if ((changed & NETIF_F_IP_CSUM)) {
 		rc = qeth_set_ipa_csum(card, features & NETIF_F_IP_CSUM,
-				       IPA_OUTBOUND_CHECKSUM, QETH_PROT_IPV4);
+				       IPA_OUTBOUND_CHECKSUM, QETH_PROT_IPV4,
+				       &card->info.has_lp2lp_cso_v4);
 		if (rc)
 			changed ^= NETIF_F_IP_CSUM;
 	}
 	if (changed & NETIF_F_IPV6_CSUM) {
 		rc = qeth_set_ipa_csum(card, features & NETIF_F_IPV6_CSUM,
-				       IPA_OUTBOUND_CHECKSUM, QETH_PROT_IPV6);
+				       IPA_OUTBOUND_CHECKSUM, QETH_PROT_IPV6,
+				       &card->info.has_lp2lp_cso_v6);
 		if (rc)
 			changed ^= NETIF_F_IPV6_CSUM;
 	}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 02/11] s390/qeth: process local address events
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 01/11] s390/qeth: keep track of LP2LP capability for csum offload Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 03/11] s390/qeth: add debugfs file for local IP addresses Julian Wiedmann
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

In configurations where specific HW offloads are in use, OSA adapters
will raise notifications to their virtual devices about the IP addresses
that currently reside on the same adapter.
Cache these addresses in two RCU-enabled hash tables, and flush the
tables once the relevant HW offload(s) get disabled.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core.h      |  13 ++
 drivers/s390/net/qeth_core_main.c | 217 ++++++++++++++++++++++++++++++
 drivers/s390/net/qeth_core_mpc.h  |  25 ++++
 drivers/s390/net/qeth_l2_main.c   |   1 +
 drivers/s390/net/qeth_l3_main.c   |   1 +
 5 files changed, 257 insertions(+)

diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 2ac7771394d8..b92af3735dd4 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -21,8 +21,10 @@
 #include <linux/seq_file.h>
 #include <linux/hashtable.h>
 #include <linux/ip.h>
+#include <linux/rcupdate.h>
 #include <linux/refcount.h>
 #include <linux/timer.h>
+#include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
@@ -356,6 +358,12 @@ static inline bool qeth_l3_same_next_hop(struct qeth_hdr_layer3 *h1,
 			       &h2->next_hop.ipv6_addr);
 }
 
+struct qeth_local_addr {
+	struct hlist_node hnode;
+	struct rcu_head rcu;
+	struct in6_addr addr;
+};
+
 enum qeth_qdio_info_states {
 	QETH_QDIO_UNINITIALIZED,
 	QETH_QDIO_ALLOCATED,
@@ -800,6 +808,10 @@ struct qeth_card {
 	wait_queue_head_t wait_q;
 	DECLARE_HASHTABLE(mac_htable, 4);
 	DECLARE_HASHTABLE(ip_htable, 4);
+	DECLARE_HASHTABLE(local_addrs4, 4);
+	DECLARE_HASHTABLE(local_addrs6, 4);
+	spinlock_t local_addrs4_lock;
+	spinlock_t local_addrs6_lock;
 	struct mutex ip_lock;
 	DECLARE_HASHTABLE(ip_mc_htable, 4);
 	struct work_struct rx_mode_work;
@@ -1025,6 +1037,7 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
 void qeth_put_cmd(struct qeth_cmd_buffer *iob);
 
 void qeth_schedule_recovery(struct qeth_card *);
+void qeth_flush_local_addrs(struct qeth_card *card);
 int qeth_poll(struct napi_struct *napi, int budget);
 void qeth_clear_ipacmd_list(struct qeth_card *);
 int qeth_qdio_clear_card(struct qeth_card *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index ef96890eea5c..6b5d42a4501c 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -26,6 +26,7 @@
 #include <linux/if_vlan.h>
 #include <linux/netdevice.h>
 #include <linux/netdev_features.h>
+#include <linux/rcutree.h>
 #include <linux/skbuff.h>
 #include <linux/vmalloc.h>
 
@@ -623,6 +624,187 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason)
 }
 EXPORT_SYMBOL_GPL(qeth_notify_cmd);
 
+static void qeth_flush_local_addrs4(struct qeth_card *card)
+{
+	struct qeth_local_addr *addr;
+	struct hlist_node *tmp;
+	unsigned int i;
+
+	spin_lock_irq(&card->local_addrs4_lock);
+	hash_for_each_safe(card->local_addrs4, i, tmp, addr, hnode) {
+		hash_del_rcu(&addr->hnode);
+		kfree_rcu(addr, rcu);
+	}
+	spin_unlock_irq(&card->local_addrs4_lock);
+}
+
+static void qeth_flush_local_addrs6(struct qeth_card *card)
+{
+	struct qeth_local_addr *addr;
+	struct hlist_node *tmp;
+	unsigned int i;
+
+	spin_lock_irq(&card->local_addrs6_lock);
+	hash_for_each_safe(card->local_addrs6, i, tmp, addr, hnode) {
+		hash_del_rcu(&addr->hnode);
+		kfree_rcu(addr, rcu);
+	}
+	spin_unlock_irq(&card->local_addrs6_lock);
+}
+
+void qeth_flush_local_addrs(struct qeth_card *card)
+{
+	qeth_flush_local_addrs4(card);
+	qeth_flush_local_addrs6(card);
+}
+EXPORT_SYMBOL_GPL(qeth_flush_local_addrs);
+
+static void qeth_add_local_addrs4(struct qeth_card *card,
+				  struct qeth_ipacmd_local_addrs4 *cmd)
+{
+	unsigned int i;
+
+	if (cmd->addr_length !=
+	    sizeof_field(struct qeth_ipacmd_local_addr4, addr)) {
+		dev_err_ratelimited(&card->gdev->dev,
+				    "Dropped IPv4 ADD LOCAL ADDR event with bad length %u\n",
+				    cmd->addr_length);
+		return;
+	}
+
+	spin_lock(&card->local_addrs4_lock);
+	for (i = 0; i < cmd->count; i++) {
+		unsigned int key = ipv4_addr_hash(cmd->addrs[i].addr);
+		struct qeth_local_addr *addr;
+		bool duplicate = false;
+
+		hash_for_each_possible(card->local_addrs4, addr, hnode, key) {
+			if (addr->addr.s6_addr32[3] == cmd->addrs[i].addr) {
+				duplicate = true;
+				break;
+			}
+		}
+
+		if (duplicate)
+			continue;
+
+		addr = kmalloc(sizeof(*addr), GFP_ATOMIC);
+		if (!addr) {
+			dev_err(&card->gdev->dev,
+				"Failed to allocate local addr object. Traffic to %pI4 might suffer.\n",
+				&cmd->addrs[i].addr);
+			continue;
+		}
+
+		ipv6_addr_set(&addr->addr, 0, 0, 0, cmd->addrs[i].addr);
+		hash_add_rcu(card->local_addrs4, &addr->hnode, key);
+	}
+	spin_unlock(&card->local_addrs4_lock);
+}
+
+static void qeth_add_local_addrs6(struct qeth_card *card,
+				  struct qeth_ipacmd_local_addrs6 *cmd)
+{
+	unsigned int i;
+
+	if (cmd->addr_length !=
+	    sizeof_field(struct qeth_ipacmd_local_addr6, addr)) {
+		dev_err_ratelimited(&card->gdev->dev,
+				    "Dropped IPv6 ADD LOCAL ADDR event with bad length %u\n",
+				    cmd->addr_length);
+		return;
+	}
+
+	spin_lock(&card->local_addrs6_lock);
+	for (i = 0; i < cmd->count; i++) {
+		u32 key = ipv6_addr_hash(&cmd->addrs[i].addr);
+		struct qeth_local_addr *addr;
+		bool duplicate = false;
+
+		hash_for_each_possible(card->local_addrs6, addr, hnode, key) {
+			if (ipv6_addr_equal(&addr->addr, &cmd->addrs[i].addr)) {
+				duplicate = true;
+				break;
+			}
+		}
+
+		if (duplicate)
+			continue;
+
+		addr = kmalloc(sizeof(*addr), GFP_ATOMIC);
+		if (!addr) {
+			dev_err(&card->gdev->dev,
+				"Failed to allocate local addr object. Traffic to %pI6c might suffer.\n",
+				&cmd->addrs[i].addr);
+			continue;
+		}
+
+		addr->addr = cmd->addrs[i].addr;
+		hash_add_rcu(card->local_addrs6, &addr->hnode, key);
+	}
+	spin_unlock(&card->local_addrs6_lock);
+}
+
+static void qeth_del_local_addrs4(struct qeth_card *card,
+				  struct qeth_ipacmd_local_addrs4 *cmd)
+{
+	unsigned int i;
+
+	if (cmd->addr_length !=
+	    sizeof_field(struct qeth_ipacmd_local_addr4, addr)) {
+		dev_err_ratelimited(&card->gdev->dev,
+				    "Dropped IPv4 DEL LOCAL ADDR event with bad length %u\n",
+				    cmd->addr_length);
+		return;
+	}
+
+	spin_lock(&card->local_addrs4_lock);
+	for (i = 0; i < cmd->count; i++) {
+		struct qeth_ipacmd_local_addr4 *addr = &cmd->addrs[i];
+		unsigned int key = ipv4_addr_hash(addr->addr);
+		struct qeth_local_addr *tmp;
+
+		hash_for_each_possible(card->local_addrs4, tmp, hnode, key) {
+			if (tmp->addr.s6_addr32[3] == addr->addr) {
+				hash_del_rcu(&tmp->hnode);
+				kfree_rcu(tmp, rcu);
+				break;
+			}
+		}
+	}
+	spin_unlock(&card->local_addrs4_lock);
+}
+
+static void qeth_del_local_addrs6(struct qeth_card *card,
+				  struct qeth_ipacmd_local_addrs6 *cmd)
+{
+	unsigned int i;
+
+	if (cmd->addr_length !=
+	    sizeof_field(struct qeth_ipacmd_local_addr6, addr)) {
+		dev_err_ratelimited(&card->gdev->dev,
+				    "Dropped IPv6 DEL LOCAL ADDR event with bad length %u\n",
+				    cmd->addr_length);
+		return;
+	}
+
+	spin_lock(&card->local_addrs6_lock);
+	for (i = 0; i < cmd->count; i++) {
+		struct qeth_ipacmd_local_addr6 *addr = &cmd->addrs[i];
+		u32 key = ipv6_addr_hash(&addr->addr);
+		struct qeth_local_addr *tmp;
+
+		hash_for_each_possible(card->local_addrs6, tmp, hnode, key) {
+			if (ipv6_addr_equal(&tmp->addr, &addr->addr)) {
+				hash_del_rcu(&tmp->hnode);
+				kfree_rcu(tmp, rcu);
+				break;
+			}
+		}
+	}
+	spin_unlock(&card->local_addrs6_lock);
+}
+
 static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
 		struct qeth_card *card)
 {
@@ -686,9 +868,19 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
 	case IPA_CMD_MODCCID:
 		return cmd;
 	case IPA_CMD_REGISTER_LOCAL_ADDR:
+		if (cmd->hdr.prot_version == QETH_PROT_IPV4)
+			qeth_add_local_addrs4(card, &cmd->data.local_addrs4);
+		else if (cmd->hdr.prot_version == QETH_PROT_IPV6)
+			qeth_add_local_addrs6(card, &cmd->data.local_addrs6);
+
 		QETH_CARD_TEXT(card, 3, "irla");
 		return NULL;
 	case IPA_CMD_UNREGISTER_LOCAL_ADDR:
+		if (cmd->hdr.prot_version == QETH_PROT_IPV4)
+			qeth_del_local_addrs4(card, &cmd->data.local_addrs4);
+		else if (cmd->hdr.prot_version == QETH_PROT_IPV6)
+			qeth_del_local_addrs6(card, &cmd->data.local_addrs6);
+
 		QETH_CARD_TEXT(card, 3, "urla");
 		return NULL;
 	default:
@@ -1376,6 +1568,10 @@ static void qeth_setup_card(struct qeth_card *card)
 	qeth_init_qdio_info(card);
 	INIT_DELAYED_WORK(&card->buffer_reclaim_work, qeth_buffer_reclaim_work);
 	INIT_WORK(&card->close_dev_work, qeth_close_dev_handler);
+	hash_init(card->local_addrs4);
+	hash_init(card->local_addrs6);
+	spin_lock_init(&card->local_addrs4_lock);
+	spin_lock_init(&card->local_addrs6_lock);
 }
 
 static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
@@ -6496,6 +6692,24 @@ void qeth_enable_hw_features(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(qeth_enable_hw_features);
 
+static void qeth_check_restricted_features(struct qeth_card *card,
+					   netdev_features_t changed,
+					   netdev_features_t actual)
+{
+	netdev_features_t ipv6_features = NETIF_F_TSO6;
+	netdev_features_t ipv4_features = NETIF_F_TSO;
+
+	if (!card->info.has_lp2lp_cso_v6)
+		ipv6_features |= NETIF_F_IPV6_CSUM;
+	if (!card->info.has_lp2lp_cso_v4)
+		ipv4_features |= NETIF_F_IP_CSUM;
+
+	if ((changed & ipv6_features) && !(actual & ipv6_features))
+		qeth_flush_local_addrs6(card);
+	if ((changed & ipv4_features) && !(actual & ipv4_features))
+		qeth_flush_local_addrs4(card);
+}
+
 int qeth_set_features(struct net_device *dev, netdev_features_t features)
 {
 	struct qeth_card *card = dev->ml_priv;
@@ -6537,6 +6751,9 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features)
 			changed ^= NETIF_F_TSO6;
 	}
 
+	qeth_check_restricted_features(card, dev->features ^ features,
+				       dev->features ^ changed);
+
 	/* everything changed successfully? */
 	if ((dev->features ^ features) == changed)
 		return 0;
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index d89a04bfd8b0..9d6f39d8f9ab 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -772,6 +772,29 @@ struct qeth_ipacmd_addr_change {
 	struct qeth_ipacmd_addr_change_entry entry[];
 } __packed;
 
+/* [UN]REGISTER_LOCAL_ADDRESS notifications */
+struct qeth_ipacmd_local_addr4 {
+	__be32 addr;
+	u32 flags;
+};
+
+struct qeth_ipacmd_local_addrs4 {
+	u32 count;
+	u32 addr_length;
+	struct qeth_ipacmd_local_addr4 addrs[];
+};
+
+struct qeth_ipacmd_local_addr6 {
+	struct in6_addr addr;
+	u32 flags;
+};
+
+struct qeth_ipacmd_local_addrs6 {
+	u32 count;
+	u32 addr_length;
+	struct qeth_ipacmd_local_addr6 addrs[];
+};
+
 /* Header for each IPA command */
 struct qeth_ipacmd_hdr {
 	__u8   command;
@@ -803,6 +826,8 @@ struct qeth_ipa_cmd {
 		struct qeth_ipacmd_setbridgeport	sbp;
 		struct qeth_ipacmd_addr_change		addrchange;
 		struct qeth_ipacmd_vnicc		vnicc;
+		struct qeth_ipacmd_local_addrs4		local_addrs4;
+		struct qeth_ipacmd_local_addrs6		local_addrs6;
 	} data;
 } __attribute__ ((packed));
 
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 0bd5b09e7a22..47f624b37040 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -291,6 +291,7 @@ static void qeth_l2_stop_card(struct qeth_card *card)
 	qeth_qdio_clear_card(card, 0);
 	qeth_clear_working_pool_list(card);
 	flush_workqueue(card->event_wq);
+	qeth_flush_local_addrs(card);
 	card->info.promisc_mode = 0;
 }
 
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 0742a749d26e..fec4ac41e946 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1176,6 +1176,7 @@ static void qeth_l3_stop_card(struct qeth_card *card)
 	qeth_qdio_clear_card(card, 0);
 	qeth_clear_working_pool_list(card);
 	flush_workqueue(card->event_wq);
+	qeth_flush_local_addrs(card);
 	card->info.promisc_mode = 0;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 03/11] s390/qeth: add debugfs file for local IP addresses
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 01/11] s390/qeth: keep track of LP2LP capability for csum offload Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 02/11] s390/qeth: process local address events Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 04/11] s390/qeth: extract helpers for next-hop lookup Julian Wiedmann
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

For debugging purposes, provide read access to the local_addr caches
via debug/qeth/<dev_name>/local_addrs.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core.h      |  2 ++
 drivers/s390/net/qeth_core_main.c | 32 ++++++++++++++++++++++++++++++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index b92af3735dd4..3d8b8e0f2438 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -11,6 +11,7 @@
 #define __QETH_CORE_H__
 
 #include <linux/completion.h>
+#include <linux/debugfs.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -797,6 +798,7 @@ struct qeth_card {
 	struct qeth_channel data;
 
 	struct net_device *dev;
+	struct dentry *debugfs;
 	struct qeth_card_stats stats;
 	struct qeth_card_info info;
 	struct qeth_token token;
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 6b5d42a4501c..771282cb7aef 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -61,6 +61,7 @@ EXPORT_SYMBOL_GPL(qeth_core_header_cache);
 static struct kmem_cache *qeth_qdio_outbuf_cache;
 
 static struct device *qeth_core_root_dev;
+static struct dentry *qeth_debugfs_root;
 static struct lock_class_key qdio_out_skb_queue_key;
 
 static void qeth_issue_next_read_cb(struct qeth_card *card,
@@ -805,6 +806,24 @@ static void qeth_del_local_addrs6(struct qeth_card *card,
 	spin_unlock(&card->local_addrs6_lock);
 }
 
+static int qeth_debugfs_local_addr_show(struct seq_file *m, void *v)
+{
+	struct qeth_card *card = m->private;
+	struct qeth_local_addr *tmp;
+	unsigned int i;
+
+	rcu_read_lock();
+	hash_for_each_rcu(card->local_addrs4, i, tmp, hnode)
+		seq_printf(m, "%pI4\n", &tmp->addr.s6_addr32[3]);
+	hash_for_each_rcu(card->local_addrs6, i, tmp, hnode)
+		seq_printf(m, "%pI6c\n", &tmp->addr);
+	rcu_read_unlock();
+
+	return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(qeth_debugfs_local_addr);
+
 static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
 		struct qeth_card *card)
 {
@@ -1608,6 +1627,11 @@ static struct qeth_card *qeth_alloc_card(struct ccwgroup_device *gdev)
 	if (!card->read_cmd)
 		goto out_read_cmd;
 
+	card->debugfs = debugfs_create_dir(dev_name(&gdev->dev),
+					   qeth_debugfs_root);
+	debugfs_create_file("local_addrs", 0400, card->debugfs, card,
+			    &qeth_debugfs_local_addr_fops);
+
 	card->qeth_service_level.seq_print = qeth_core_sl_print;
 	register_service_level(&card->qeth_service_level);
 	return card;
@@ -5085,9 +5109,11 @@ static int qeth_qdio_establish(struct qeth_card *card)
 static void qeth_core_free_card(struct qeth_card *card)
 {
 	QETH_CARD_TEXT(card, 2, "freecrd");
+
+	unregister_service_level(&card->qeth_service_level);
+	debugfs_remove_recursive(card->debugfs);
 	qeth_put_cmd(card->read_cmd);
 	destroy_workqueue(card->event_wq);
-	unregister_service_level(&card->qeth_service_level);
 	dev_set_drvdata(&card->gdev->dev, NULL);
 	kfree(card);
 }
@@ -6967,6 +6993,8 @@ static int __init qeth_core_init(void)
 
 	pr_info("loading core functions\n");
 
+	qeth_debugfs_root = debugfs_create_dir("qeth", NULL);
+
 	rc = qeth_register_dbf_views();
 	if (rc)
 		goto dbf_err;
@@ -7008,6 +7036,7 @@ static int __init qeth_core_init(void)
 register_err:
 	qeth_unregister_dbf_views();
 dbf_err:
+	debugfs_remove_recursive(qeth_debugfs_root);
 	pr_err("Initializing the qeth device driver failed\n");
 	return rc;
 }
@@ -7021,6 +7050,7 @@ static void __exit qeth_core_exit(void)
 	kmem_cache_destroy(qeth_core_header_cache);
 	root_device_unregister(qeth_core_root_dev);
 	qeth_unregister_dbf_views();
+	debugfs_remove_recursive(qeth_debugfs_root);
 	pr_info("core functions removed\n");
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 04/11] s390/qeth: extract helpers for next-hop lookup
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (2 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 03/11] s390/qeth: add debugfs file for local IP addresses Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 05/11] s390/qeth: don't use restricted offloads for local traffic Julian Wiedmann
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

These will be used in a subsequent patch.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core.h    | 29 ++++++++++++++++++++++-------
 drivers/s390/net/qeth_l3_main.c | 18 +++++-------------
 2 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 3d8b8e0f2438..6b0d37d2c638 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -34,6 +34,7 @@
 #include <net/ipv6.h>
 #include <net/if_inet6.h>
 #include <net/addrconf.h>
+#include <net/route.h>
 #include <net/sch_generic.h>
 #include <net/tcp.h>
 
@@ -234,11 +235,7 @@ struct qeth_hdr_layer3 {
 	__u16 frame_offset;
 	union {
 		/* TX: */
-		struct in6_addr ipv6_addr;
-		struct ipv4 {
-			u8 res[12];
-			u32 addr;
-		} ipv4;
+		struct in6_addr addr;
 		/* RX: */
 		struct rx {
 			u8 res1[2];
@@ -355,8 +352,7 @@ static inline bool qeth_l3_same_next_hop(struct qeth_hdr_layer3 *h1,
 					 struct qeth_hdr_layer3 *h2)
 {
 	return !((h1->flags ^ h2->flags) & QETH_HDR_IPV6) &&
-	       ipv6_addr_equal(&h1->next_hop.ipv6_addr,
-			       &h2->next_hop.ipv6_addr);
+	       ipv6_addr_equal(&h1->next_hop.addr, &h2->next_hop.addr);
 }
 
 struct qeth_local_addr {
@@ -945,6 +941,25 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv)
 	return dst;
 }
 
+static inline __be32 qeth_next_hop_v4_rcu(struct sk_buff *skb,
+					  struct dst_entry *dst)
+{
+	struct rtable *rt = (struct rtable *) dst;
+
+	return (rt) ? rt_nexthop(rt, ip_hdr(skb)->daddr) : ip_hdr(skb)->daddr;
+}
+
+static inline struct in6_addr *qeth_next_hop_v6_rcu(struct sk_buff *skb,
+						    struct dst_entry *dst)
+{
+	struct rt6_info *rt = (struct rt6_info *) dst;
+
+	if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
+		return &rt->rt6i_gateway;
+	else
+		return &ipv6_hdr(skb)->daddr;
+}
+
 static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv)
 {
 	*flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index fec4ac41e946..1e50aa0297a3 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1694,8 +1694,8 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
 
 		if (skb->protocol == htons(ETH_P_AF_IUCV)) {
 			l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
-			l3_hdr->next_hop.ipv6_addr.s6_addr16[0] = htons(0xfe80);
-			memcpy(&l3_hdr->next_hop.ipv6_addr.s6_addr32[2],
+			l3_hdr->next_hop.addr.s6_addr16[0] = htons(0xfe80);
+			memcpy(&l3_hdr->next_hop.addr.s6_addr32[2],
 			       iucv_trans_hdr(skb)->destUserID, 8);
 			return;
 		}
@@ -1729,18 +1729,10 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
 	l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type);
 
 	if (ipv == 4) {
-		struct rtable *rt = (struct rtable *) dst;
-
-		*((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
-				rt_nexthop(rt, ip_hdr(skb)->daddr) :
-				ip_hdr(skb)->daddr;
+		l3_hdr->next_hop.addr.s6_addr32[3] =
+					qeth_next_hop_v4_rcu(skb, dst);
 	} else if (ipv == 6) {
-		struct rt6_info *rt = (struct rt6_info *) dst;
-
-		if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
-			l3_hdr->next_hop.ipv6_addr = rt->rt6i_gateway;
-		else
-			l3_hdr->next_hop.ipv6_addr = ipv6_hdr(skb)->daddr;
+		l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, dst);
 
 		hdr->hdr.l3.flags |= QETH_HDR_IPV6;
 		if (!IS_IQD(card))
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 05/11] s390/qeth: don't use restricted offloads for local traffic
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (3 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 04/11] s390/qeth: extract helpers for next-hop lookup Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 06/11] s390/qeth: merge TX skb mapping code Julian Wiedmann
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

Current OSA models don't support TSO for traffic to local next-hops, and
some old models didn't offer TX CSO for such packets either.

So as part of .ndo_features_check, check if a packet's next-hop resides
on the same OSA Adapter. Opt out from affected HW offloads accordingly.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core_main.c | 84 +++++++++++++++++++++++++++++--
 drivers/s390/net/qeth_l2_main.c   |  1 +
 2 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 771282cb7aef..1f18b38047a0 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -806,6 +806,58 @@ static void qeth_del_local_addrs6(struct qeth_card *card,
 	spin_unlock(&card->local_addrs6_lock);
 }
 
+static bool qeth_next_hop_is_local_v4(struct qeth_card *card,
+				      struct sk_buff *skb)
+{
+	struct qeth_local_addr *tmp;
+	bool is_local = false;
+	unsigned int key;
+	__be32 next_hop;
+
+	if (hash_empty(card->local_addrs4))
+		return false;
+
+	rcu_read_lock();
+	next_hop = qeth_next_hop_v4_rcu(skb, qeth_dst_check_rcu(skb, 4));
+	key = ipv4_addr_hash(next_hop);
+
+	hash_for_each_possible_rcu(card->local_addrs4, tmp, hnode, key) {
+		if (tmp->addr.s6_addr32[3] == next_hop) {
+			is_local = true;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	return is_local;
+}
+
+static bool qeth_next_hop_is_local_v6(struct qeth_card *card,
+				      struct sk_buff *skb)
+{
+	struct qeth_local_addr *tmp;
+	struct in6_addr *next_hop;
+	bool is_local = false;
+	u32 key;
+
+	if (hash_empty(card->local_addrs6))
+		return false;
+
+	rcu_read_lock();
+	next_hop = qeth_next_hop_v6_rcu(skb, qeth_dst_check_rcu(skb, 6));
+	key = ipv6_addr_hash(next_hop);
+
+	hash_for_each_possible_rcu(card->local_addrs6, tmp, hnode, key) {
+		if (ipv6_addr_equal(&tmp->addr, next_hop)) {
+			is_local = true;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	return is_local;
+}
+
 static int qeth_debugfs_local_addr_show(struct seq_file *m, void *v)
 {
 	struct qeth_card *card = m->private;
@@ -6578,10 +6630,6 @@ static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
 	if (lp2lp)
 		*lp2lp = qeth_ipa_caps_enabled(&caps, QETH_IPA_CHECKSUM_LP2LP);
 
-	if (lp2lp && !*lp2lp)
-		dev_warn(&card->gdev->dev,
-			 "Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n",
-			 QETH_CARD_IFNAME(card));
 	return 0;
 }
 
@@ -6816,6 +6864,34 @@ netdev_features_t qeth_features_check(struct sk_buff *skb,
 				      struct net_device *dev,
 				      netdev_features_t features)
 {
+	/* Traffic with local next-hop is not eligible for some offloads: */
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		struct qeth_card *card = dev->ml_priv;
+		netdev_features_t restricted = 0;
+
+		if (skb_is_gso(skb) && !netif_needs_gso(skb, features))
+			restricted |= NETIF_F_ALL_TSO;
+
+		switch (vlan_get_protocol(skb)) {
+		case htons(ETH_P_IP):
+			if (!card->info.has_lp2lp_cso_v4)
+				restricted |= NETIF_F_IP_CSUM;
+
+			if (restricted && qeth_next_hop_is_local_v4(card, skb))
+				features &= ~restricted;
+			break;
+		case htons(ETH_P_IPV6):
+			if (!card->info.has_lp2lp_cso_v6)
+				restricted |= NETIF_F_IPV6_CSUM;
+
+			if (restricted && qeth_next_hop_is_local_v6(card, skb))
+				features &= ~restricted;
+			break;
+		default:
+			break;
+		}
+	}
+
 	/* GSO segmentation builds skbs with
 	 *	a (small) linear part for the headers, and
 	 *	page frags for the data.
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 47f624b37040..da47e423e1b1 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -710,6 +710,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
 
 	if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
 		card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
+		netif_keep_dst(card->dev);
 		netif_set_gso_max_size(card->dev,
 				       PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
 	}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 06/11] s390/qeth: merge TX skb mapping code
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (4 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 05/11] s390/qeth: don't use restricted offloads for local traffic Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 07/11] s390/qeth: indicate contiguous TX buffer elements Julian Wiedmann
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

Merge the __qeth_fill_buffer() helper into its only caller. This way all
mapping-related context is in one place, and we can make some more use
of it in a subsequent patch.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core_main.c | 64 +++++++++++++------------------
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 1f18b38047a0..9c9a6edb5384 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -4081,15 +4081,39 @@ static bool qeth_iqd_may_bulk(struct qeth_qdio_out_q *queue,
 	       qeth_l3_iqd_same_vlan(&prev_hdr->hdr.l3, &curr_hdr->hdr.l3);
 }
 
-static unsigned int __qeth_fill_buffer(struct sk_buff *skb,
-				       struct qeth_qdio_out_buffer *buf,
-				       bool is_first_elem, unsigned int offset)
+/**
+ * qeth_fill_buffer() - map skb into an output buffer
+ * @buf:	buffer to transport the skb
+ * @skb:	skb to map into the buffer
+ * @hdr:	qeth_hdr for this skb. Either at skb->data, or allocated
+ *		from qeth_core_header_cache.
+ * @offset:	when mapping the skb, start at skb->data + offset
+ * @hd_len:	if > 0, build a dedicated header element of this size
+ */
+static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
+				     struct sk_buff *skb, struct qeth_hdr *hdr,
+				     unsigned int offset, unsigned int hd_len)
 {
 	struct qdio_buffer *buffer = buf->buffer;
 	int element = buf->next_element_to_fill;
 	int length = skb_headlen(skb) - offset;
 	char *data = skb->data + offset;
 	unsigned int elem_length, cnt;
+	bool is_first_elem = true;
+
+	__skb_queue_tail(&buf->skb_list, skb);
+
+	/* build dedicated element for HW Header */
+	if (hd_len) {
+		is_first_elem = false;
+
+		buffer->element[element].addr = virt_to_phys(hdr);
+		buffer->element[element].length = hd_len;
+		buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
+		/* remember to free cache-allocated HW header: */
+		buf->is_header[element] = ((void *)hdr != skb->data);
+		element++;
+	}
 
 	/* map linear part into buffer element(s) */
 	while (length > 0) {
@@ -4143,40 +4167,6 @@ static unsigned int __qeth_fill_buffer(struct sk_buff *skb,
 	return element;
 }
 
-/**
- * qeth_fill_buffer() - map skb into an output buffer
- * @buf:	buffer to transport the skb
- * @skb:	skb to map into the buffer
- * @hdr:	qeth_hdr for this skb. Either at skb->data, or allocated
- *		from qeth_core_header_cache.
- * @offset:	when mapping the skb, start at skb->data + offset
- * @hd_len:	if > 0, build a dedicated header element of this size
- */
-static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
-				     struct sk_buff *skb, struct qeth_hdr *hdr,
-				     unsigned int offset, unsigned int hd_len)
-{
-	struct qdio_buffer *buffer = buf->buffer;
-	bool is_first_elem = true;
-
-	__skb_queue_tail(&buf->skb_list, skb);
-
-	/* build dedicated header element */
-	if (hd_len) {
-		int element = buf->next_element_to_fill;
-		is_first_elem = false;
-
-		buffer->element[element].addr = virt_to_phys(hdr);
-		buffer->element[element].length = hd_len;
-		buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
-		/* remember to free cache-allocated qeth_hdr: */
-		buf->is_header[element] = ((void *)hdr != skb->data);
-		buf->next_element_to_fill++;
-	}
-
-	return __qeth_fill_buffer(skb, buf, is_first_elem, offset);
-}
-
 static int __qeth_xmit(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 		       struct sk_buff *skb, unsigned int elements,
 		       struct qeth_hdr *hdr, unsigned int offset,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 07/11] s390/qeth: indicate contiguous TX buffer elements
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (5 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 06/11] s390/qeth: merge TX skb mapping code Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 08/11] s390/qeth: set TX IRQ marker on last buffer in a group Julian Wiedmann
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

The TX path usually maps the full content of a page into a buffer
element. But there's specific skb layouts (ie. linearized TSO skbs)
where the HW header (1) requires a separate buffer element, and (2) is
page-contiguous with the packet data that's mapped into the next buffer
element.
Flag such buffer elements accordingly, so that HW can optimize its data
access for them.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core_main.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 9c9a6edb5384..4d1d053eebb7 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -4110,8 +4110,16 @@ static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf,
 		buffer->element[element].addr = virt_to_phys(hdr);
 		buffer->element[element].length = hd_len;
 		buffer->element[element].eflags = SBAL_EFLAGS_FIRST_FRAG;
-		/* remember to free cache-allocated HW header: */
-		buf->is_header[element] = ((void *)hdr != skb->data);
+
+		/* HW header is allocated from cache: */
+		if ((void *)hdr != skb->data)
+			buf->is_header[element] = 1;
+		/* HW header was pushed and is contiguous with linear part: */
+		else if (length > 0 && !PAGE_ALIGNED(data) &&
+			 (data == (char *)hdr + hd_len))
+			buffer->element[element].eflags |=
+				SBAL_EFLAGS_CONTIGUOUS;
+
 		element++;
 	}
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 08/11] s390/qeth: set TX IRQ marker on last buffer in a group
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (6 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 07/11] s390/qeth: indicate contiguous TX buffer elements Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 09/11] s390/qeth: return error when starting a reset fails Julian Wiedmann
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

When qeth_flush_buffers() gets called for a group of TX buffers
(currently up to 2 for OSA-style devices), the code iterates over each
buffer for some final processing.

During this processing, it sets the TX IRQ marker on the leading buffer
rather than the last one. This can result in delayed TX completion of
the trailing buffers. So pull the IRQ marker code out of the loop, and
apply it to the final buffer.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/qeth_core_main.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 4d1d053eebb7..164cc7f377fc 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -3617,11 +3617,11 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
 static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
 			       int count)
 {
+	struct qeth_qdio_out_buffer *buf = queue->bufs[index];
+	unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
 	struct qeth_card *card = queue->card;
-	struct qeth_qdio_out_buffer *buf;
 	int rc;
 	int i;
-	unsigned int qdio_flags;
 
 	for (i = index; i < index + count; ++i) {
 		unsigned int bidx = QDIO_BUFNR(i);
@@ -3638,9 +3638,10 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
 		if (IS_IQD(card)) {
 			skb_queue_walk(&buf->skb_list, skb)
 				skb_tx_timestamp(skb);
-			continue;
 		}
+	}
 
+	if (!IS_IQD(card)) {
 		if (!queue->do_pack) {
 			if ((atomic_read(&queue->used_buffers) >=
 				(QETH_HIGH_WATERMARK_PACK -
@@ -3665,12 +3666,12 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
 				buf->buffer->element[0].sflags |= SBAL_SFLAGS0_PCI_REQ;
 			}
 		}
+
+		if (atomic_read(&queue->set_pci_flags_count))
+			qdio_flags |= QDIO_FLAG_PCI_OUT;
 	}
 
 	QETH_TXQ_STAT_INC(queue, doorbell);
-	qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
-	if (atomic_read(&queue->set_pci_flags_count))
-		qdio_flags |= QDIO_FLAG_PCI_OUT;
 	rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
 		     queue->queue_no, index, count);
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 09/11] s390/qeth: return error when starting a reset fails
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (7 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 08/11] s390/qeth: set TX IRQ marker on last buffer in a group Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 10/11] s390/qeth: allow reset via ethtool Julian Wiedmann
  2020-05-05 16:25 ` [PATCH net-next 11/11] s390/qeth: clean up Kconfig help text Julian Wiedmann
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

When starting the reset worker via sysfs is unsuccessful, return an
error to the user.
Modernize the sysfs input parsing while at it.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
---
 drivers/s390/net/qeth_core.h      |  2 +-
 drivers/s390/net/qeth_core_main.c | 26 +++++++++++++++++---------
 drivers/s390/net/qeth_core_sys.c  | 15 +++++++++------
 3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 6b0d37d2c638..51ea56b73a97 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -1053,7 +1053,7 @@ struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card,
 void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
 void qeth_put_cmd(struct qeth_cmd_buffer *iob);
 
-void qeth_schedule_recovery(struct qeth_card *);
+int qeth_schedule_recovery(struct qeth_card *card);
 void qeth_flush_local_addrs(struct qeth_card *card);
 int qeth_poll(struct napi_struct *napi, int budget);
 void qeth_clear_ipacmd_list(struct qeth_card *);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 164cc7f377fc..c0ab6e7bc129 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1131,16 +1131,18 @@ static int qeth_set_thread_start_bit(struct qeth_card *card,
 		unsigned long thread)
 {
 	unsigned long flags;
+	int rc = 0;
 
 	spin_lock_irqsave(&card->thread_mask_lock, flags);
-	if (!(card->thread_allowed_mask & thread) ||
-	      (card->thread_start_mask & thread)) {
-		spin_unlock_irqrestore(&card->thread_mask_lock, flags);
-		return -EPERM;
-	}
-	card->thread_start_mask |= thread;
+	if (!(card->thread_allowed_mask & thread))
+		rc = -EPERM;
+	else if (card->thread_start_mask & thread)
+		rc = -EBUSY;
+	else
+		card->thread_start_mask |= thread;
 	spin_unlock_irqrestore(&card->thread_mask_lock, flags);
-	return 0;
+
+	return rc;
 }
 
 static void qeth_clear_thread_start_bit(struct qeth_card *card,
@@ -1193,11 +1195,17 @@ static int qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
 	return rc;
 }
 
-void qeth_schedule_recovery(struct qeth_card *card)
+int qeth_schedule_recovery(struct qeth_card *card)
 {
+	int rc;
+
 	QETH_CARD_TEXT(card, 2, "startrec");
-	if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)
+
+	rc = qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD);
+	if (!rc)
 		schedule_work(&card->kernel_thread_starter);
+
+	return rc;
 }
 
 static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev,
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index d7e429f6631e..c901c942fed7 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -275,17 +275,20 @@ static ssize_t qeth_dev_recover_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct qeth_card *card = dev_get_drvdata(dev);
-	char *tmp;
-	int i;
+	bool reset;
+	int rc;
+
+	rc = kstrtobool(buf, &reset);
+	if (rc)
+		return rc;
 
 	if (!qeth_card_hw_is_reachable(card))
 		return -EPERM;
 
-	i = simple_strtoul(buf, &tmp, 16);
-	if (i == 1)
-		qeth_schedule_recovery(card);
+	if (reset)
+		rc = qeth_schedule_recovery(card);
 
-	return count;
+	return rc ? rc : count;
 }
 
 static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (8 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 09/11] s390/qeth: return error when starting a reset fails Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  2020-05-05 17:21   ` Jakub Kicinski
  2020-05-05 16:25 ` [PATCH net-next 11/11] s390/qeth: clean up Kconfig help text Julian Wiedmann
  10 siblings, 1 reply; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

Implement the .reset callback. Only a full reset is supported.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
---
 drivers/s390/net/qeth_ethtool.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
index ebdc03210608..0d12002d0615 100644
--- a/drivers/s390/net/qeth_ethtool.c
+++ b/drivers/s390/net/qeth_ethtool.c
@@ -193,6 +193,21 @@ static void qeth_get_drvinfo(struct net_device *dev,
 		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
 }
 
+static int qeth_reset(struct net_device *dev, u32 *flags)
+{
+	struct qeth_card *card = dev->ml_priv;
+	int rc;
+
+	if (*flags != ETH_RESET_ALL)
+		return -EINVAL;
+
+	rc = qeth_schedule_recovery(card);
+	if (!rc)
+		*flags = 0;
+
+	return rc;
+}
+
 static void qeth_get_channels(struct net_device *dev,
 			      struct ethtool_channels *channels)
 {
@@ -522,6 +537,7 @@ const struct ethtool_ops qeth_ethtool_ops = {
 	.get_ethtool_stats = qeth_get_ethtool_stats,
 	.get_sset_count = qeth_get_sset_count,
 	.get_drvinfo = qeth_get_drvinfo,
+	.reset = qeth_reset,
 	.get_channels = qeth_get_channels,
 	.set_channels = qeth_set_channels,
 	.get_ts_info = qeth_get_ts_info,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH net-next 11/11] s390/qeth: clean up Kconfig help text
  2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
                   ` (9 preceding siblings ...)
  2020-05-05 16:25 ` [PATCH net-next 10/11] s390/qeth: allow reset via ethtool Julian Wiedmann
@ 2020-05-05 16:25 ` Julian Wiedmann
  10 siblings, 0 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 16:25 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, linux-s390, Heiko Carstens, Ursula Braun, Julian Wiedmann

Remove a stale doc link. While at it also reword the help text to get
rid of an outdated marketing term.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
---
 drivers/s390/net/Kconfig | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 3850a0f5f0bc..53120e68796e 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -63,12 +63,9 @@ config QETH
 	prompt "Gigabit Ethernet device support"
 	depends on CCW && NETDEVICES && IP_MULTICAST && QDIO && ETHERNET
 	help
-	  This driver supports the IBM System z OSA Express adapters
-	  in QDIO mode (all media types), HiperSockets interfaces and z/VM
-	  virtual NICs for Guest LAN and VSWITCH.
-	
-	  For details please refer to the documentation provided by IBM at
-	  <http://www.ibm.com/developerworks/linux/linux390>
+	  This driver supports IBM's OSA Express network adapters in QDIO mode,
+	  HiperSockets interfaces and z/VM virtual NICs for Guest LAN and
+	  VSWITCH.
 
 	  To compile this driver as a module, choose M.
 	  The module name is qeth.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 16:25 ` [PATCH net-next 10/11] s390/qeth: allow reset via ethtool Julian Wiedmann
@ 2020-05-05 17:21   ` Jakub Kicinski
  2020-05-05 18:23     ` Julian Wiedmann
  0 siblings, 1 reply; 20+ messages in thread
From: Jakub Kicinski @ 2020-05-05 17:21 UTC (permalink / raw)
  To: Julian Wiedmann
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On Tue,  5 May 2020 18:25:58 +0200 Julian Wiedmann wrote:
> Implement the .reset callback. Only a full reset is supported.
> 
> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
> ---
>  drivers/s390/net/qeth_ethtool.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
> index ebdc03210608..0d12002d0615 100644
> --- a/drivers/s390/net/qeth_ethtool.c
> +++ b/drivers/s390/net/qeth_ethtool.c
> @@ -193,6 +193,21 @@ static void qeth_get_drvinfo(struct net_device *dev,
>  		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
>  }
>  
> +static int qeth_reset(struct net_device *dev, u32 *flags)
> +{
> +	struct qeth_card *card = dev->ml_priv;
> +	int rc;
> +
> +	if (*flags != ETH_RESET_ALL)
> +		return -EINVAL;
> +
> +	rc = qeth_schedule_recovery(card);
> +	if (!rc)
> +		*flags = 0;

I think it's better if you only clear the flags for things you actually
reset. See the commit message for 7a13240e3718 ("bnxt_en: fix
ethtool_reset_flags ABI violations").

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 17:21   ` Jakub Kicinski
@ 2020-05-05 18:23     ` Julian Wiedmann
  2020-05-05 18:29       ` Jakub Kicinski
  0 siblings, 1 reply; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 18:23 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On 05.05.20 19:21, Jakub Kicinski wrote:
> On Tue,  5 May 2020 18:25:58 +0200 Julian Wiedmann wrote:
>> Implement the .reset callback. Only a full reset is supported.
>>
>> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
>> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
>> ---
>>  drivers/s390/net/qeth_ethtool.c | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
>> index ebdc03210608..0d12002d0615 100644
>> --- a/drivers/s390/net/qeth_ethtool.c
>> +++ b/drivers/s390/net/qeth_ethtool.c
>> @@ -193,6 +193,21 @@ static void qeth_get_drvinfo(struct net_device *dev,
>>  		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
>>  }
>>  
>> +static int qeth_reset(struct net_device *dev, u32 *flags)
>> +{
>> +	struct qeth_card *card = dev->ml_priv;
>> +	int rc;
>> +
>> +	if (*flags != ETH_RESET_ALL)
>> +		return -EINVAL;
>> +
>> +	rc = qeth_schedule_recovery(card);
>> +	if (!rc)
>> +		*flags = 0;
> 
> I think it's better if you only clear the flags for things you actually
> reset. See the commit message for 7a13240e3718 ("bnxt_en: fix
> ethtool_reset_flags ABI violations").
> 

Not sure I understand - you mean *flags &= ~ETH_RESET_ALL ?

Since we're effectively managing a virtual device, those individual
ETH_RESET_* flags just don't map very well...
This _is_ a full-blown reset, I don't see how we could provide any finer
granularity.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 18:23     ` Julian Wiedmann
@ 2020-05-05 18:29       ` Jakub Kicinski
  2020-05-05 19:57         ` Julian Wiedmann
  0 siblings, 1 reply; 20+ messages in thread
From: Jakub Kicinski @ 2020-05-05 18:29 UTC (permalink / raw)
  To: Julian Wiedmann
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On Tue, 5 May 2020 20:23:31 +0200 Julian Wiedmann wrote:
> On 05.05.20 19:21, Jakub Kicinski wrote:
> > On Tue,  5 May 2020 18:25:58 +0200 Julian Wiedmann wrote:  
> >> Implement the .reset callback. Only a full reset is supported.
> >>
> >> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
> >> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
> >> ---
> >>  drivers/s390/net/qeth_ethtool.c | 16 ++++++++++++++++
> >>  1 file changed, 16 insertions(+)
> >>
> >> diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
> >> index ebdc03210608..0d12002d0615 100644
> >> --- a/drivers/s390/net/qeth_ethtool.c
> >> +++ b/drivers/s390/net/qeth_ethtool.c
> >> @@ -193,6 +193,21 @@ static void qeth_get_drvinfo(struct net_device *dev,
> >>  		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
> >>  }
> >>  
> >> +static int qeth_reset(struct net_device *dev, u32 *flags)
> >> +{
> >> +	struct qeth_card *card = dev->ml_priv;
> >> +	int rc;
> >> +
> >> +	if (*flags != ETH_RESET_ALL)
> >> +		return -EINVAL;
> >> +
> >> +	rc = qeth_schedule_recovery(card);
> >> +	if (!rc)
> >> +		*flags = 0;  
> > 
> > I think it's better if you only clear the flags for things you actually
> > reset. See the commit message for 7a13240e3718 ("bnxt_en: fix
> > ethtool_reset_flags ABI violations").
> >   
> 
> Not sure I understand - you mean *flags &= ~ETH_RESET_ALL ?
> 
> Since we're effectively managing a virtual device, those individual
> ETH_RESET_* flags just don't map very well...
> This _is_ a full-blown reset, I don't see how we could provide any finer
> granularity.

This is the comment from the uAPI header:

/* The reset() operation must clear the flags for the components which
 * were actually reset.  On successful return, the flags indicate the
 * components which were not reset, either because they do not exist
 * in the hardware or because they cannot be reset independently.  The
 * driver must never reset any components that were not requested.
 */

Now let's take ETH_RESET_PHY as an example. Surely you're not resetting
any PHY here, so that bit should not be cleared. Please look at the
bits and select the ones which make sense, add whatever is missing.

Then my suggestion would be something like:

  #define QETH_RESET_FLAGS (flag | flag | flag)

  if ((*flags & QETH_RESET_FLAGS) != QETH_RESET_FLAGS))
	return -EINVAL;
  ...
  *flags &= ~QETH_RESET_FLAGS;

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 18:29       ` Jakub Kicinski
@ 2020-05-05 19:57         ` Julian Wiedmann
  2020-05-05 20:09           ` Edwin Peer
  2020-05-05 21:28           ` Jakub Kicinski
  0 siblings, 2 replies; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-05 19:57 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On 05.05.20 20:29, Jakub Kicinski wrote:
> On Tue, 5 May 2020 20:23:31 +0200 Julian Wiedmann wrote:
>> On 05.05.20 19:21, Jakub Kicinski wrote:
>>> On Tue,  5 May 2020 18:25:58 +0200 Julian Wiedmann wrote:  
>>>> Implement the .reset callback. Only a full reset is supported.
>>>>
>>>> Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
>>>> Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
>>>> ---
>>>>  drivers/s390/net/qeth_ethtool.c | 16 ++++++++++++++++
>>>>  1 file changed, 16 insertions(+)
>>>>
>>>> diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
>>>> index ebdc03210608..0d12002d0615 100644
>>>> --- a/drivers/s390/net/qeth_ethtool.c
>>>> +++ b/drivers/s390/net/qeth_ethtool.c
>>>> @@ -193,6 +193,21 @@ static void qeth_get_drvinfo(struct net_device *dev,
>>>>  		 CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
>>>>  }
>>>>  
>>>> +static int qeth_reset(struct net_device *dev, u32 *flags)
>>>> +{
>>>> +	struct qeth_card *card = dev->ml_priv;
>>>> +	int rc;
>>>> +
>>>> +	if (*flags != ETH_RESET_ALL)
>>>> +		return -EINVAL;
>>>> +
>>>> +	rc = qeth_schedule_recovery(card);
>>>> +	if (!rc)
>>>> +		*flags = 0;  
>>>
>>> I think it's better if you only clear the flags for things you actually
>>> reset. See the commit message for 7a13240e3718 ("bnxt_en: fix
>>> ethtool_reset_flags ABI violations").
>>>   
>>
>> Not sure I understand - you mean *flags &= ~ETH_RESET_ALL ?
>>
>> Since we're effectively managing a virtual device, those individual
>> ETH_RESET_* flags just don't map very well...
>> This _is_ a full-blown reset, I don't see how we could provide any finer
>> granularity.
> 
> This is the comment from the uAPI header:
> 
> /* The reset() operation must clear the flags for the components which
>  * were actually reset.  On successful return, the flags indicate the
>  * components which were not reset, either because they do not exist
>  * in the hardware or because they cannot be reset independently.  The
>  * driver must never reset any components that were not requested.
>  */
> 
> Now let's take ETH_RESET_PHY as an example. Surely you're not resetting
> any PHY here, so that bit should not be cleared. Please look at the
> bits and select the ones which make sense, add whatever is missing.
> 

It's a virtual device, _none_ of them make much sense?! We better not be
resetting any actual HW components, the other interfaces on the same
adapter would be quite unhappy about that.

Sorry for being dense, and I appreciate that the API leaves a lot of room
for sophisticated partial resets where the driver/HW allows it.
But it sounds like what you're suggesting is
(1) we select a rather arbitrary set of components that _might_ represent a
    full "virtual" reset, and then
(2) expect the user to guess a super-set of these features. And not worry
    when they selected too much, and this obscure PHY thing failed to reset.

So I looked at gve's implementation and thought "yep, looks simple enough".
But if we start asking users to interpret HW bits that hardly make any
sense to them, we're worse off than with the existing custom sysfs trigger...

> Then my suggestion would be something like:
> 
>   #define QETH_RESET_FLAGS (flag | flag | flag)
> 
>   if ((*flags & QETH_RESET_FLAGS) != QETH_RESET_FLAGS))
> 	return -EINVAL;
>   ...
>   *flags &= ~QETH_RESET_FLAGS;
> 


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 19:57         ` Julian Wiedmann
@ 2020-05-05 20:09           ` Edwin Peer
  2020-05-05 21:28           ` Jakub Kicinski
  1 sibling, 0 replies; 20+ messages in thread
From: Edwin Peer @ 2020-05-05 20:09 UTC (permalink / raw)
  To: Julian Wiedmann
  Cc: Jakub Kicinski, David Miller, netdev, linux-s390, Heiko Carstens,
	Ursula Braun

On Tue, May 5, 2020 at 12:57 PM Julian Wiedmann <jwi@linux.ibm.com> wrote:

> It's a virtual device, _none_ of them make much sense?!

Why not introduce a new reset bit that captures the semantics of
whatever qeth_schedule_recovery does?

Regards,
Edwin Peer

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 19:57         ` Julian Wiedmann
  2020-05-05 20:09           ` Edwin Peer
@ 2020-05-05 21:28           ` Jakub Kicinski
  2020-05-06  7:56             ` Julian Wiedmann
  1 sibling, 1 reply; 20+ messages in thread
From: Jakub Kicinski @ 2020-05-05 21:28 UTC (permalink / raw)
  To: Julian Wiedmann
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On Tue, 5 May 2020 21:57:43 +0200 Julian Wiedmann wrote:
> > This is the comment from the uAPI header:
> > 
> > /* The reset() operation must clear the flags for the components which
> >  * were actually reset.  On successful return, the flags indicate the
> >  * components which were not reset, either because they do not exist
> >  * in the hardware or because they cannot be reset independently.  The
> >  * driver must never reset any components that were not requested.
> >  */
> > 
> > Now let's take ETH_RESET_PHY as an example. Surely you're not resetting
> > any PHY here, so that bit should not be cleared. Please look at the
> > bits and select the ones which make sense, add whatever is missing.
> >   
> 
> It's a virtual device, _none_ of them make much sense?! We better not be
> resetting any actual HW components, the other interfaces on the same
> adapter would be quite unhappy about that.

Well, then, you can't use the API in its current form. You can't say
none of the sub-options are applicable, but the sum of them does.

> Sorry for being dense, and I appreciate that the API leaves a lot of room
> for sophisticated partial resets where the driver/HW allows it.
> But it sounds like what you're suggesting is
> (1) we select a rather arbitrary set of components that _might_ represent a
>     full "virtual" reset, and then
> (2) expect the user to guess a super-set of these features. And not worry
>     when they selected too much, and this obscure PHY thing failed to reset.

No, please see the code I provided below, and read how the interface 
is supposed to work. I posted the code comment in my previous reply. 
I don't know what else I can do for you.

User can still pass "all" but you can't _clear_ all bits, 'cause you
didn't reset any PHY, MAC, etc.

> So I looked at gve's implementation and thought "yep, looks simple enough".

Ugh, yeah, gve is not a good example.

> But if we start asking users to interpret HW bits that hardly make any
> sense to them, we're worse off than with the existing custom sysfs trigger...

Actually - operationally, how do you expect people to use this reset?
Some user space system detects the NIC is in a bad state? Does the
interface communicate that via some log messages or such?

The commit message doesn't really explain the "why".

> > Then my suggestion would be something like:
> > 
> >   #define QETH_RESET_FLAGS (flag | flag | flag)
> > 
> >   if ((*flags & QETH_RESET_FLAGS) != QETH_RESET_FLAGS))
> > 	return -EINVAL;
> >   ...
> >   *flags &= ~QETH_RESET_FLAGS;

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-05 21:28           ` Jakub Kicinski
@ 2020-05-06  7:56             ` Julian Wiedmann
  2020-05-06 19:09               ` Jakub Kicinski
  0 siblings, 1 reply; 20+ messages in thread
From: Julian Wiedmann @ 2020-05-06  7:56 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun

On 05.05.20 23:28, Jakub Kicinski wrote:
> On Tue, 5 May 2020 21:57:43 +0200 Julian Wiedmann wrote:
>>> This is the comment from the uAPI header:
>>>
>>> /* The reset() operation must clear the flags for the components which
>>>  * were actually reset.  On successful return, the flags indicate the
>>>  * components which were not reset, either because they do not exist
>>>  * in the hardware or because they cannot be reset independently.  The
>>>  * driver must never reset any components that were not requested.
>>>  */
>>>
>>> Now let's take ETH_RESET_PHY as an example. Surely you're not resetting
>>> any PHY here, so that bit should not be cleared. Please look at the
>>> bits and select the ones which make sense, add whatever is missing.
>>>   
>>
>> It's a virtual device, _none_ of them make much sense?! We better not be
>> resetting any actual HW components, the other interfaces on the same
>> adapter would be quite unhappy about that.
> 
> Well, then, you can't use the API in its current form. You can't say
> none of the sub-options are applicable, but the sum of them does.
> 

Agreed, that's my take as well. So we'll basically need a ETH_RESET_FULL bit,
for devices that don't fit into the fine-grained component model.

>> Sorry for being dense, and I appreciate that the API leaves a lot of room
>> for sophisticated partial resets where the driver/HW allows it.
>> But it sounds like what you're suggesting is
>> (1) we select a rather arbitrary set of components that _might_ represent a
>>     full "virtual" reset, and then
>> (2) expect the user to guess a super-set of these features. And not worry
>>     when they selected too much, and this obscure PHY thing failed to reset.
> 
> No, please see the code I provided below, and read how the interface 
> is supposed to work. I posted the code comment in my previous reply. 
> I don't know what else I can do for you.
> 
> User can still pass "all" but you can't _clear_ all bits, 'cause you
> didn't reset any PHY, MAC, etc.
> 
>> So I looked at gve's implementation and thought "yep, looks simple enough".
> 
> Ugh, yeah, gve is not a good example.
> 
>> But if we start asking users to interpret HW bits that hardly make any
>> sense to them, we're worse off than with the existing custom sysfs trigger...
> 
> Actually - operationally, how do you expect people to use this reset?
> Some user space system detects the NIC is in a bad state? Does the
> interface communicate that via some log messages or such?
> 
> The commit message doesn't really explain the "why".
> 

Usually the driver will detect a hung condition itself, and trigger an
automatic reset internally (eg. from the TX watchdog).
But if that doesn't work, you'll hopefully get enough noisy log warnings
to investigate & reset the interface manually.
Besides that, it's just an easy way to exercise/test the reset code.

Integration with a daemon / management layer definitely sounds like an
option, and I'd much rather point those people towards ethtool instead
of sysfs.

>>> Then my suggestion would be something like:
>>>
>>>   #define QETH_RESET_FLAGS (flag | flag | flag)
>>>
>>>   if ((*flags & QETH_RESET_FLAGS) != QETH_RESET_FLAGS))
>>> 	return -EINVAL;
>>>   ...
>>>   *flags &= ~QETH_RESET_FLAGS;


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH net-next 10/11] s390/qeth: allow reset via ethtool
  2020-05-06  7:56             ` Julian Wiedmann
@ 2020-05-06 19:09               ` Jakub Kicinski
  0 siblings, 0 replies; 20+ messages in thread
From: Jakub Kicinski @ 2020-05-06 19:09 UTC (permalink / raw)
  To: Julian Wiedmann
  Cc: David Miller, netdev, linux-s390, Heiko Carstens, Ursula Braun,
	Jiri Pirko

On Wed, 6 May 2020 09:56:41 +0200 Julian Wiedmann wrote:
> On 05.05.20 23:28, Jakub Kicinski wrote:
> > On Tue, 5 May 2020 21:57:43 +0200 Julian Wiedmann wrote:  
> >>> This is the comment from the uAPI header:
> >>>
> >>> /* The reset() operation must clear the flags for the components which
> >>>  * were actually reset.  On successful return, the flags indicate the
> >>>  * components which were not reset, either because they do not exist
> >>>  * in the hardware or because they cannot be reset independently.  The
> >>>  * driver must never reset any components that were not requested.
> >>>  */
> >>>
> >>> Now let's take ETH_RESET_PHY as an example. Surely you're not resetting
> >>> any PHY here, so that bit should not be cleared. Please look at the
> >>> bits and select the ones which make sense, add whatever is missing.
> >>>     
> >>
> >> It's a virtual device, _none_ of them make much sense?! We better not be
> >> resetting any actual HW components, the other interfaces on the same
> >> adapter would be quite unhappy about that.  
> > 
> > Well, then, you can't use the API in its current form. You can't say
> > none of the sub-options are applicable, but the sum of them does.
> 
> Agreed, that's my take as well. So we'll basically need a ETH_RESET_FULL bit,
> for devices that don't fit into the fine-grained component model.

I'd say you're barely re-opening all communication channels with the
device, without any loss of configuration, right? So perhaps
RESET_DRV_IFC? Not great but best I can come up with :S

> >> Sorry for being dense, and I appreciate that the API leaves a lot of room
> >> for sophisticated partial resets where the driver/HW allows it.
> >> But it sounds like what you're suggesting is
> >> (1) we select a rather arbitrary set of components that _might_ represent a
> >>     full "virtual" reset, and then
> >> (2) expect the user to guess a super-set of these features. And not worry
> >>     when they selected too much, and this obscure PHY thing failed to reset.  
> > 
> > No, please see the code I provided below, and read how the interface 
> > is supposed to work. I posted the code comment in my previous reply. 
> > I don't know what else I can do for you.
> > 
> > User can still pass "all" but you can't _clear_ all bits, 'cause you
> > didn't reset any PHY, MAC, etc.
> >   
> >> So I looked at gve's implementation and thought "yep, looks simple enough".  
> > 
> > Ugh, yeah, gve is not a good example.
> >   
> >> But if we start asking users to interpret HW bits that hardly make any
> >> sense to them, we're worse off than with the existing custom sysfs trigger...  
> > 
> > Actually - operationally, how do you expect people to use this reset?
> > Some user space system detects the NIC is in a bad state? Does the
> > interface communicate that via some log messages or such?
> > 
> > The commit message doesn't really explain the "why".
> >   
> 
> Usually the driver will detect a hung condition itself, and trigger an
> automatic reset internally (eg. from the TX watchdog).
> But if that doesn't work, you'll hopefully get enough noisy log warnings
> to investigate & reset the interface manually.
> Besides that, it's just an easy way to exercise/test the reset code.

Perhaps a better path would be using devlink health? There's currently
no way to force a recovery, but that's effectively what you're doing
here, right? We can extend the devlink API.

> Integration with a daemon / management layer definitely sounds like an
> option, and I'd much rather point those people towards ethtool instead
> of sysfs.
> 
> >>> Then my suggestion would be something like:
> >>>
> >>>   #define QETH_RESET_FLAGS (flag | flag | flag)
> >>>
> >>>   if ((*flags & QETH_RESET_FLAGS) != QETH_RESET_FLAGS))
> >>> 	return -EINVAL;
> >>>   ...
> >>>   *flags &= ~QETH_RESET_FLAGS;  

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2020-05-06 19:09 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-05 16:25 [PATCH net-next 00/11] s390/qeth: updates 2020-05-05 Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 01/11] s390/qeth: keep track of LP2LP capability for csum offload Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 02/11] s390/qeth: process local address events Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 03/11] s390/qeth: add debugfs file for local IP addresses Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 04/11] s390/qeth: extract helpers for next-hop lookup Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 05/11] s390/qeth: don't use restricted offloads for local traffic Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 06/11] s390/qeth: merge TX skb mapping code Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 07/11] s390/qeth: indicate contiguous TX buffer elements Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 08/11] s390/qeth: set TX IRQ marker on last buffer in a group Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 09/11] s390/qeth: return error when starting a reset fails Julian Wiedmann
2020-05-05 16:25 ` [PATCH net-next 10/11] s390/qeth: allow reset via ethtool Julian Wiedmann
2020-05-05 17:21   ` Jakub Kicinski
2020-05-05 18:23     ` Julian Wiedmann
2020-05-05 18:29       ` Jakub Kicinski
2020-05-05 19:57         ` Julian Wiedmann
2020-05-05 20:09           ` Edwin Peer
2020-05-05 21:28           ` Jakub Kicinski
2020-05-06  7:56             ` Julian Wiedmann
2020-05-06 19:09               ` Jakub Kicinski
2020-05-05 16:25 ` [PATCH net-next 11/11] s390/qeth: clean up Kconfig help text Julian Wiedmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.