Skip to content

Commit

Permalink
s390/qeth: add support for IPv6 TSO
Browse files Browse the repository at this point in the history
This adds TSO6 support for L3 qeth devices.
Just like for standard IPv6 traffic, TSO6 doesn't use IP offload and
thus runs over the normal qeth_xmit() path.

Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Julian Wiedmann authored and David S. Miller committed Oct 12, 2018
1 parent 4666d7f commit 82bf5c0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 31 deletions.
2 changes: 2 additions & 0 deletions drivers/s390/net/qeth_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,8 @@ int qeth_vm_request_mac(struct qeth_card *card);
int qeth_add_hw_header(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr, unsigned int hdr_len,
unsigned int proto_len, unsigned int *elements);
void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len,
struct sk_buff *skb, unsigned int proto_len);
int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv, int cast_type,
void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr,
Expand Down
49 changes: 44 additions & 5 deletions drivers/s390/net/qeth_core_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4088,22 +4088,46 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
}
EXPORT_SYMBOL_GPL(qeth_do_send_packet);

void qeth_fill_tso_ext(struct qeth_hdr_tso *hdr, unsigned int payload_len,
struct sk_buff *skb, unsigned int proto_len)
{
struct qeth_hdr_ext_tso *ext = &hdr->ext;

ext->hdr_tot_len = sizeof(*ext);
ext->imb_hdr_no = 1;
ext->hdr_type = 1;
ext->hdr_version = 1;
ext->hdr_len = 28;
ext->payload_len = payload_len;
ext->mss = skb_shinfo(skb)->gso_size;
ext->dg_hdr_len = proto_len;
}
EXPORT_SYMBOL_GPL(qeth_fill_tso_ext);

int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
struct qeth_qdio_out_q *queue, int ipv, int cast_type,
void (*fill_header)(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type,
unsigned int data_len))
{
const unsigned int proto_len = IS_IQD(card) ? ETH_HLEN : 0;
const unsigned int hw_hdr_len = sizeof(struct qeth_hdr);
unsigned int proto_len, hw_hdr_len;
unsigned int frame_len = skb->len;
bool is_tso = skb_is_gso(skb);
unsigned int data_offset = 0;
struct qeth_hdr *hdr = NULL;
unsigned int hd_len = 0;
unsigned int elements;
int push_len, rc;
bool is_sg;

if (is_tso) {
hw_hdr_len = sizeof(struct qeth_hdr_tso);
proto_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
} else {
hw_hdr_len = sizeof(struct qeth_hdr);
proto_len = IS_IQD(card) ? ETH_HLEN : 0;
}

rc = skb_cow_head(skb, hw_hdr_len);
if (rc)
return rc;
Expand All @@ -4112,13 +4136,16 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
&elements);
if (push_len < 0)
return push_len;
if (!push_len) {
if (is_tso || !push_len) {
/* HW header needs its own buffer element. */
hd_len = hw_hdr_len + proto_len;
data_offset = proto_len;
data_offset = push_len + proto_len;
}
memset(hdr, 0, hw_hdr_len);
fill_header(card, hdr, skb, ipv, cast_type, frame_len);
if (is_tso)
qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
frame_len - proto_len, skb, proto_len);

is_sg = skb_is_nonlinear(skb);
if (IS_IQD(card)) {
Expand All @@ -4136,6 +4163,10 @@ int qeth_xmit(struct qeth_card *card, struct sk_buff *skb,
card->perf_stats.buf_elements_sent += elements;
if (is_sg)
card->perf_stats.sg_skbs_sent++;
if (is_tso) {
card->perf_stats.large_send_bytes += frame_len;
card->perf_stats.large_send_cnt++;
}
}
} else {
if (!push_len)
Expand Down Expand Up @@ -6516,7 +6547,7 @@ static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on)
}

#define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO | \
NETIF_F_IPV6_CSUM)
NETIF_F_IPV6_CSUM | NETIF_F_TSO6)
/**
* qeth_enable_hw_features() - (Re-)Enable HW functions for device features
* @dev: a net_device
Expand Down Expand Up @@ -6572,6 +6603,12 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features)
if (rc)
changed ^= NETIF_F_TSO;
}
if (changed & NETIF_F_TSO6) {
rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO6,
QETH_PROT_IPV6);
if (rc)
changed ^= NETIF_F_TSO6;
}

/* everything changed successfully? */
if ((dev->features ^ features) == changed)
Expand All @@ -6597,6 +6634,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev,
features &= ~NETIF_F_RXCSUM;
if (!qeth_is_supported(card, IPA_OUTBOUND_TSO))
features &= ~NETIF_F_TSO;
if (!qeth_is_supported6(card, IPA_OUTBOUND_TSO))
features &= ~NETIF_F_TSO6;
/* if the card isn't up, remove features that require hw changes */
if (card->state == CARD_STATE_DOWN ||
card->state == CARD_STATE_RECOVER)
Expand Down
45 changes: 19 additions & 26 deletions drivers/s390/net/qeth_l3_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2099,22 +2099,6 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
rcu_read_unlock();
}

static void qeth_l3_fill_tso_ext(struct qeth_hdr_tso *hdr,
unsigned int payload_len, struct sk_buff *skb,
unsigned int proto_len)
{
struct qeth_hdr_ext_tso *ext = &hdr->ext;

ext->hdr_tot_len = sizeof(*ext);
ext->imb_hdr_no = 1;
ext->hdr_type = 1;
ext->hdr_version = 1;
ext->hdr_len = 28;
ext->payload_len = payload_len;
ext->mss = skb_shinfo(skb)->gso_size;
ext->dg_hdr_len = proto_len;
}

static void qeth_l3_fixup_headers(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
Expand Down Expand Up @@ -2175,9 +2159,9 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,
} else {
qeth_l3_fill_header(card, hdr, skb, ipv, cast_type, frame_len);
if (is_tso)
qeth_l3_fill_tso_ext((struct qeth_hdr_tso *) hdr,
frame_len - proto_len, skb,
proto_len);
qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr,
frame_len - proto_len, skb,
proto_len);
}

is_sg = skb_is_nonlinear(skb);
Expand Down Expand Up @@ -2401,6 +2385,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {

static int qeth_l3_setup_netdev(struct qeth_card *card)
{
unsigned int headroom;
int rc;

if (card->dev->netdev_ops)
Expand All @@ -2415,11 +2400,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
}

card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
card->dev->needed_headroom = sizeof(struct qeth_hdr);
/* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
card->dev->needed_headroom += VLAN_HLEN;
if (qeth_is_supported(card, IPA_OUTBOUND_TSO))
card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);

/*IPv6 address autoconfiguration stuff*/
qeth_l3_get_unique_id(card);
Expand All @@ -2438,10 +2418,22 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
card->dev->hw_features |= NETIF_F_IPV6_CSUM;
card->dev->vlan_features |= NETIF_F_IPV6_CSUM;
}
if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
card->dev->hw_features |= NETIF_F_TSO6;
card->dev->vlan_features |= NETIF_F_TSO6;
}

/* allow for de-acceleration of NETIF_F_HW_VLAN_CTAG_TX: */
if (card->dev->hw_features & NETIF_F_TSO6)
headroom = sizeof(struct qeth_hdr_tso) + VLAN_HLEN;
else if (card->dev->hw_features & NETIF_F_TSO)
headroom = sizeof(struct qeth_hdr_tso);
else
headroom = sizeof(struct qeth_hdr) + VLAN_HLEN;
} else if (card->info.type == QETH_CARD_TYPE_IQD) {
card->dev->flags |= IFF_NOARP;
card->dev->netdev_ops = &qeth_l3_netdev_ops;
card->dev->needed_headroom = sizeof(struct qeth_hdr) - ETH_HLEN;
headroom = sizeof(struct qeth_hdr) - ETH_HLEN;

rc = qeth_l3_iqd_read_initial_mac(card);
if (rc)
Expand All @@ -2452,13 +2444,14 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
} else
return -ENODEV;

card->dev->needed_headroom = headroom;
card->dev->ethtool_ops = &qeth_l3_ethtool_ops;
card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;

netif_keep_dst(card->dev);
if (card->dev->hw_features & NETIF_F_TSO)
if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6))
netif_set_gso_max_size(card->dev,
PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1));

Expand Down

0 comments on commit 82bf5c0

Please sign in to comment.