Commit 14a6daf3 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 's390-qeth-updates-2021-01-28'

Julian Wiedmann says:

====================
s390/qeth: updates 2021-01-28

Nothing special, mostly fine-tuning and follow-on cleanups for earlier fixes.
====================

Link: https://lore.kernel.org/r/20210128112551.18780-1-jwi@linux.ibm.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 699e4bc8 d6e51503
...@@ -956,24 +956,6 @@ static inline int qeth_get_elements_for_range(addr_t start, addr_t end) ...@@ -956,24 +956,6 @@ static inline int qeth_get_elements_for_range(addr_t start, addr_t end)
return PFN_UP(end) - PFN_DOWN(start); return PFN_UP(end) - PFN_DOWN(start);
} }
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
__be16 prot = veth->h_vlan_proto;
if (prot == htons(ETH_P_8021Q))
prot = veth->h_vlan_encapsulated_proto;
switch (prot) {
case htons(ETH_P_IPV6):
return 6;
case htons(ETH_P_IP):
return 4;
default:
return 0;
}
}
static inline int qeth_get_ether_cast_type(struct sk_buff *skb) static inline int qeth_get_ether_cast_type(struct sk_buff *skb)
{ {
u8 *addr = eth_hdr(skb)->h_dest; u8 *addr = eth_hdr(skb)->h_dest;
...@@ -984,14 +966,20 @@ static inline int qeth_get_ether_cast_type(struct sk_buff *skb) ...@@ -984,14 +966,20 @@ static inline int qeth_get_ether_cast_type(struct sk_buff *skb)
return RTN_UNICAST; return RTN_UNICAST;
} }
static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb, int ipv) static inline struct dst_entry *qeth_dst_check_rcu(struct sk_buff *skb,
__be16 proto)
{ {
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct rt6_info *rt; struct rt6_info *rt;
rt = (struct rt6_info *) dst; rt = (struct rt6_info *) dst;
if (dst) if (dst) {
dst = dst_check(dst, (ipv == 6) ? rt6_get_cookie(rt) : 0); if (proto == htons(ETH_P_IPV6))
dst = dst_check(dst, rt6_get_cookie(rt));
else
dst = dst_check(dst, 0);
}
return dst; return dst;
} }
...@@ -1014,11 +1002,11 @@ static inline struct in6_addr *qeth_next_hop_v6_rcu(struct sk_buff *skb, ...@@ -1014,11 +1002,11 @@ static inline struct in6_addr *qeth_next_hop_v6_rcu(struct sk_buff *skb,
return &ipv6_hdr(skb)->daddr; 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, __be16 proto)
{ {
*flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; *flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
if ((ipv == 4 && ip_hdr(skb)->protocol == IPPROTO_UDP) || if ((proto == htons(ETH_P_IP) && ip_hdr(skb)->protocol == IPPROTO_UDP) ||
(ipv == 6 && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)) (proto == htons(ETH_P_IPV6) && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP))
*flags |= QETH_HDR_EXT_UDP; *flags |= QETH_HDR_EXT_UDP;
} }
...@@ -1067,8 +1055,8 @@ extern const struct device_type qeth_generic_devtype; ...@@ -1067,8 +1055,8 @@ extern const struct device_type qeth_generic_devtype;
const char *qeth_get_cardname_short(struct qeth_card *); const char *qeth_get_cardname_short(struct qeth_card *);
int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count); int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count);
int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id); int qeth_setup_discipline(struct qeth_card *card, enum qeth_discipline_id disc);
void qeth_core_free_discipline(struct qeth_card *); void qeth_remove_discipline(struct qeth_card *card);
/* exports for qeth discipline device drivers */ /* exports for qeth discipline device drivers */
extern struct kmem_cache *qeth_core_header_cache; extern struct kmem_cache *qeth_core_header_cache;
...@@ -1145,10 +1133,10 @@ int qeth_stop(struct net_device *dev); ...@@ -1145,10 +1133,10 @@ int qeth_stop(struct net_device *dev);
int qeth_vm_request_mac(struct qeth_card *card); int qeth_vm_request_mac(struct qeth_card *card);
int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv, struct qeth_qdio_out_q *queue, __be16 proto,
void (*fill_header)(struct qeth_qdio_out_q *queue, void (*fill_header)(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb,
int ipv, unsigned int data_len)); __be16 proto, unsigned int data_len));
/* exports for OSN */ /* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int); int qeth_osn_assist(struct net_device *, void *, int);
......
...@@ -825,7 +825,8 @@ static bool qeth_next_hop_is_local_v4(struct qeth_card *card, ...@@ -825,7 +825,8 @@ static bool qeth_next_hop_is_local_v4(struct qeth_card *card,
return false; return false;
rcu_read_lock(); rcu_read_lock();
next_hop = qeth_next_hop_v4_rcu(skb, qeth_dst_check_rcu(skb, 4)); next_hop = qeth_next_hop_v4_rcu(skb,
qeth_dst_check_rcu(skb, htons(ETH_P_IP)));
key = ipv4_addr_hash(next_hop); key = ipv4_addr_hash(next_hop);
hash_for_each_possible_rcu(card->local_addrs4, tmp, hnode, key) { hash_for_each_possible_rcu(card->local_addrs4, tmp, hnode, key) {
...@@ -851,7 +852,8 @@ static bool qeth_next_hop_is_local_v6(struct qeth_card *card, ...@@ -851,7 +852,8 @@ static bool qeth_next_hop_is_local_v6(struct qeth_card *card,
return false; return false;
rcu_read_lock(); rcu_read_lock();
next_hop = qeth_next_hop_v6_rcu(skb, qeth_dst_check_rcu(skb, 6)); next_hop = qeth_next_hop_v6_rcu(skb,
qeth_dst_check_rcu(skb, htons(ETH_P_IPV6)));
key = ipv6_addr_hash(next_hop); key = ipv6_addr_hash(next_hop);
hash_for_each_possible_rcu(card->local_addrs6, tmp, hnode, key) { hash_for_each_possible_rcu(card->local_addrs6, tmp, hnode, key) {
...@@ -3690,24 +3692,27 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, ...@@ -3690,24 +3692,27 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
queue->queue_no, index, count); queue->queue_no, index, count);
/* Fake the TX completion interrupt: */ switch (rc) {
if (IS_IQD(card)) { case 0:
unsigned int frames = READ_ONCE(queue->max_coalesced_frames); case -ENOBUFS:
unsigned int usecs = READ_ONCE(queue->coalesce_usecs); /* ignore temporary SIGA errors without busy condition */
if (frames && queue->coalesced_frames >= frames) { /* Fake the TX completion interrupt: */
napi_schedule(&queue->napi); if (IS_IQD(card)) {
queue->coalesced_frames = 0; unsigned int frames = READ_ONCE(queue->max_coalesced_frames);
QETH_TXQ_STAT_INC(queue, coal_frames); unsigned int usecs = READ_ONCE(queue->coalesce_usecs);
} else if (usecs) {
qeth_tx_arm_timer(queue, usecs); if (frames && queue->coalesced_frames >= frames) {
napi_schedule(&queue->napi);
queue->coalesced_frames = 0;
QETH_TXQ_STAT_INC(queue, coal_frames);
} else if (usecs) {
qeth_tx_arm_timer(queue, usecs);
}
} }
}
if (rc) { break;
/* ignore temporary SIGA errors without busy condition */ default:
if (rc == -ENOBUFS)
return;
QETH_CARD_TEXT(queue->card, 2, "flushbuf"); QETH_CARD_TEXT(queue->card, 2, "flushbuf");
QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no); QETH_CARD_TEXT_(queue->card, 2, " q%d", queue->queue_no);
QETH_CARD_TEXT_(queue->card, 2, " idx%d", index); QETH_CARD_TEXT_(queue->card, 2, " idx%d", index);
...@@ -3717,7 +3722,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, ...@@ -3717,7 +3722,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
/* this must not happen under normal circumstances. if it /* this must not happen under normal circumstances. if it
* happens something is really wrong -> recover */ * happens something is really wrong -> recover */
qeth_schedule_recovery(queue->card); qeth_schedule_recovery(queue->card);
return;
} }
} }
...@@ -3896,11 +3900,11 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb) ...@@ -3896,11 +3900,11 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb)
switch (card->qdio.do_prio_queueing) { switch (card->qdio.do_prio_queueing) {
case QETH_PRIO_Q_ING_TOS: case QETH_PRIO_Q_ING_TOS:
case QETH_PRIO_Q_ING_PREC: case QETH_PRIO_Q_ING_PREC:
switch (qeth_get_ip_version(skb)) { switch (vlan_get_protocol(skb)) {
case 4: case htons(ETH_P_IP):
tos = ipv4_get_dsfield(ip_hdr(skb)); tos = ipv4_get_dsfield(ip_hdr(skb));
break; break;
case 6: case htons(ETH_P_IPV6):
tos = ipv6_get_dsfield(ipv6_hdr(skb)); tos = ipv6_get_dsfield(ipv6_hdr(skb));
break; break;
default: default:
...@@ -4365,10 +4369,10 @@ static void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, ...@@ -4365,10 +4369,10 @@ static void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr,
} }
int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv, struct qeth_qdio_out_q *queue, __be16 proto,
void (*fill_header)(struct qeth_qdio_out_q *queue, void (*fill_header)(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb,
int ipv, unsigned int data_len)) __be16 proto, unsigned int data_len))
{ {
unsigned int proto_len, hw_hdr_len; unsigned int proto_len, hw_hdr_len;
unsigned int frame_len = skb->len; unsigned int frame_len = skb->len;
...@@ -4401,7 +4405,7 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb, ...@@ -4401,7 +4405,7 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
data_offset = push_len + proto_len; data_offset = push_len + proto_len;
} }
memset(hdr, 0, hw_hdr_len); memset(hdr, 0, hw_hdr_len);
fill_header(queue, hdr, skb, ipv, frame_len); fill_header(queue, hdr, skb, proto, frame_len);
if (is_tso) if (is_tso)
qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
frame_len - proto_len, skb, proto_len); frame_len - proto_len, skb, proto_len);
...@@ -6349,9 +6353,11 @@ static int qeth_register_dbf_views(void) ...@@ -6349,9 +6353,11 @@ static int qeth_register_dbf_views(void)
static DEFINE_MUTEX(qeth_mod_mutex); /* for synchronized module loading */ static DEFINE_MUTEX(qeth_mod_mutex); /* for synchronized module loading */
int qeth_core_load_discipline(struct qeth_card *card, int qeth_setup_discipline(struct qeth_card *card,
enum qeth_discipline_id discipline) enum qeth_discipline_id discipline)
{ {
int rc;
mutex_lock(&qeth_mod_mutex); mutex_lock(&qeth_mod_mutex);
switch (discipline) { switch (discipline) {
case QETH_DISCIPLINE_LAYER3: case QETH_DISCIPLINE_LAYER3:
...@@ -6373,12 +6379,25 @@ int qeth_core_load_discipline(struct qeth_card *card, ...@@ -6373,12 +6379,25 @@ int qeth_core_load_discipline(struct qeth_card *card,
return -EINVAL; return -EINVAL;
} }
rc = card->discipline->setup(card->gdev);
if (rc) {
if (discipline == QETH_DISCIPLINE_LAYER2)
symbol_put(qeth_l2_discipline);
else
symbol_put(qeth_l3_discipline);
card->discipline = NULL;
return rc;
}
card->options.layer = discipline; card->options.layer = discipline;
return 0; return 0;
} }
void qeth_core_free_discipline(struct qeth_card *card) void qeth_remove_discipline(struct qeth_card *card)
{ {
card->discipline->remove(card->gdev);
if (IS_LAYER2(card)) if (IS_LAYER2(card))
symbol_put(qeth_l2_discipline); symbol_put(qeth_l2_discipline);
else else
...@@ -6586,23 +6605,18 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) ...@@ -6586,23 +6605,18 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
default: default:
card->info.layer_enforced = true; card->info.layer_enforced = true;
/* It's so early that we don't need the discipline_mutex yet. */ /* It's so early that we don't need the discipline_mutex yet. */
rc = qeth_core_load_discipline(card, enforced_disc); rc = qeth_setup_discipline(card, enforced_disc);
if (rc) if (rc)
goto err_load; goto err_setup_disc;
gdev->dev.type = IS_OSN(card) ? &qeth_osn_devtype : gdev->dev.type = IS_OSN(card) ? &qeth_osn_devtype :
card->discipline->devtype; card->discipline->devtype;
rc = card->discipline->setup(card->gdev);
if (rc)
goto err_disc;
break; break;
} }
return 0; return 0;
err_disc: err_setup_disc:
qeth_core_free_discipline(card);
err_load:
err_chp_desc: err_chp_desc:
free_netdev(card->dev); free_netdev(card->dev);
err_card: err_card:
...@@ -6619,10 +6633,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev) ...@@ -6619,10 +6633,8 @@ static void qeth_core_remove_device(struct ccwgroup_device *gdev)
QETH_CARD_TEXT(card, 2, "removedv"); QETH_CARD_TEXT(card, 2, "removedv");
mutex_lock(&card->discipline_mutex); mutex_lock(&card->discipline_mutex);
if (card->discipline) { if (card->discipline)
card->discipline->remove(gdev); qeth_remove_discipline(card);
qeth_core_free_discipline(card);
}
mutex_unlock(&card->discipline_mutex); mutex_unlock(&card->discipline_mutex);
qeth_free_qdio_queues(card); qeth_free_qdio_queues(card);
...@@ -6642,14 +6654,9 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev) ...@@ -6642,14 +6654,9 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev)
if (!card->discipline) { if (!card->discipline) {
def_discipline = IS_IQD(card) ? QETH_DISCIPLINE_LAYER3 : def_discipline = IS_IQD(card) ? QETH_DISCIPLINE_LAYER3 :
QETH_DISCIPLINE_LAYER2; QETH_DISCIPLINE_LAYER2;
rc = qeth_core_load_discipline(card, def_discipline); rc = qeth_setup_discipline(card, def_discipline);
if (rc) if (rc)
goto err; goto err;
rc = card->discipline->setup(card->gdev);
if (rc) {
qeth_core_free_discipline(card);
goto err;
}
} }
rc = qeth_set_online(card, card->discipline); rc = qeth_set_online(card, card->discipline);
......
...@@ -384,19 +384,13 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, ...@@ -384,19 +384,13 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
goto out; goto out;
} }
card->discipline->remove(card->gdev); qeth_remove_discipline(card);
qeth_core_free_discipline(card);
free_netdev(card->dev); free_netdev(card->dev);
card->dev = ndev; card->dev = ndev;
} }
rc = qeth_core_load_discipline(card, newdis); rc = qeth_setup_discipline(card, newdis);
if (rc)
goto out;
rc = card->discipline->setup(card->gdev);
if (rc)
qeth_core_free_discipline(card);
out: out:
mutex_unlock(&card->discipline_mutex); mutex_unlock(&card->discipline_mutex);
return rc ? rc : count; return rc ? rc : count;
......
...@@ -157,7 +157,7 @@ static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card) ...@@ -157,7 +157,7 @@ static void qeth_l2_drain_rx_mode_cache(struct qeth_card *card)
static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue, static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb,
int ipv, unsigned int data_len) __be16 proto, unsigned int data_len)
{ {
int cast_type = qeth_get_ether_cast_type(skb); int cast_type = qeth_get_ether_cast_type(skb);
struct vlan_ethhdr *veth = vlan_eth_hdr(skb); struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
...@@ -169,7 +169,7 @@ static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue, ...@@ -169,7 +169,7 @@ static void qeth_l2_fill_header(struct qeth_qdio_out_q *queue,
} else { } else {
hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
if (skb->ip_summed == CHECKSUM_PARTIAL) if (skb->ip_summed == CHECKSUM_PARTIAL)
qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], proto);
} }
/* set byte byte 3 to casting flags */ /* set byte byte 3 to casting flags */
...@@ -551,7 +551,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, ...@@ -551,7 +551,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
if (IS_OSN(card)) if (IS_OSN(card))
rc = qeth_l2_xmit_osn(card, skb, queue); rc = qeth_l2_xmit_osn(card, skb, queue);
else else
rc = qeth_xmit(card, skb, queue, qeth_get_ip_version(skb), rc = qeth_xmit(card, skb, queue, vlan_get_protocol(skb),
qeth_l2_fill_header); qeth_l2_fill_header);
if (!rc) if (!rc)
......
...@@ -1576,7 +1576,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1576,7 +1576,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
} }
static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst, static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst,
int ipv) __be16 proto)
{ {
struct neighbour *n = NULL; struct neighbour *n = NULL;
...@@ -1595,30 +1595,31 @@ static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst, ...@@ -1595,30 +1595,31 @@ static int qeth_l3_get_cast_type_rcu(struct sk_buff *skb, struct dst_entry *dst,
} }
/* no neighbour (eg AF_PACKET), fall back to target's IP address ... */ /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
switch (ipv) { switch (proto) {
case 4: case htons(ETH_P_IP):
if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) if (ipv4_is_lbcast(ip_hdr(skb)->daddr))
return RTN_BROADCAST; return RTN_BROADCAST;
return ipv4_is_multicast(ip_hdr(skb)->daddr) ? return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
RTN_MULTICAST : RTN_UNICAST; RTN_MULTICAST : RTN_UNICAST;
case 6: case htons(ETH_P_IPV6):
return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ? return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
RTN_MULTICAST : RTN_UNICAST; RTN_MULTICAST : RTN_UNICAST;
case htons(ETH_P_AF_IUCV):
return RTN_UNICAST;
default: default:
/* ... and MAC address */ /* OSA only: ... and MAC address */
return qeth_get_ether_cast_type(skb); return qeth_get_ether_cast_type(skb);
} }
} }
static int qeth_l3_get_cast_type(struct sk_buff *skb) static int qeth_l3_get_cast_type(struct sk_buff *skb, __be16 proto)
{ {
int ipv = qeth_get_ip_version(skb);
struct dst_entry *dst; struct dst_entry *dst;
int cast_type; int cast_type;
rcu_read_lock(); rcu_read_lock();
dst = qeth_dst_check_rcu(skb, ipv); dst = qeth_dst_check_rcu(skb, proto);
cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv); cast_type = qeth_l3_get_cast_type_rcu(skb, dst, proto);
rcu_read_unlock(); rcu_read_unlock();
return cast_type; return cast_type;
...@@ -1637,7 +1638,7 @@ static u8 qeth_l3_cast_type_to_flag(int cast_type) ...@@ -1637,7 +1638,7 @@ static u8 qeth_l3_cast_type_to_flag(int cast_type)
static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb,
int ipv, unsigned int data_len) __be16 proto, unsigned int data_len)
{ {
struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3; struct qeth_hdr_layer3 *l3_hdr = &hdr->hdr.l3;
struct vlan_ethhdr *veth = vlan_eth_hdr(skb); struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
...@@ -1652,23 +1653,15 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, ...@@ -1652,23 +1653,15 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
} else { } else {
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
if (skb->protocol == htons(ETH_P_AF_IUCV)) {
l3_hdr->flags = QETH_HDR_IPV6 | QETH_CAST_UNICAST;
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;
}
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, ipv); qeth_tx_csum(skb, &hdr->hdr.l3.ext_flags, proto);
/* some HW requires combined L3+L4 csum offload: */ /* some HW requires combined L3+L4 csum offload: */
if (ipv == 4) if (proto == htons(ETH_P_IP))
hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ; hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_HDR_REQ;
} }
} }
if (ipv == 4 || IS_IQD(card)) { if (proto == htons(ETH_P_IP) || IS_IQD(card)) {
/* NETIF_F_HW_VLAN_CTAG_TX */ /* NETIF_F_HW_VLAN_CTAG_TX */
if (skb_vlan_tag_present(skb)) { if (skb_vlan_tag_present(skb)) {
hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME; hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_VLAN_FRAME;
...@@ -1680,24 +1673,33 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue, ...@@ -1680,24 +1673,33 @@ static void qeth_l3_fill_header(struct qeth_qdio_out_q *queue,
} }
rcu_read_lock(); rcu_read_lock();
dst = qeth_dst_check_rcu(skb, ipv); dst = qeth_dst_check_rcu(skb, proto);
if (IS_IQD(card) && skb_get_queue_mapping(skb) != QETH_IQD_MCAST_TXQ) if (IS_IQD(card) && skb_get_queue_mapping(skb) != QETH_IQD_MCAST_TXQ)
cast_type = RTN_UNICAST; cast_type = RTN_UNICAST;
else else
cast_type = qeth_l3_get_cast_type_rcu(skb, dst, ipv); cast_type = qeth_l3_get_cast_type_rcu(skb, dst, proto);
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) { switch (proto) {
case htons(ETH_P_IP):
l3_hdr->next_hop.addr.s6_addr32[3] = l3_hdr->next_hop.addr.s6_addr32[3] =
qeth_next_hop_v4_rcu(skb, dst); qeth_next_hop_v4_rcu(skb, dst);
} else if (ipv == 6) { break;
case htons(ETH_P_IPV6):
l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, dst); l3_hdr->next_hop.addr = *qeth_next_hop_v6_rcu(skb, dst);
hdr->hdr.l3.flags |= QETH_HDR_IPV6; hdr->hdr.l3.flags |= QETH_HDR_IPV6;
if (!IS_IQD(card)) if (!IS_IQD(card))
hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU; hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
} else { break;
case htons(ETH_P_AF_IUCV):
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);
l3_hdr->flags |= QETH_HDR_IPV6;
break;
default:
/* OSA only: */ /* OSA only: */
l3_hdr->flags |= QETH_HDR_PASSTHRU; l3_hdr->flags |= QETH_HDR_PASSTHRU;
} }
...@@ -1719,7 +1721,7 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb) ...@@ -1719,7 +1721,7 @@ static void qeth_l3_fixup_headers(struct sk_buff *skb)
} }
static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv) struct qeth_qdio_out_q *queue, __be16 proto)
{ {
unsigned int hw_hdr_len; unsigned int hw_hdr_len;
int rc; int rc;
...@@ -1733,15 +1735,15 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, ...@@ -1733,15 +1735,15 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
skb_pull(skb, ETH_HLEN); skb_pull(skb, ETH_HLEN);
qeth_l3_fixup_headers(skb); qeth_l3_fixup_headers(skb);
return qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header); return qeth_xmit(card, skb, queue, proto, qeth_l3_fill_header);
} }
static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
__be16 proto = vlan_get_protocol(skb);
u16 txq = skb_get_queue_mapping(skb); u16 txq = skb_get_queue_mapping(skb);
int ipv = qeth_get_ip_version(skb);
struct qeth_qdio_out_q *queue; struct qeth_qdio_out_q *queue;
int rc; int rc;
...@@ -1752,22 +1754,32 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, ...@@ -1752,22 +1754,32 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
if (card->options.sniffer) if (card->options.sniffer)
goto tx_drop; goto tx_drop;
if ((card->options.cq != QETH_CQ_ENABLED && !ipv) ||
(card->options.cq == QETH_CQ_ENABLED && switch (proto) {
skb->protocol != htons(ETH_P_AF_IUCV))) case htons(ETH_P_AF_IUCV):
if (card->options.cq != QETH_CQ_ENABLED)
goto tx_drop;
break;
case htons(ETH_P_IP):
case htons(ETH_P_IPV6):
if (card->options.cq == QETH_CQ_ENABLED)
goto tx_drop;
break;
default:
goto tx_drop; goto tx_drop;
}
} else { } else {
queue = card->qdio.out_qs[txq]; queue = card->qdio.out_qs[txq];
} }
if (!(dev->flags & IFF_BROADCAST) && if (!(dev->flags & IFF_BROADCAST) &&
qeth_l3_get_cast_type(skb) == RTN_BROADCAST) qeth_l3_get_cast_type(skb, proto) == RTN_BROADCAST)
goto tx_drop; goto tx_drop;
if (ipv == 4 || IS_IQD(card)) if (proto == htons(ETH_P_IP) || IS_IQD(card))
rc = qeth_l3_xmit(card, skb, queue, ipv); rc = qeth_l3_xmit(card, skb, queue, proto);
else else
rc = qeth_xmit(card, skb, queue, ipv, qeth_l3_fill_header); rc = qeth_xmit(card, skb, queue, proto, qeth_l3_fill_header);
if (!rc) if (!rc)
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -1821,8 +1833,10 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb, ...@@ -1821,8 +1833,10 @@ static netdev_features_t qeth_l3_osa_features_check(struct sk_buff *skb,
static u16 qeth_l3_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, static u16 qeth_l3_iqd_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev) struct net_device *sb_dev)
{ {
return qeth_iqd_select_queue(dev, skb, qeth_l3_get_cast_type(skb), __be16 proto = vlan_get_protocol(skb);
sb_dev);
return qeth_iqd_select_queue(dev, skb,
qeth_l3_get_cast_type(skb, proto), sb_dev);
} }
static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb, static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb,
......
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