Commit 77afd987 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2020-05-06

please apply the following patch series for qeth to netdev's net-next
tree.
Same patches as yesterday, except that the ethtool reset has been
dropped for now.

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.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2f864990 dc9c404f
...@@ -63,12 +63,9 @@ config QETH ...@@ -63,12 +63,9 @@ config QETH
prompt "Gigabit Ethernet device support" prompt "Gigabit Ethernet device support"
depends on CCW && NETDEVICES && IP_MULTICAST && QDIO && ETHERNET depends on CCW && NETDEVICES && IP_MULTICAST && QDIO && ETHERNET
help help
This driver supports the IBM System z OSA Express adapters This driver supports IBM's OSA Express network adapters in QDIO mode,
in QDIO mode (all media types), HiperSockets interfaces and z/VM HiperSockets interfaces and z/VM virtual NICs for Guest LAN and
virtual NICs for Guest LAN and VSWITCH. VSWITCH.
For details please refer to the documentation provided by IBM at
<http://www.ibm.com/developerworks/linux/linux390>
To compile this driver as a module, choose M. To compile this driver as a module, choose M.
The module name is qeth. The module name is qeth.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define __QETH_CORE_H__ #define __QETH_CORE_H__
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -21,8 +22,10 @@ ...@@ -21,8 +22,10 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/rcupdate.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/types.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -31,6 +34,7 @@ ...@@ -31,6 +34,7 @@
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/if_inet6.h> #include <net/if_inet6.h>
#include <net/addrconf.h> #include <net/addrconf.h>
#include <net/route.h>
#include <net/sch_generic.h> #include <net/sch_generic.h>
#include <net/tcp.h> #include <net/tcp.h>
...@@ -231,11 +235,7 @@ struct qeth_hdr_layer3 { ...@@ -231,11 +235,7 @@ struct qeth_hdr_layer3 {
__u16 frame_offset; __u16 frame_offset;
union { union {
/* TX: */ /* TX: */
struct in6_addr ipv6_addr; struct in6_addr addr;
struct ipv4 {
u8 res[12];
u32 addr;
} ipv4;
/* RX: */ /* RX: */
struct rx { struct rx {
u8 res1[2]; u8 res1[2];
...@@ -352,10 +352,15 @@ static inline bool qeth_l3_same_next_hop(struct qeth_hdr_layer3 *h1, ...@@ -352,10 +352,15 @@ static inline bool qeth_l3_same_next_hop(struct qeth_hdr_layer3 *h1,
struct qeth_hdr_layer3 *h2) struct qeth_hdr_layer3 *h2)
{ {
return !((h1->flags ^ h2->flags) & QETH_HDR_IPV6) && return !((h1->flags ^ h2->flags) & QETH_HDR_IPV6) &&
ipv6_addr_equal(&h1->next_hop.ipv6_addr, ipv6_addr_equal(&h1->next_hop.addr, &h2->next_hop.addr);
&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 { enum qeth_qdio_info_states {
QETH_QDIO_UNINITIALIZED, QETH_QDIO_UNINITIALIZED,
QETH_QDIO_ALLOCATED, QETH_QDIO_ALLOCATED,
...@@ -688,6 +693,9 @@ struct qeth_card_info { ...@@ -688,6 +693,9 @@ struct qeth_card_info {
u8 promisc_mode:1; u8 promisc_mode:1;
u8 use_v1_blkt:1; u8 use_v1_blkt:1;
u8 is_vm_nic: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_card_types type;
enum qeth_link_types link_type; enum qeth_link_types link_type;
int broadcast_capable; int broadcast_capable;
...@@ -786,6 +794,7 @@ struct qeth_card { ...@@ -786,6 +794,7 @@ struct qeth_card {
struct qeth_channel data; struct qeth_channel data;
struct net_device *dev; struct net_device *dev;
struct dentry *debugfs;
struct qeth_card_stats stats; struct qeth_card_stats stats;
struct qeth_card_info info; struct qeth_card_info info;
struct qeth_token token; struct qeth_token token;
...@@ -797,6 +806,10 @@ struct qeth_card { ...@@ -797,6 +806,10 @@ struct qeth_card {
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
DECLARE_HASHTABLE(mac_htable, 4); DECLARE_HASHTABLE(mac_htable, 4);
DECLARE_HASHTABLE(ip_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; struct mutex ip_lock;
DECLARE_HASHTABLE(ip_mc_htable, 4); DECLARE_HASHTABLE(ip_mc_htable, 4);
struct work_struct rx_mode_work; struct work_struct rx_mode_work;
...@@ -928,6 +941,25 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv) ...@@ -928,6 +941,25 @@ static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv)
return dst; 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) static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv)
{ {
*flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; *flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
...@@ -1021,7 +1053,8 @@ struct qeth_cmd_buffer *qeth_get_diag_cmd(struct qeth_card *card, ...@@ -1021,7 +1053,8 @@ 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_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
void qeth_put_cmd(struct qeth_cmd_buffer *iob); 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); int qeth_poll(struct napi_struct *napi, int budget);
void qeth_clear_ipacmd_list(struct qeth_card *); void qeth_clear_ipacmd_list(struct qeth_card *);
int qeth_qdio_clear_card(struct qeth_card *, int); int qeth_qdio_clear_card(struct qeth_card *, int);
......
This diff is collapsed.
...@@ -772,6 +772,29 @@ struct qeth_ipacmd_addr_change { ...@@ -772,6 +772,29 @@ struct qeth_ipacmd_addr_change {
struct qeth_ipacmd_addr_change_entry entry[]; struct qeth_ipacmd_addr_change_entry entry[];
} __packed; } __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 */ /* Header for each IPA command */
struct qeth_ipacmd_hdr { struct qeth_ipacmd_hdr {
__u8 command; __u8 command;
...@@ -803,6 +826,8 @@ struct qeth_ipa_cmd { ...@@ -803,6 +826,8 @@ struct qeth_ipa_cmd {
struct qeth_ipacmd_setbridgeport sbp; struct qeth_ipacmd_setbridgeport sbp;
struct qeth_ipacmd_addr_change addrchange; struct qeth_ipacmd_addr_change addrchange;
struct qeth_ipacmd_vnicc vnicc; struct qeth_ipacmd_vnicc vnicc;
struct qeth_ipacmd_local_addrs4 local_addrs4;
struct qeth_ipacmd_local_addrs6 local_addrs6;
} data; } data;
} __attribute__ ((packed)); } __attribute__ ((packed));
......
...@@ -275,17 +275,20 @@ static ssize_t qeth_dev_recover_store(struct device *dev, ...@@ -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 device_attribute *attr, const char *buf, size_t count)
{ {
struct qeth_card *card = dev_get_drvdata(dev); struct qeth_card *card = dev_get_drvdata(dev);
char *tmp; bool reset;
int i; int rc;
rc = kstrtobool(buf, &reset);
if (rc)
return rc;
if (!qeth_card_hw_is_reachable(card)) if (!qeth_card_hw_is_reachable(card))
return -EPERM; return -EPERM;
i = simple_strtoul(buf, &tmp, 16); if (reset)
if (i == 1) rc = qeth_schedule_recovery(card);
qeth_schedule_recovery(card);
return count; return rc ? rc : count;
} }
static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store); static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
......
...@@ -291,6 +291,7 @@ static void qeth_l2_stop_card(struct qeth_card *card) ...@@ -291,6 +291,7 @@ static void qeth_l2_stop_card(struct qeth_card *card)
qeth_qdio_clear_card(card, 0); qeth_qdio_clear_card(card, 0);
qeth_clear_working_pool_list(card); qeth_clear_working_pool_list(card);
flush_workqueue(card->event_wq); flush_workqueue(card->event_wq);
qeth_flush_local_addrs(card);
card->info.promisc_mode = 0; card->info.promisc_mode = 0;
} }
...@@ -709,6 +710,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) ...@@ -709,6 +710,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) { if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
card->dev->needed_headroom = sizeof(struct qeth_hdr_tso); card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
netif_keep_dst(card->dev);
netif_set_gso_max_size(card->dev, netif_set_gso_max_size(card->dev,
PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)); PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
} }
......
...@@ -1176,6 +1176,7 @@ static void qeth_l3_stop_card(struct qeth_card *card) ...@@ -1176,6 +1176,7 @@ static void qeth_l3_stop_card(struct qeth_card *card)
qeth_qdio_clear_card(card, 0); qeth_qdio_clear_card(card, 0);
qeth_clear_working_pool_list(card); qeth_clear_working_pool_list(card);
flush_workqueue(card->event_wq); flush_workqueue(card->event_wq);
qeth_flush_local_addrs(card);
card->info.promisc_mode = 0; card->info.promisc_mode = 0;
} }
...@@ -1693,8 +1694,8 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, ...@@ -1693,8 +1694,8 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
if (skb->protocol == htons(ETH_P_AF_IUCV)) { if (skb->protocol == htons(ETH_P_AF_IUCV)) {
l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST; l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
l3_hdr->next_hop.ipv6_addr.s6_addr16[0] = htons(0xfe80); l3_hdr->next_hop.addr.s6_addr16[0] = htons(0xfe80);
memcpy(&l3_hdr->next_hop.ipv6_addr.s6_addr32[2], memcpy(&l3_hdr->next_hop.addr.s6_addr32[2],
iucv_trans_hdr(skb)->destUserID, 8); iucv_trans_hdr(skb)->destUserID, 8);
return; return;
} }
...@@ -1728,18 +1729,10 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, ...@@ -1728,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); l3_hdr->flags |= qeth_l3_cast_type_to_flag(cast_type);
if (ipv == 4) { if (ipv == 4) {
struct rtable *rt = (struct rtable *) dst; l3_hdr->next_hop.addr.s6_addr32[3] =
qeth_next_hop_v4_rcu(skb, dst);
*((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
rt_nexthop(rt, ip_hdr(skb)->daddr) :
ip_hdr(skb)->daddr;
} else if (ipv == 6) { } else if (ipv == 6) {
struct rt6_info *rt = (struct rt6_info *) dst; l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, 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;
hdr->hdr.l3.flags |= QETH_HDR_IPV6; hdr->hdr.l3.flags |= QETH_HDR_IPV6;
if (!IS_IQD(card)) if (!IS_IQD(card))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment