3333
3434#include <net/iucv/af_iucv.h>
3535#include <net/dsfield.h>
36+ #include <net/sock.h>
3637
3738#include <asm/ebcdic.h>
3839#include <asm/chpid.h>
@@ -499,17 +500,12 @@ static void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q, int bidx,
499500
500501 }
501502 }
502- if (forced_cleanup && (atomic_read (& (q -> bufs [bidx ]-> state )) ==
503- QETH_QDIO_BUF_HANDLED_DELAYED )) {
504- /* for recovery situations */
505- qeth_init_qdio_out_buf (q , bidx );
506- QETH_CARD_TEXT (q -> card , 2 , "clprecov" );
507- }
508503}
509504
510505static void qeth_qdio_handle_aob (struct qeth_card * card ,
511506 unsigned long phys_aob_addr )
512507{
508+ enum qeth_qdio_out_buffer_state new_state = QETH_QDIO_BUF_QAOB_OK ;
513509 struct qaob * aob ;
514510 struct qeth_qdio_out_buffer * buffer ;
515511 enum iucv_tx_notify notification ;
@@ -521,22 +517,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
521517 buffer = (struct qeth_qdio_out_buffer * ) aob -> user1 ;
522518 QETH_CARD_TEXT_ (card , 5 , "%lx" , aob -> user1 );
523519
524- if (atomic_cmpxchg (& buffer -> state , QETH_QDIO_BUF_PRIMED ,
525- QETH_QDIO_BUF_IN_CQ ) == QETH_QDIO_BUF_PRIMED ) {
526- notification = TX_NOTIFY_OK ;
527- } else {
528- WARN_ON_ONCE (atomic_read (& buffer -> state ) !=
529- QETH_QDIO_BUF_PENDING );
530- atomic_set (& buffer -> state , QETH_QDIO_BUF_IN_CQ );
531- notification = TX_NOTIFY_DELAYED_OK ;
532- }
533-
534- if (aob -> aorc != 0 ) {
535- QETH_CARD_TEXT_ (card , 2 , "aorc%02X" , aob -> aorc );
536- notification = qeth_compute_cq_notification (aob -> aorc , 1 );
537- }
538- qeth_notify_skbs (buffer -> q , buffer , notification );
539-
540520 /* Free dangling allocations. The attached skbs are handled by
541521 * qeth_cleanup_handled_pending().
542522 */
@@ -548,7 +528,33 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,
548528 if (data && buffer -> is_header [i ])
549529 kmem_cache_free (qeth_core_header_cache , data );
550530 }
551- atomic_set (& buffer -> state , QETH_QDIO_BUF_HANDLED_DELAYED );
531+
532+ if (aob -> aorc ) {
533+ QETH_CARD_TEXT_ (card , 2 , "aorc%02X" , aob -> aorc );
534+ new_state = QETH_QDIO_BUF_QAOB_ERROR ;
535+ }
536+
537+ switch (atomic_xchg (& buffer -> state , new_state )) {
538+ case QETH_QDIO_BUF_PRIMED :
539+ /* Faster than TX completion code. */
540+ notification = qeth_compute_cq_notification (aob -> aorc , 0 );
541+ qeth_notify_skbs (buffer -> q , buffer , notification );
542+ atomic_set (& buffer -> state , QETH_QDIO_BUF_HANDLED_DELAYED );
543+ break ;
544+ case QETH_QDIO_BUF_PENDING :
545+ /* TX completion code is active and will handle the async
546+ * completion for us.
547+ */
548+ break ;
549+ case QETH_QDIO_BUF_NEED_QAOB :
550+ /* TX completion code is already finished. */
551+ notification = qeth_compute_cq_notification (aob -> aorc , 1 );
552+ qeth_notify_skbs (buffer -> q , buffer , notification );
553+ atomic_set (& buffer -> state , QETH_QDIO_BUF_HANDLED_DELAYED );
554+ break ;
555+ default :
556+ WARN_ON_ONCE (1 );
557+ }
552558
553559 qdio_release_aob (aob );
554560}
@@ -1405,7 +1411,7 @@ static void qeth_notify_skbs(struct qeth_qdio_out_q *q,
14051411 skb_queue_walk (& buf -> skb_list , skb ) {
14061412 QETH_CARD_TEXT_ (q -> card , 5 , "skbn%d" , notification );
14071413 QETH_CARD_TEXT_ (q -> card , 5 , "%lx" , (long ) skb );
1408- if (skb -> protocol == htons ( ETH_P_AF_IUCV ) && skb -> sk )
1414+ if (skb -> sk && skb -> sk -> sk_family == PF_IUCV )
14091415 iucv_sk (skb -> sk )-> sk_txnotify (skb , notification );
14101416 }
14111417}
@@ -1416,9 +1422,6 @@ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error,
14161422 struct qeth_qdio_out_q * queue = buf -> q ;
14171423 struct sk_buff * skb ;
14181424
1419- /* release may never happen from within CQ tasklet scope */
1420- WARN_ON_ONCE (atomic_read (& buf -> state ) == QETH_QDIO_BUF_IN_CQ );
1421-
14221425 if (atomic_read (& buf -> state ) == QETH_QDIO_BUF_PENDING )
14231426 qeth_notify_skbs (queue , buf , TX_NOTIFY_GENERALERROR );
14241427
@@ -5869,9 +5872,32 @@ static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue,
58695872
58705873 if (atomic_cmpxchg (& buffer -> state , QETH_QDIO_BUF_PRIMED ,
58715874 QETH_QDIO_BUF_PENDING ) ==
5872- QETH_QDIO_BUF_PRIMED )
5875+ QETH_QDIO_BUF_PRIMED ) {
58735876 qeth_notify_skbs (queue , buffer , TX_NOTIFY_PENDING );
58745877
5878+ /* Handle race with qeth_qdio_handle_aob(): */
5879+ switch (atomic_xchg (& buffer -> state ,
5880+ QETH_QDIO_BUF_NEED_QAOB )) {
5881+ case QETH_QDIO_BUF_PENDING :
5882+ /* No concurrent QAOB notification. */
5883+ break ;
5884+ case QETH_QDIO_BUF_QAOB_OK :
5885+ qeth_notify_skbs (queue , buffer ,
5886+ TX_NOTIFY_DELAYED_OK );
5887+ atomic_set (& buffer -> state ,
5888+ QETH_QDIO_BUF_HANDLED_DELAYED );
5889+ break ;
5890+ case QETH_QDIO_BUF_QAOB_ERROR :
5891+ qeth_notify_skbs (queue , buffer ,
5892+ TX_NOTIFY_DELAYED_GENERALERROR );
5893+ atomic_set (& buffer -> state ,
5894+ QETH_QDIO_BUF_HANDLED_DELAYED );
5895+ break ;
5896+ default :
5897+ WARN_ON_ONCE (1 );
5898+ }
5899+ }
5900+
58755901 QETH_CARD_TEXT_ (card , 5 , "pel%u" , bidx );
58765902
58775903 /* prepare the queue slot for re-use: */
0 commit comments