s390/qeth: updates 2018-07-11
Subsystems (4)
cover s390/qeth: updates 2018-07-11
Hi Dave,
please apply this first batch of qeth patches for net-next. It brings the usual cleanups, and some performance improvements to the transmit paths.
Thanks,
Julian
Julian Wiedmann (10):
s390/qeth: various buffer management cleanups s390/qeth: remove unused buffer->aob pointer s390/qeth: fine-tune RX modesetting
s390/qeth: clean up Output Queue selection s390/qeth: consolidate ccwgroup driver definition s390/qeth: clean up exported symbols
s390/qeth: increase GSO max size for eligible L3 devices s390/qeth: add a L3 xmit wrapper
s390/qeth: speed-up L3 IQD xmit
s390/qeth: speed-up IPv4 OSA xmit
drivers/s390/net/qeth_core.h | 22 ++- drivers/s390/net/qeth_core_main.c | 131 +++++--------- drivers/s390/net/qeth_core_mpc.h | 2 + drivers/s390/net/qeth_l2.h | 5 + drivers/s390/net/qeth_l2_main.c | 20 +-- drivers/s390/net/qeth_l3_main.c | 360 ++++++++++++++++++++++---------------- 6 files changed, 281 insertions(+), 259 deletions(-)
Signature · 1 line
2.16.4
PATCH 1/10 s390/qeth: various buffer management cleanups
Use the new qeth_scrub_qdio_buffer() helper, remove an extra parameter from qeth_clear_output_buffer(), init the bufstates.user field just once (in qeth_flush_buffers()) and remove some noisy trace messages.
--- drivers/s390/net/qeth_core_main.c | 66 ++++++++++++--------------------------- 1 file changed, 20 insertions(+), 46 deletions(-)
drivers/s390/net/qeth_core_main.c +20 -46
@@ -1267,8 +1267,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) }static void qeth_clear_output_buffer (struct qeth_qdio_out_q *queue, -struct qeth_qdio_out_buffer *buf, -enum qeth_qdio_buffer_states newbufstate) +struct qeth_qdio_out_buffer *buf) {int i;
@@ -1276,23 +1275,19 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,if (buf->buffer->element[0 ].sflags &SBAL_SFLAGS0_PCI_REQ )atomic_dec (&queue->set_pci_flags_count); -if (newbufstate ==QETH_QDIO_BUF_EMPTY ) { -qeth_release_skbs (buf); - } +qeth_release_skbs (buf); +for (i =0 ; i <QETH_MAX_BUFFER_ELEMENTS (queue->card); ++i) {if (buf->buffer->element[i].addr && buf->is_header[i])kmem_cache_free (qeth_core_header_cache, buf->buffer->element[i].addr); buf->is_header[i] =0 ; - buf->buffer->element[i].length =0 ; - buf->buffer->element[i].addr =NULL ; - buf->buffer->element[i].eflags =0 ; - buf->buffer->element[i].sflags =0 ; } - buf->buffer->element[15 ].eflags =0 ; - buf->buffer->element[15 ].sflags =0 ; + +qeth_scrub_qdio_buffer (buf->buffer, +QETH_MAX_BUFFER_ELEMENTS (queue->card)); buf->next_element_to_fill =0 ; -atomic_set (&buf->state, newbufstate); +atomic_set (&buf->state,QETH_QDIO_BUF_EMPTY ); }static void qeth_clear_outq_buffers (struct qeth_qdio_out_q *q,int free)
@@ -1303,7 +1298,7 @@ static void qeth_clear_outq_buffers(struct qeth_qdio_out_q *q, int free)if (!q->bufs[j])continue ;qeth_cleanup_handled_pending (q, j,1 ); -qeth_clear_output_buffer (q, q->bufs[j],QETH_QDIO_BUF_EMPTY ); +qeth_clear_output_buffer (q, q->bufs[j]);if (free) {kmem_cache_free (qeth_qdio_outbuf_cache, q->bufs[j]); q->bufs[j] =NULL ;
@@ -2473,15 +2468,12 @@ static int qeth_ulp_setup(struct qeth_card *card)static int qeth_init_qdio_out_buf (struct qeth_qdio_out_q *q,int bidx) { -int rc;struct qeth_qdio_out_buffer *newbuf; - rc =0 ; newbuf =kmem_cache_zalloc (qeth_qdio_outbuf_cache,GFP_ATOMIC ); -if (!newbuf) { - rc = -ENOMEM ; - goto out; - } +if (!newbuf) +return -ENOMEM ; + newbuf->buffer = q->qdio_bufs[bidx];skb_queue_head_init (&newbuf->skb_list);lockdep_set_class (&newbuf->skb_list.lock, &qdio_out_skb_queue_key);
@@ -2490,15 +2482,7 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx) newbuf->next_pending = q->bufs[bidx];atomic_set (&newbuf->state,QETH_QDIO_BUF_EMPTY ); q->bufs[bidx] = newbuf; -if (q->bufstates) { - q->bufstates[bidx].user = newbuf; -QETH_CARD_TEXT_ (q->card,2 ,"nbs%d" , bidx); -QETH_CARD_TEXT_ (q->card,2 ,"%lx" , (long ) newbuf); -QETH_CARD_TEXT_ (q->card,2 ,"%lx" , - (long ) newbuf->next_pending); - } -out: -return rc; +return 0 ; }static void qeth_free_qdio_out_buf (struct qeth_qdio_out_q *q)
@@ -2908,8 +2892,7 @@ int qeth_init_qdio_queues(struct qeth_card *card) QDIO_MAX_BUFFERS_PER_Q);for (j =0 ; j <QDIO_MAX_BUFFERS_PER_Q ; ++j) {qeth_clear_output_buffer (card->qdio.out_qs[i], - card->qdio.out_qs[i]->bufs[j], -QETH_QDIO_BUF_EMPTY ); + card->qdio.out_qs[i]->bufs[j]); } card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->next_buf_to_fill =0 ;
@@ -3634,10 +3617,10 @@ int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq) }EXPORT_SYMBOL_GPL (qeth_configure_cq); - -static void qeth_qdio_cq_handler (struct qeth_card *card, -unsigned int qdio_err, -unsigned int queue,int first_element,int count) { +static void qeth_qdio_cq_handler (struct qeth_card *card,unsigned int qdio_err, +unsigned int queue,int first_element, +int count) +{struct qeth_qdio_q *cq = card->qdio.c_q;int i;int rc;
@@ -3663,25 +3646,17 @@ static void qeth_qdio_cq_handler(struct qeth_card *card,for (i = first_element; i < first_element + count; ++i) {int bidx = i %QDIO_MAX_BUFFERS_PER_Q ;struct qdio_buffer *buffer = cq->qdio_bufs[bidx]; -int e; +int e =0 ; - e =0 ;while ((e <QDIO_MAX_ELEMENTS_PER_BUFFER ) && buffer->element[e].addr) {unsigned long phys_aob_addr; phys_aob_addr = (unsigned long ) buffer->element[e].addr;qeth_qdio_handle_aob (card, phys_aob_addr); - buffer->element[e].addr =NULL ; - buffer->element[e].eflags =0 ; - buffer->element[e].sflags =0 ; - buffer->element[e].length =0 ; - ++e; } - - buffer->element[15 ].eflags =0 ; - buffer->element[15 ].sflags =0 ; +qeth_scrub_qdio_buffer (buffer,QDIO_MAX_ELEMENTS_PER_BUFFER ); } rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, queue, card->qdio.c_q->next_buf_to_init,
@@ -3782,8 +3757,7 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev,qeth_notify_skbs (queue, buffer, n); } -qeth_clear_output_buffer (queue, buffer, -QETH_QDIO_BUF_EMPTY ); +qeth_clear_output_buffer (queue, buffer); }qeth_cleanup_handled_pending (queue, bidx,0 ); }
Signature · 1 line
2.16.4
PATCH 2/10 s390/qeth: remove unused buffer->aob pointer
In reply to Julian WiedmannExcept for tracing, the pointer is not used.
At the same time, accessing it from qeth_qdio_output_handler() is racy:
whenever qeth_qdio_cq_handler() gets control, its call to qeth_qdio_handle_aob() frees the AOB.
So the AOB pointer that qeth_qdio_output_handler() stores into 'buffer' can go stale at any time, and trigger a use-after-free.
--- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_core_main.c | 7 ------- 2 files changed, 8 deletions(-)
drivers/s390/net/qeth_core.h +0 -1
@@ -465,7 +465,6 @@ struct qeth_qdio_out_buffer {struct sk_buff_head skb_list;int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER ]; -struct qaob *aob;struct qeth_qdio_out_q *q;struct qeth_qdio_out_buffer *next_pending; };
drivers/s390/net/qeth_core_main.c +0 -7
@@ -473,7 +473,6 @@ static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx,if (forced_cleanup && (atomic_read (&(q->bufs[bidx]->state)) ==QETH_QDIO_BUF_HANDLED_DELAYED )) {/* for recovery situations */ - q->bufs[bidx]->aob = q->bufstates[bidx].aob;qeth_init_qdio_out_buf (q, bidx);QETH_CARD_TEXT (q->card,2 ,"clprecov" ); }
@@ -510,7 +509,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card, }qeth_notify_skbs (buffer->q, buffer, notification); - buffer->aob =NULL ;/* Free dangling allocations. The attached skbs are handled by * qeth_cleanup_handled_pending(). */
@@ -2478,7 +2476,6 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *q, int bidx)skb_queue_head_init (&newbuf->skb_list);lockdep_set_class (&newbuf->skb_list.lock, &qdio_out_skb_queue_key); newbuf->q = q; - newbuf->aob =NULL ; newbuf->next_pending = q->bufs[bidx];atomic_set (&newbuf->state,QETH_QDIO_BUF_EMPTY ); q->bufs[bidx] = newbuf;
@@ -3735,11 +3732,7 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev,qeth_notify_skbs (queue, buffer,TX_NOTIFY_PENDING ); } - buffer->aob = queue->bufstates[bidx].aob;QETH_CARD_TEXT_ (queue->card,5 ,"pel%d" , bidx); -QETH_CARD_TEXT (queue->card,5 ,"aob" ); -QETH_CARD_TEXT_ (queue->card,5 ,"%lx" , -virt_to_phys (buffer->aob));/* prepare the queue slot for re-use: */ qeth_scrub_qdio_buffer(buffer->buffer,
Signature · 1 line
2.16.4
PATCH 3/10 s390/qeth: fine-tune RX modesetting
In reply to Julian WiedmannChanging a device's address lists (or its promisc mode) already triggers an RX modeset, there's no need to do it manually from the L2 driver's ndo_vlan_rx_kill_vid() hook.
Also when setting a device online, dev_open() already calls dev_set_rx_mode(). So a manual modeset is only necessary from the recovery path.
--- drivers/s390/net/qeth_l2_main.c | 5 +---- drivers/s390/net/qeth_l3_main.c | 7 ++++--- 2 files changed, 5 insertions(+), 7 deletions(-)
drivers/s390/net/qeth_l2_main.c +1 -4
@@ -26,7 +26,6 @@static int qeth_l2_set_offline (struct ccwgroup_device *);static int qeth_l2_stop (struct net_device *); -static void qeth_l2_set_rx_mode (struct net_device *);static void qeth_bridgeport_query_support (struct qeth_card *card);static void qeth_bridge_state_change (struct qeth_card *card,struct qeth_ipa_cmd *cmd);
@@ -344,7 +343,6 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, rc =qeth_l2_send_setdelvlan (card, vid,IPA_CMD_DELVLAN );kfree (tmpid); } -qeth_l2_set_rx_mode (card->dev);return rc; }
@@ -1125,13 +1123,12 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)if (recovery_mode && card->info.type !=QETH_CARD_TYPE_OSN ) {__qeth_l2_open (card->dev); +qeth_l2_set_rx_mode (card->dev); }else {rtnl_lock ();dev_open (card->dev);rtnl_unlock (); } -/* this also sets saved unicast addresses */ -qeth_l2_set_rx_mode (card->dev); }/* let user_space know that device is online */ kobject_uevent (&gdev->dev.kobj,KOBJ_CHANGE );
drivers/s390/net/qeth_l3_main.c +4 -3
@@ -2666,11 +2666,12 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)qeth_enable_hw_features (card->dev);if (recover_flag ==CARD_STATE_RECOVER ) {rtnl_lock (); -if (recovery_mode) +if (recovery_mode) {__qeth_l3_open (card->dev); -else +qeth_l3_set_rx_mode (card->dev); + }else {dev_open (card->dev); -qeth_l3_set_rx_mode (card->dev); + }rtnl_unlock (); }qeth_trace_features (card);
Signature · 1 line
2.16.4
PATCH 4/10 s390/qeth: clean up Output Queue selection
In reply to Julian WiedmannConsolidate duplicated code, fix the misuse of RTN_UNSPEC and simplify the handling of non-unicast traffic on IQD devices.
--- drivers/s390/net/qeth_core.h | 15 +++++++++++++-- drivers/s390/net/qeth_core_main.c | 8 +------- drivers/s390/net/qeth_core_mpc.h | 2 ++ drivers/s390/net/qeth_l2_main.c | 13 ++++--------- drivers/s390/net/qeth_l3_main.c | 16 +++++++--------- 5 files changed, 27 insertions(+), 27 deletions(-)
drivers/s390/net/qeth_core.h +13 -2
@@ -661,7 +661,6 @@ struct qeth_card_info {int portno;enum qeth_card_types type;enum qeth_link_types link_type; -int is_multicast_different;int initial_mtu;int max_mtu;int broadcast_capable;
@@ -934,6 +933,19 @@ static inline int qeth_send_simple_setassparms_v6(struct qeth_card *card, data, QETH_PROT_IPV6); } +int qeth_get_priority_queue (struct qeth_card *card,struct sk_buff *skb, +int ipv); +static inline struct qeth_qdio_out_q *qeth_get_tx_queue (struct qeth_card *card, +struct sk_buff *skb, +int ipv,int cast_type) +{ +if (IS_IQD (card) && cast_type !=RTN_UNICAST ) +return card->qdio.out_qs[card->qdio.no_out_queues -1 ]; +if (!card->qdio.do_prio_queueing) +return card->qdio.out_qs[card->qdio.default_out_queue]; +return card->qdio.out_qs[qeth_get_priority_queue (card, skb, ipv)]; +} +extern struct qeth_discipline qeth_l2_discipline;extern struct qeth_discipline qeth_l3_discipline;extern const struct attribute_group *qeth_generic_attr_groups[];
@@ -1001,7 +1013,6 @@ int qeth_bridgeport_query_ports(struct qeth_card *card, enum qeth_sbp_roles *role, enum qeth_sbp_states *state);int qeth_bridgeport_setrole (struct qeth_card *card,enum qeth_sbp_roles role);int qeth_bridgeport_an_set (struct qeth_card *card,int enable); -int qeth_get_priority_queue (struct qeth_card *,struct sk_buff *,int ,int );int qeth_get_elements_no (struct qeth_card *card,struct sk_buff *skb,int extra_elems,int data_offset);int qeth_get_elements_for_frags (struct sk_buff *);
drivers/s390/net/qeth_core_main.c +1 -7
@@ -1537,8 +1537,6 @@ static void qeth_determine_card_type(struct qeth_card *card) card->qdio.default_out_queue =QETH_DEFAULT_QUEUE ; card->info.type =CARD_RDEV (card)->id.driver_info; card->qdio.no_out_queues =QETH_MAX_QUEUES ; -if (card->info.type ==QETH_CARD_TYPE_IQD ) - card->info.is_multicast_different =0x0103 ;qeth_update_from_chp_desc (card); }
@@ -3777,15 +3775,11 @@ static inline int qeth_cut_iqd_prio(struct qeth_card *card, int queue_num)* Note: Function assumes that we have 4 outbound queues. */ int qeth_get_priority_queue (struct qeth_card *card,struct sk_buff *skb, -int ipv,int cast_type) +int ipv) {__be16 *tci;u8 tos; -if (cast_type && card->info.is_multicast_different) -return card->info.is_multicast_different & - (card->qdio.no_out_queues -1 ); -switch (card->qdio.do_prio_queueing) {case QETH_PRIO_Q_ING_TOS :case QETH_PRIO_Q_ING_PREC :
drivers/s390/net/qeth_core_mpc.h +2 -0
@@ -64,6 +64,8 @@ enum qeth_card_types { QETH_CARD_TYPE_OSX = 2, }; +#define IS_IQD (card) ((card)->info.type == QETH_CARD_TYPE_IQD) +#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18/* only the first two bytes are looked at in qeth_get_cardname_short */ enum qeth_link_types {
drivers/s390/net/qeth_l2_main.c +4 -9
@@ -185,12 +185,12 @@ static void qeth_l2_del_all_macs(struct qeth_card *card)static int qeth_l2_get_cast_type (struct qeth_card *card,struct sk_buff *skb) {if (card->info.type ==QETH_CARD_TYPE_OSN ) -return RTN_UNSPEC ; +return RTN_UNICAST ;if (is_broadcast_ether_addr (skb->data))return RTN_BROADCAST ;if (is_multicast_ether_addr (skb->data))return RTN_MULTICAST ; -return RTN_UNSPEC ; +return RTN_UNICAST ; } static void qeth_l2_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb,
@@ -768,18 +768,13 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,int tx_bytes = skb->len;int rc; -if (card->qdio.do_prio_queueing || (cast_type && - card->info.is_multicast_different)) - queue = card->qdio.out_qs[qeth_get_priority_queue (card, skb, - ipv, cast_type)]; -else - queue = card->qdio.out_qs[card->qdio.default_out_queue]; -if ((card->state !=CARD_STATE_UP ) || !card->lan_online) { card->stats.tx_carrier_errors++; goto tx_drop; } + queue =qeth_get_tx_queue (card, skb, ipv, cast_type); +if (card->options.performance_stats) { card->perf_stats.outbound_cnt++; card->perf_stats.outbound_start_time =qeth_get_micros ();
drivers/s390/net/qeth_l3_main.c +7 -9
@@ -1978,17 +1978,17 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb) (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST))return cast_type; -return RTN_UNSPEC ; +return RTN_UNICAST ; }rcu_read_unlock ();/* no neighbour (eg AF_PACKET), fall back to target's IP address ... */ if (be16_to_cpu (skb->protocol) ==ETH_P_IPV6 )return ipv6_addr_is_multicast (&ipv6_hdr (skb)->daddr) ? -RTN_MULTICAST :RTN_UNSPEC ; +RTN_MULTICAST :RTN_UNICAST ;else if (be16_to_cpu (skb->protocol) ==ETH_P_IP )return ipv4_is_multicast (ip_hdr (skb)->daddr) ? -RTN_MULTICAST :RTN_UNSPEC ; +RTN_MULTICAST :RTN_UNICAST ;/* ... and MAC address */ if (ether_addr_equal_64bits (eth_hdr (skb)->h_dest, skb->dev->broadcast))
@@ -1997,7 +1997,7 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)return RTN_MULTICAST ;/* default to unicast */ -return RTN_UNSPEC ; +return RTN_UNICAST ; } static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
@@ -2168,11 +2168,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,struct sk_buff *new_skb =NULL ;int ipv =qeth_get_ip_version (skb);int cast_type =qeth_l3_get_cast_type (skb); -struct qeth_qdio_out_q *queue = - card->qdio.out_qs[card->qdio.do_prio_queueing - || (cast_type && card->info.is_multicast_different) ? -qeth_get_priority_queue (card, skb, ipv, cast_type) : - card->qdio.default_out_queue]; +struct qeth_qdio_out_q *queue;int tx_bytes = skb->len;unsigned int hd_len =0 ;bool use_tso;
@@ -2195,6 +2191,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, (card->info.broadcast_capable == 0)) goto tx_drop; + queue =qeth_get_tx_queue (card, skb, ipv, cast_type); +if (card->options.performance_stats) { card->perf_stats.outbound_cnt++; card->perf_stats.outbound_start_time =qeth_get_micros ();
Signature · 1 line
2.16.4
PATCH 5/10 s390/qeth: consolidate ccwgroup driver definition
In reply to Julian WiedmannReshuffle the code a bit so that everything is in one place.
--- drivers/s390/net/qeth_core_main.c | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-)
drivers/s390/net/qeth_core_main.c +21 -21
@@ -5848,31 +5848,13 @@ static int qeth_core_restore(struct ccwgroup_device *gdev)return 0 ; } -static struct ccwgroup_driver qeth_core_ccwgroup_driver = { - .driver = { - .owner =THIS_MODULE , - .name ="qeth" , - }, - .ccw_driver = &qeth_ccw_driver, - .setup = qeth_core_probe_device, - .remove = qeth_core_remove_device, - .set_online = qeth_core_set_online, - .set_offline = qeth_core_set_offline, - .shutdown = qeth_core_shutdown, - .prepare =NULL , - .complete =NULL , - .freeze = qeth_core_freeze, - .thaw = qeth_core_thaw, - .restore = qeth_core_restore, -}; -static ssize_t group_store (struct device_driver *ddrv,const char *buf,size_t count) {int err; - err =ccwgroup_create_dev (qeth_core_root_dev, - &qeth_core_ccwgroup_driver,3 , buf); + err =ccwgroup_create_dev (qeth_core_root_dev,to_ccwgroupdrv (ddrv),3 , + buf);return err ? err : count; }
@@ -5890,6 +5872,25 @@ static const struct attribute_group *qeth_drv_attr_groups[] = { NULL, }; +static struct ccwgroup_driver qeth_core_ccwgroup_driver = { + .driver = { + .groups = qeth_drv_attr_groups, + .owner =THIS_MODULE , + .name ="qeth" , + }, + .ccw_driver = &qeth_ccw_driver, + .setup = qeth_core_probe_device, + .remove = qeth_core_remove_device, + .set_online = qeth_core_set_online, + .set_offline = qeth_core_set_offline, + .shutdown = qeth_core_shutdown, + .prepare =NULL , + .complete =NULL , + .freeze = qeth_core_freeze, + .thaw = qeth_core_thaw, + .restore = qeth_core_restore, +}; +int qeth_do_ioctl (struct net_device *dev,struct ifreq *rq,int cmd) {struct qeth_card *card = dev->ml_priv;
@@ -6581,7 +6582,6 @@ static int __init qeth_core_init(void) rc =ccw_driver_register (&qeth_ccw_driver);if (rc) goto ccw_err; - qeth_core_ccwgroup_driver.driver.groups = qeth_drv_attr_groups; rc =ccwgroup_driver_register (&qeth_core_ccwgroup_driver);if (rc) goto ccwgroup_err;
Signature · 1 line
2.16.4
PATCH 6/10 s390/qeth: clean up exported symbols
In reply to Julian WiedmannRemove some redundant EXPORTs. While at it, also move some L2-only prototypes into the proper header file.
--- drivers/s390/net/qeth_core.h | 6 ------ drivers/s390/net/qeth_core_main.c | 8 +++----- drivers/s390/net/qeth_l2.h | 5 +++++ drivers/s390/net/qeth_l2_main.c | 2 -- 4 files changed, 8 insertions(+), 13 deletions(-)
drivers/s390/net/qeth_core.h +0 -6
@@ -983,7 +983,6 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, void *);struct qeth_cmd_buffer *qeth_get_ipacmd_buffer (struct qeth_card *,enum qeth_ipa_cmds ,enum qeth_prot_versions ); -int qeth_query_setadapterparms (struct qeth_card *);struct sk_buff *qeth_core_get_next_skb (struct qeth_card *,struct qeth_qdio_buffer *,struct qdio_buffer_element **,int *,struct qeth_hdr **);
@@ -1009,10 +1008,6 @@ int qeth_query_switch_attributes(struct qeth_card *card,int qeth_send_control_data (struct qeth_card *,int ,struct qeth_cmd_buffer *,int (*reply_cb)(struct qeth_card *,struct qeth_reply *,unsigned long ),void *reply_param); -int qeth_bridgeport_query_ports (struct qeth_card *card, -enum qeth_sbp_roles *role,enum qeth_sbp_states *state); -int qeth_bridgeport_setrole (struct qeth_card *card,enum qeth_sbp_roles role); -int qeth_bridgeport_an_set (struct qeth_card *card,int enable);int qeth_get_elements_no (struct qeth_card *card,struct sk_buff *skb,int extra_elems,int data_offset);int qeth_get_elements_for_frags (struct sk_buff *);
@@ -1036,7 +1031,6 @@ int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);int qeth_hdr_chk_and_bounce (struct sk_buff *,struct qeth_hdr **,int );int qeth_configure_cq (struct qeth_card *,enum qeth_cq );int qeth_hw_trap (struct qeth_card *,enum qeth_diags_trap_action ); -int qeth_query_ipassists (struct qeth_card *,enum qeth_prot_versions prot);void qeth_trace_features (struct qeth_card *);void qeth_close_dev (struct qeth_card *); int qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *, __u16,
drivers/s390/net/qeth_core_main.c +3 -5
@@ -3054,7 +3054,7 @@ static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,return iob; } -int qeth_query_setadapterparms (struct qeth_card *card) +static int qeth_query_setadapterparms (struct qeth_card *card) {int rc;struct qeth_cmd_buffer *iob;
@@ -3067,7 +3067,6 @@ int qeth_query_setadapterparms(struct qeth_card *card) rc =qeth_send_ipa_cmd (card, iob, qeth_query_setadapterparms_cb,NULL );return rc; } -EXPORT_SYMBOL_GPL (qeth_query_setadapterparms);static int qeth_query_ipassists_cb (struct qeth_card *card,struct qeth_reply *reply,unsigned long data)
@@ -3107,7 +3106,8 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,return 0 ; } -int qeth_query_ipassists (struct qeth_card *card,enum qeth_prot_versions prot) +static int qeth_query_ipassists (struct qeth_card *card, +enum qeth_prot_versions prot) {int rc;struct qeth_cmd_buffer *iob;
@@ -3119,7 +3119,6 @@ int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) rc =qeth_send_ipa_cmd (card, iob, qeth_query_ipassists_cb,NULL );return rc; } -EXPORT_SYMBOL_GPL (qeth_query_ipassists);static int qeth_query_switch_attributes_cb (struct qeth_card *card,struct qeth_reply *reply,unsigned long data)
@@ -3158,7 +3157,6 @@ int qeth_query_switch_attributes(struct qeth_card *card,return qeth_send_ipa_cmd (card, iob, qeth_query_switch_attributes_cb, sw_info); } -EXPORT_SYMBOL_GPL (qeth_query_switch_attributes);static int qeth_query_setdiagass_cb (struct qeth_card *card,struct qeth_reply *reply,unsigned long data)
drivers/s390/net/qeth_l2.h +5 -0
@@ -14,6 +14,11 @@ extern const struct attribute_group *qeth_l2_attr_groups[];int qeth_l2_create_device_attributes (struct device *);void qeth_l2_remove_device_attributes (struct device *);void qeth_l2_setup_bridgeport_attrs (struct qeth_card *card); +int qeth_bridgeport_query_ports (struct qeth_card *card, +enum qeth_sbp_roles *role, +enum qeth_sbp_states *state); +int qeth_bridgeport_setrole (struct qeth_card *card,enum qeth_sbp_roles role); +int qeth_bridgeport_an_set (struct qeth_card *card,int enable);int qeth_l2_vnicc_set_state (struct qeth_card *card,u32 vnicc,bool state);int qeth_l2_vnicc_get_state (struct qeth_card *card,u32 vnicc,bool *state);
drivers/s390/net/qeth_l2_main.c +0 -2
@@ -1869,7 +1869,6 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,return rc;return qeth_bridgeport_makerc (card, &cbctl,IPA_SBP_QUERY_BRIDGE_PORTS ); } -EXPORT_SYMBOL_GPL (qeth_bridgeport_query_ports);static int qeth_bridgeport_set_cb (struct qeth_card *card,struct qeth_reply *reply,unsigned long data)
@@ -2017,7 +2016,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable) rc =qdio_pnso_brinfo (schid,0 , &response,NULL ,NULL );return qeth_anset_makerc (card, rc, response); } -EXPORT_SYMBOL_GPL (qeth_bridgeport_an_set);static bool qeth_bridgeport_is_in_use (struct qeth_card *card) {
Signature · 1 line
2.16.4
PATCH 7/10 s390/qeth: increase GSO max size for eligible L3 devices
In reply to Julian WiedmannWhen a L3 device doesn't offer TSO, allow the stack to build full-size GSO skbs.
--- drivers/s390/net/qeth_l3_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/s390/net/qeth_l3_main.c +3 -2
@@ -2536,8 +2536,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)NETIF_F_HW_VLAN_CTAG_RX |NETIF_F_HW_VLAN_CTAG_FILTER ;netif_keep_dst (card->dev); -netif_set_gso_max_size (card->dev, (QETH_MAX_BUFFER_ELEMENTS (card) -1 ) * -PAGE_SIZE ); +if (card->dev->hw_features &NETIF_F_TSO ) +netif_set_gso_max_size (card->dev, +PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS (card) -1 ));SET_NETDEV_DEV (card->dev, &card->gdev->dev);netif_napi_add (card->dev, &card->napi, qeth_poll,QETH_NAPI_WEIGHT );
Signature · 1 line
2.16.4
PATCH 8/10 s390/qeth: add a L3 xmit wrapper
In reply to Julian WiedmannIn preparation for future work, move the high-level xmit work into a separate wrapper. This matches the L2 xmit code.
--- drivers/s390/net/qeth_l3_main.c | 122 +++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 57 deletions(-)
drivers/s390/net/qeth_l3_main.c +65 -57
@@ -2156,48 +2156,21 @@ static int qeth_l3_get_elements_no_tso(struct qeth_card *card,return elements; } -static netdev_tx_t qeth_l3_hard_start_xmit (struct sk_buff *skb, -struct net_device *dev) +static int qeth_l3_xmit (struct qeth_card *card,struct sk_buff *skb, +struct qeth_qdio_out_q *queue,int ipv,int cast_type) {int rc;__be16 *tag;struct qeth_hdr *hdr =NULL ;int hdr_elements =0 ;int elements; -struct qeth_card *card = dev->ml_priv;struct sk_buff *new_skb =NULL ; -int ipv =qeth_get_ip_version (skb); -int cast_type =qeth_l3_get_cast_type (skb); -struct qeth_qdio_out_q *queue;int tx_bytes = skb->len;unsigned int hd_len =0 ;bool use_tso;int data_offset =-1 ;unsigned int nr_frags; -if (((card->info.type ==QETH_CARD_TYPE_IQD ) && - (((card->options.cq !=QETH_CQ_ENABLED ) && !ipv) || - ((card->options.cq ==QETH_CQ_ENABLED ) && - (be16_to_cpu (skb->protocol) !=ETH_P_AF_IUCV )))) || - card->options.sniffer) - goto tx_drop; - -if ((card->state !=CARD_STATE_UP ) || !card->lan_online) { - card->stats.tx_carrier_errors++; - goto tx_drop; - } - -if ((cast_type ==RTN_BROADCAST ) && - (card->info.broadcast_capable ==0 )) - goto tx_drop; - - queue =qeth_get_tx_queue (card, skb, ipv, cast_type); - -if (card->options.performance_stats) { - card->perf_stats.outbound_cnt++; - card->perf_stats.outbound_start_time =qeth_get_micros (); - } -/* Ignore segment size from skb_is_gso(), 1 page is always used. */ use_tso =skb_is_gso (skb) && (skb_shinfo (skb)->gso_type &SKB_GSO_TCPV4 );
@@ -2208,14 +2181,14 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, hd_len =sizeof (*hdr); hdr =kmem_cache_alloc (qeth_core_header_cache,GFP_ATOMIC );if (!hdr) - goto tx_drop; +return -ENOMEM ; hdr_elements++; }else {/* create a clone with writeable headroom */ new_skb =skb_realloc_headroom (skb,sizeof (struct qeth_hdr_tso ) +VLAN_HLEN );if (!new_skb) - goto tx_drop; +return -ENOMEM ;if (ipv ==4 ) {skb_pull (new_skb,ETH_HLEN );
@@ -2234,24 +2207,22 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, } } -netif_stop_queue (dev); -/* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists */ if ((card->info.type !=QETH_CARD_TYPE_IQD ) && ((use_tso && !qeth_l3_get_elements_no_tso (card, new_skb,1 )) || (!use_tso && !qeth_get_elements_no (card, new_skb,0 ,0 )))) { -int lin_rc =skb_linearize (new_skb); + rc =skb_linearize (new_skb);if (card->options.performance_stats) { -if (lin_rc) +if (rc) card->perf_stats.tx_linfail++;else card->perf_stats.tx_lin++; } -if (lin_rc) - goto tx_drop; +if (rc) + goto out; } nr_frags =skb_shinfo (new_skb)->nr_frags;
@@ -2290,9 +2261,8 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,qeth_get_elements_no (card, new_skb, hdr_elements, (data_offset >0 ) ? data_offset :0 );if (!elements) { -if (data_offset >=0 ) -kmem_cache_free (qeth_core_header_cache, hdr); - goto tx_drop; + rc = -E2BIG ; + goto out; } elements += hdr_elements;
@@ -2306,17 +2276,18 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, len =sizeof (struct qeth_hdr_layer3 ); } -if (qeth_hdr_chk_and_bounce (new_skb, &hdr, len)) - goto tx_drop; +if (qeth_hdr_chk_and_bounce (new_skb, &hdr, len)) { + rc = -EINVAL ; + goto out; + } rc =qeth_do_send_packet (card, queue, new_skb, hdr, hd_len, hd_len, elements); }else rc =qeth_do_send_packet_fast (queue, new_skb, hdr, data_offset, hd_len); +out:if (!rc) { - card->stats.tx_packets++; - card->stats.tx_bytes += tx_bytes;if (new_skb != skb)dev_kfree_skb_any (skb);if (card->options.performance_stats) {
@@ -2330,30 +2301,67 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, card->perf_stats.sg_frags_sent += nr_frags +1 ; } } - rc =NETDEV_TX_OK ; }else { +if (new_skb != skb) +dev_kfree_skb_any (new_skb);if (data_offset >=0 )kmem_cache_free (qeth_core_header_cache, hdr); + } +return rc; +} -if (rc == -EBUSY ) { -if (new_skb != skb) -dev_kfree_skb_any (new_skb); -return NETDEV_TX_BUSY ; - }else +static netdev_tx_t qeth_l3_hard_start_xmit (struct sk_buff *skb, +struct net_device *dev) +{ +int cast_type =qeth_l3_get_cast_type (skb); +struct qeth_card *card = dev->ml_priv; +int ipv =qeth_get_ip_version (skb); +struct qeth_qdio_out_q *queue; +int tx_bytes = skb->len; +int rc; + +if (IS_IQD (card)) { +if (card->options.sniffer) + goto tx_drop; +if ((card->options.cq !=QETH_CQ_ENABLED && !ipv) || + (card->options.cq ==QETH_CQ_ENABLED && + skb->protocol !=htons (ETH_P_AF_IUCV ))) goto tx_drop; } -netif_wake_queue (dev); -if (card->options.performance_stats) - card->perf_stats.outbound_time +=qeth_get_micros () - - card->perf_stats.outbound_start_time; -return rc; +if (card->state !=CARD_STATE_UP || !card->lan_online) { + card->stats.tx_carrier_errors++; + goto tx_drop; + } + +if (cast_type ==RTN_BROADCAST && !card->info.broadcast_capable) + goto tx_drop; + + queue =qeth_get_tx_queue (card, skb, ipv, cast_type); + +if (card->options.performance_stats) { + card->perf_stats.outbound_cnt++; + card->perf_stats.outbound_start_time =qeth_get_micros (); + } +netif_stop_queue (dev); + + rc =qeth_l3_xmit (card, skb, queue, ipv, cast_type); + +if (!rc) { + card->stats.tx_packets++; + card->stats.tx_bytes += tx_bytes; +if (card->options.performance_stats) + card->perf_stats.outbound_time +=qeth_get_micros () - + card->perf_stats.outbound_start_time; +netif_wake_queue (dev); +return NETDEV_TX_OK ; + }else if (rc == -EBUSY ) { +return NETDEV_TX_BUSY ; + }/* else fall through */ tx_drop: card->stats.tx_dropped++; card->stats.tx_errors++; -if ((new_skb != skb) && new_skb) -dev_kfree_skb_any (new_skb);dev_kfree_skb_any (skb);netif_wake_queue (dev);return NETDEV_TX_OK ;
Signature · 1 line
2.16.4
PATCH 9/10 s390/qeth: speed-up L3 IQD xmit
In reply to Julian WiedmannThis implements a new xmit path for L3 HiperSockets, which carves the HW header from skb headroom instead of allocating it from the hdr cache. It also adds NETIF_F_SG support.
The delta in qeth_l3_xmit() is all just removal of IQD-specific code and some minor consolidation.
--- drivers/s390/net/qeth_l3_main.c | 211 ++++++++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 83 deletions(-)
drivers/s390/net/qeth_l3_main.c +128 -83
@@ -2000,19 +2000,18 @@ static int qeth_l3_get_cast_type(struct sk_buff *skb)return RTN_UNICAST ; } -static void qeth_l3_fill_af_iucv_hdr (struct qeth_card *card, -struct qeth_hdr *hdr,struct sk_buff *skb) +static void qeth_l3_fill_af_iucv_hdr (struct qeth_hdr *hdr,struct sk_buff *skb, +unsigned int data_len) {char daddr[16 ];struct af_iucv_trans_hdr *iucv_hdr;memset (hdr,0 ,sizeof (struct qeth_hdr )); hdr->hdr.l3.id =QETH_HEADER_TYPE_LAYER3 ; - hdr->hdr.l3.ext_flags =0 ; - hdr->hdr.l3.length = skb->len -ETH_HLEN ; + hdr->hdr.l3.length = data_len; hdr->hdr.l3.flags =QETH_HDR_IPV6 |QETH_CAST_UNICAST ; - iucv_hdr = (struct af_iucv_trans_hdr *) (skb->data +ETH_HLEN ); + iucv_hdr = (struct af_iucv_trans_hdr *)(skb_mac_header (skb) +ETH_HLEN );memset (daddr,0 ,sizeof (daddr)); daddr[0 ] =0xfe ; daddr[1 ] =0x80 ;
@@ -2156,63 +2155,122 @@ static int qeth_l3_get_elements_no_tso(struct qeth_card *card,return elements; } +static int qeth_l3_xmit_offload (struct qeth_card *card,struct sk_buff *skb, +struct qeth_qdio_out_q *queue,int ipv, +int cast_type) +{ +const unsigned int hw_hdr_len =sizeof (struct qeth_hdr ); +unsigned int frame_len, nr_frags; +unsigned char eth_hdr[ETH_HLEN ]; +unsigned int hdr_elements =0 ; +struct qeth_hdr *hdr =NULL ; +unsigned int hd_len =0 ; +int push_len, rc; + +/* compress skb to fit into one IO buffer: */ +if (!qeth_get_elements_no (card, skb,0 ,0 )) { + rc =skb_linearize (skb); + +if (card->options.performance_stats) { +if (rc) + card->perf_stats.tx_linfail++; +else + card->perf_stats.tx_lin++; + } +if (rc) +return rc; + } + +/* re-use the L2 header area for the HW header: */ + rc =skb_cow_head (skb, hw_hdr_len -ETH_HLEN ); +if (rc) +return rc; +skb_copy_from_linear_data (skb, eth_hdr,ETH_HLEN ); +skb_pull (skb,ETH_HLEN ); + frame_len = skb->len; + nr_frags =skb_shinfo (skb)->nr_frags; + + push_len =qeth_push_hdr (skb, &hdr, hw_hdr_len); +if (push_len <0 ) +return push_len; +if (!push_len) { +/* hdr was added discontiguous from skb->data */ + hd_len = hw_hdr_len; + hdr_elements =1 ; + } + +if (!qeth_get_elements_no (card, skb, hdr_elements,0 )) { + rc = -E2BIG ; + goto out; + } + +if (skb->protocol ==htons (ETH_P_AF_IUCV )) +qeth_l3_fill_af_iucv_hdr (hdr, skb, frame_len); +else +qeth_l3_fill_header (card, hdr, skb, ipv, cast_type, frame_len); + + rc =qeth_do_send_packet_fast (queue, skb, hdr,0 , hd_len); +out: +if (!rc) { +if (card->options.performance_stats && nr_frags) { + card->perf_stats.sg_skbs_sent++; +/* nr_frags + skb->data */ + card->perf_stats.sg_frags_sent += nr_frags +1 ; + } + }else { +if (!push_len) +kmem_cache_free (qeth_core_header_cache, hdr); +if (rc == -EBUSY ) { +/* roll back to ETH header */ +skb_pull (skb, push_len); +skb_push (skb,ETH_HLEN ); +skb_copy_to_linear_data (skb, eth_hdr,ETH_HLEN ); + } + } +return rc; +} +static int qeth_l3_xmit (struct qeth_card *card,struct sk_buff *skb,struct qeth_qdio_out_q *queue,int ipv,int cast_type) { -int rc; +unsigned int hd_len, nr_frags; +int elements, len, rc;__be16 *tag;struct qeth_hdr *hdr =NULL ;int hdr_elements =0 ; -int elements;struct sk_buff *new_skb =NULL ;int tx_bytes = skb->len; -unsigned int hd_len =0 ;bool use_tso; -int data_offset =-1 ; -unsigned int nr_frags;/* Ignore segment size from skb_is_gso(), 1 page is always used. */ use_tso =skb_is_gso (skb) && (skb_shinfo (skb)->gso_type &SKB_GSO_TCPV4 ); -if (card->info.type ==QETH_CARD_TYPE_IQD ) { - new_skb = skb; - data_offset =ETH_HLEN ; - hd_len =sizeof (*hdr); - hdr =kmem_cache_alloc (qeth_core_header_cache,GFP_ATOMIC ); -if (!hdr) -return -ENOMEM ; - hdr_elements++; - }else { -/* create a clone with writeable headroom */ - new_skb =skb_realloc_headroom (skb,sizeof (struct qeth_hdr_tso ) - +VLAN_HLEN ); -if (!new_skb) -return -ENOMEM ; - -if (ipv ==4 ) { -skb_pull (new_skb,ETH_HLEN ); - } +/* create a clone with writeable headroom */ + new_skb =skb_realloc_headroom (skb,sizeof (struct qeth_hdr_tso ) + +VLAN_HLEN ); +if (!new_skb) +return -ENOMEM ; -if (ipv !=4 &&skb_vlan_tag_present (new_skb)) { -skb_push (new_skb,VLAN_HLEN ); -skb_copy_to_linear_data (new_skb, new_skb->data +4 ,4 ); -skb_copy_to_linear_data_offset (new_skb,4 , - new_skb->data +8 ,4 ); -skb_copy_to_linear_data_offset (new_skb,8 , - new_skb->data +12 ,4 ); - tag = (__be16 *)(new_skb->data +12 ); - *tag =cpu_to_be16 (ETH_P_8021Q ); - *(tag +1 ) =cpu_to_be16 (skb_vlan_tag_get (new_skb)); - } +if (ipv ==4 ) { +skb_pull (new_skb,ETH_HLEN ); + }else if (skb_vlan_tag_present (new_skb)) { +skb_push (new_skb,VLAN_HLEN ); +skb_copy_to_linear_data (new_skb, new_skb->data +4 ,4 ); +skb_copy_to_linear_data_offset (new_skb,4 , + new_skb->data +8 ,4 ); +skb_copy_to_linear_data_offset (new_skb,8 , + new_skb->data +12 ,4 ); + tag = (__be16 *)(new_skb->data +12 ); + *tag =cpu_to_be16 (ETH_P_8021Q ); + *(tag +1 ) =cpu_to_be16 (skb_vlan_tag_get (new_skb)); }/* fix hardware limitation: as long as we do not have sbal * chaining we can not send long frag lists */ -if ((card->info.type !=QETH_CARD_TYPE_IQD ) && - ((use_tso && !qeth_l3_get_elements_no_tso (card, new_skb,1 )) || - (!use_tso && !qeth_get_elements_no (card, new_skb,0 ,0 )))) { +if ((use_tso && !qeth_l3_get_elements_no_tso (card, new_skb,1 )) || + (!use_tso && !qeth_get_elements_no (card, new_skb,0 ,0 ))) { rc =skb_linearize (new_skb);if (card->options.performance_stats) {
@@ -2234,20 +2292,9 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb,qeth_tso_fill_header (card, hdr, new_skb); hdr_elements++; }else { -if (data_offset <0 ) { - hdr =skb_push (new_skb,sizeof (struct qeth_hdr )); -qeth_l3_fill_header (card, hdr, new_skb, ipv, cast_type, - new_skb->len - -sizeof (struct qeth_hdr )); - }else { -if (be16_to_cpu (new_skb->protocol) ==ETH_P_AF_IUCV ) -qeth_l3_fill_af_iucv_hdr (card, hdr, new_skb); -else { -qeth_l3_fill_header (card, hdr, new_skb, ipv, - cast_type, - new_skb->len - data_offset); - } - } + hdr =skb_push (new_skb,sizeof (struct qeth_hdr )); +qeth_l3_fill_header (card, hdr, new_skb, ipv, cast_type, + new_skb->len -sizeof (struct qeth_hdr ));if (new_skb->ip_summed ==CHECKSUM_PARTIAL ) {qeth_tx_csum (new_skb, &hdr->hdr.l3.ext_flags, ipv);
@@ -2258,34 +2305,28 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, elements = use_tso ?qeth_l3_get_elements_no_tso (card, new_skb, hdr_elements) : -qeth_get_elements_no (card, new_skb, hdr_elements, - (data_offset >0 ) ? data_offset :0 ); +qeth_get_elements_no (card, new_skb, hdr_elements,0 );if (!elements) { rc = -E2BIG ; goto out; } elements += hdr_elements; -if (card->info.type !=QETH_CARD_TYPE_IQD ) { -int len; -if (use_tso) { - hd_len =sizeof (struct qeth_hdr_tso ) + -ip_hdrlen (new_skb) +tcp_hdrlen (new_skb); - len = hd_len; - }else { - len =sizeof (struct qeth_hdr_layer3 ); - } - -if (qeth_hdr_chk_and_bounce (new_skb, &hdr, len)) { - rc = -EINVAL ; - goto out; - } - rc =qeth_do_send_packet (card, queue, new_skb, hdr, hd_len, - hd_len, elements); - }else - rc =qeth_do_send_packet_fast (queue, new_skb, hdr, data_offset, - hd_len); +if (use_tso) { + hd_len =sizeof (struct qeth_hdr_tso ) + +ip_hdrlen (new_skb) +tcp_hdrlen (new_skb); + len = hd_len; + }else { + hd_len =0 ; + len =sizeof (struct qeth_hdr_layer3 ); + } +if (qeth_hdr_chk_and_bounce (new_skb, &hdr, len)) { + rc = -EINVAL ; + goto out; + } + rc =qeth_do_send_packet (card, queue, new_skb, hdr, hd_len, hd_len, + elements); out:if (!rc) {if (new_skb != skb)
@@ -2304,8 +2345,6 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, }else {if (new_skb != skb)dev_kfree_skb_any (new_skb); -if (data_offset >=0 ) -kmem_cache_free (qeth_core_header_cache, hdr); }return rc; }
@@ -2345,7 +2384,10 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, }netif_stop_queue (dev); - rc =qeth_l3_xmit (card, skb, queue, ipv, cast_type); +if (IS_IQD (card)) + rc =qeth_l3_xmit_offload (card, skb, queue, ipv, cast_type); +else + rc =qeth_l3_xmit (card, skb, queue, ipv, cast_type);if (!rc) { card->stats.tx_packets++;
@@ -2503,9 +2545,6 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)if (!(card->info.unique_id &UNIQUE_ID_NOT_BY_CARD )) card->dev->dev_id = card->info.unique_id &0xffff ; - card->dev->hw_features |=NETIF_F_SG ; - card->dev->vlan_features |=NETIF_F_SG ; -if (!card->info.guestlan) { card->dev->features |=NETIF_F_SG ; card->dev->hw_features |= NETIF_F_TSO |
@@ -2524,7 +2563,10 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)if (!card->dev)return -ENODEV ; card->dev->flags |=IFF_NOARP ; + card->dev->priv_flags &= ~IFF_TX_SKB_SHARING ; card->dev->netdev_ops = &qeth_l3_netdev_ops; + card->dev->needed_headroom =sizeof (struct qeth_hdr ) -ETH_HLEN ; + rc =qeth_l3_iqd_read_initial_mac (card);if (rc)return rc;
@@ -2543,6 +2585,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->features |=NETIF_F_HW_VLAN_CTAG_TX |NETIF_F_HW_VLAN_CTAG_RX |NETIF_F_HW_VLAN_CTAG_FILTER ; + card->dev->hw_features |=NETIF_F_SG ; + card->dev->vlan_features |=NETIF_F_SG ; +netif_keep_dst (card->dev);if (card->dev->hw_features &NETIF_F_TSO ) netif_set_gso_max_size(card->dev,
Signature · 1 line
2.16.4
PATCH 10/10 s390/qeth: speed-up IPv4 OSA xmit
In reply to Julian WiedmannMove the xmit of offload-eligible (ie IPv4) traffic on OSA over to the new, copy-free path.
As with L2, we'll need to preserve the skb_orphan() behaviour of the old code path until TX completion is sufficiently fast.
--- drivers/s390/net/qeth_l3_main.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-)
drivers/s390/net/qeth_l3_main.c +21 -12
@@ -2050,6 +2050,12 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.vlan_id =skb_vlan_tag_get (skb); } +if (!skb_is_gso (skb) && skb->ip_summed ==CHECKSUM_PARTIAL ) { +qeth_tx_csum (skb, &hdr->hdr.l3.ext_flags, ipv); +if (card->options.performance_stats) + card->perf_stats.tx_csum++; + } +/* OSA only: */ if (!ipv) { hdr->hdr.l3.flags =QETH_HDR_PASSTHRU ;
@@ -2164,8 +2170,8 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb,unsigned char eth_hdr[ETH_HLEN ];unsigned int hdr_elements =0 ;struct qeth_hdr *hdr =NULL ; +int elements, push_len, rc;unsigned int hd_len =0 ; -int push_len, rc;/* compress skb to fit into one IO buffer: */ if (!qeth_get_elements_no (card, skb,0 ,0 )) {
@@ -2199,17 +2205,26 @@ static int qeth_l3_xmit_offload(struct qeth_card *card, struct sk_buff *skb, hdr_elements =1 ; } -if (!qeth_get_elements_no (card, skb, hdr_elements,0 )) { + elements =qeth_get_elements_no (card, skb, hdr_elements,0 ); +if (!elements) { rc = -E2BIG ; goto out; } + elements += hdr_elements;if (skb->protocol ==htons (ETH_P_AF_IUCV ))qeth_l3_fill_af_iucv_hdr (hdr, skb, frame_len);else qeth_l3_fill_header (card, hdr, skb, ipv, cast_type, frame_len); - rc =qeth_do_send_packet_fast (queue, skb, hdr,0 , hd_len); +if (IS_IQD (card)) { + rc =qeth_do_send_packet_fast (queue, skb, hdr,0 , hd_len); + }else { +/* TODO: drop skb_orphan() once TX completion is fast enough */ +skb_orphan (skb); + rc =qeth_do_send_packet (card, queue, skb, hdr,0 , hd_len, + elements); + } out:if (!rc) {if (card->options.performance_stats && nr_frags) {
@@ -2295,12 +2310,6 @@ static int qeth_l3_xmit(struct qeth_card *card, struct sk_buff *skb, hdr =skb_push (new_skb,sizeof (struct qeth_hdr ));qeth_l3_fill_header (card, hdr, new_skb, ipv, cast_type, new_skb->len -sizeof (struct qeth_hdr )); - -if (new_skb->ip_summed ==CHECKSUM_PARTIAL ) { -qeth_tx_csum (new_skb, &hdr->hdr.l3.ext_flags, ipv); -if (card->options.performance_stats) - card->perf_stats.tx_csum++; - } } elements = use_tso ?
@@ -2384,7 +2393,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, }netif_stop_queue (dev); -if (IS_IQD (card)) +if (IS_IQD (card) || (!skb_is_gso (skb) && ipv ==4 )) rc =qeth_l3_xmit_offload (card, skb, queue, ipv, cast_type);else rc =qeth_l3_xmit (card, skb, queue, ipv, cast_type);
@@ -2563,9 +2572,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)if (!card->dev)return -ENODEV ; card->dev->flags |=IFF_NOARP ; - card->dev->priv_flags &= ~IFF_TX_SKB_SHARING ; card->dev->netdev_ops = &qeth_l3_netdev_ops; - card->dev->needed_headroom =sizeof (struct qeth_hdr ) -ETH_HLEN ; rc =qeth_l3_iqd_read_initial_mac (card);if (rc)
@@ -2582,6 +2589,8 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->max_mtu =ETH_MAX_MTU ; card->dev->dev_port = card->info.portno; card->dev->ethtool_ops = &qeth_l3_ethtool_ops; + card->dev->priv_flags &= ~IFF_TX_SKB_SHARING ; + card->dev->needed_headroom =sizeof (struct qeth_hdr ) -ETH_HLEN ; card->dev->features |=NETIF_F_HW_VLAN_CTAG_TX |NETIF_F_HW_VLAN_CTAG_RX |NETIF_F_HW_VLAN_CTAG_FILTER ;
Signature · 1 line
2.16.4
David Miller
maintainerFrom: Julian Wiedmann <[email protected]>
Date: Wed, 11 Jul 2018 17:42:37 +0200
Quoted 2 lines
please apply this first batch of qeth patches for net-next. It brings the usual cleanups, and some performance improvements to the transmit paths.
Series applied, thank you.