OUT ipoib_endpt_t** const pp_src,\r
OUT ipoib_endpt_t** const pp_dst );\r
\r
-static uint32_t\r
+static int32_t\r
__recv_mgr_filter(\r
IN ipoib_port_t* const p_port,\r
IN ib_wc_t* const p_done_wc_list,\r
static uint32_t\r
__recv_mgr_build_pkt_array(\r
IN ipoib_port_t* const p_port,\r
- OUT cl_qlist_t* const p_done_list );\r
+ IN int32_t shortage,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT int32_t* const p_discarded );\r
\r
/******************************************************************************\r
*\r
\r
NdisChainBufferAtFront( p_packet, p_buffer );\r
NDIS_SET_PACKET_HEADER_SIZE( p_packet, sizeof(eth_hdr_t) );\r
- NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS );\r
\r
IPOIB_EXIT( IPOIB_DBG_RECV );\r
return p_packet;\r
}\r
\r
\r
-/* Posts receive buffers to the receive queue. */\r
-static ib_api_status_t\r
+/*\r
+ * Posts receive buffers to the receive queue and returns the number\r
+ * of receives needed to bring the RQ to its low water mark. Note\r
+ * that the value is signed, and can go negative. All tests must\r
+ * be for > 0.\r
+ */\r
+static int32_t\r
__recv_mgr_repost(\r
IN ipoib_port_t* const p_port )\r
{\r
cl_obj_unlock( &p_port->obj );\r
IPOIB_PRINT_EXIT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
("Port in invalid state. Not reposting.\n") );\r
- return IB_SUCCESS;\r
+ return 0;\r
}\r
cl_obj_ref( &p_port->obj );\r
cl_obj_unlock( &p_port->obj );\r
\r
p_head = p_next;\r
\r
- cl_atomic_inc( &p_port->recv_mgr.depth );\r
+ p_port->recv_mgr.depth++;\r
}\r
\r
- if( !p_head )\r
+ if( p_head )\r
{\r
- cl_obj_deref( &p_port->obj );\r
- IPOIB_EXIT( IPOIB_DBG_RECV );\r
- return IB_SUCCESS;\r
- }\r
-\r
- cl_perf_start( PostRecv );\r
- status = p_port->p_adapter->p_ifc->post_recv(\r
- p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );\r
- cl_perf_stop( &p_port->p_adapter->perf, PostRecv );\r
+ cl_perf_start( PostRecv );\r
+ status = p_port->p_adapter->p_ifc->post_recv(\r
+ p_port->ib_mgr.h_qp, &p_head->wr, &p_failed );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PostRecv );\r
\r
- /*\r
- * If we failed, fix up the work completion list and return those\r
- * buffers to the pool\r
- */\r
- if( status != IB_SUCCESS )\r
- {\r
- IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
- ("ip_post_recv returned %s\n", \r
- p_port->p_adapter->p_ifc->get_err_str( status )) );\r
- /* return the descriptors to the pool */\r
- while( p_failed )\r
+ if( status != IB_SUCCESS )\r
{\r
- p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );\r
- p_failed = p_failed->p_next;\r
+ IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
+ ("ip_post_recv returned %s\n", \r
+ p_port->p_adapter->p_ifc->get_err_str( status )) );\r
+ /* return the descriptors to the pool */\r
+ while( p_failed )\r
+ {\r
+ p_head = PARENT_STRUCT( p_failed, ipoib_recv_desc_t, wr );\r
+ p_failed = p_failed->p_next;\r
\r
- __buf_mgr_put_recv( p_port, p_head, NULL );\r
- cl_atomic_dec( &p_port->recv_mgr.depth );\r
+ __buf_mgr_put_recv( p_port, p_head, NULL );\r
+ p_port->recv_mgr.depth--;\r
+ }\r
}\r
}\r
\r
cl_obj_deref( &p_port->obj );\r
\r
IPOIB_EXIT( IPOIB_DBG_RECV );\r
- return status;\r
+ return p_port->p_adapter->params.rq_low_watermark - p_port->recv_mgr.depth;\r
}\r
\r
\r
ipoib_port_t *p_port;\r
ipoib_recv_desc_t *p_desc;\r
ib_api_status_t status = IB_NOT_DONE;\r
+ int32_t shortage;\r
PERF_DECLARE( ReturnPacket );\r
PERF_DECLARE( ReturnPutRecv );\r
PERF_DECLARE( ReturnRepostRecv );\r
\r
cl_perf_start( ReturnPacket );\r
\r
- /* Get the manager and descriptor from the packet. */\r
+ /* Get the port and descriptor from the packet. */\r
p_port = IPOIB_PORT_FROM_PACKET( p_packet );\r
p_desc = IPOIB_RECV_FROM_PACKET( p_packet );\r
\r
cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
cl_perf_start( ReturnPutRecv );\r
__buf_mgr_put_recv( p_port, p_desc, p_packet );\r
cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
\r
/* Repost buffers. */\r
cl_perf_start( ReturnRepostRecv );\r
- __recv_mgr_repost( p_port );\r
+ shortage = __recv_mgr_repost( p_port );\r
cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
\r
- /* Complete any additional receives waiting for a packet. */\r
- p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );\r
- do\r
+ for( p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );\r
+ p_item != cl_qlist_end( &p_port->recv_mgr.done_list );\r
+ p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list ) )\r
{\r
- if( p_item == cl_qlist_end( &p_port->recv_mgr.done_list ) )\r
- {\r
- cl_spinlock_release( &p_port->recv_lock );\r
- break;\r
- }\r
-\r
p_desc = (ipoib_recv_desc_t*)p_item;\r
\r
cl_perf_start( ReturnPreparePkt );\r
cl_perf_stop( &p_port->p_adapter->perf, ReturnPreparePkt );\r
if( status == IB_SUCCESS )\r
{\r
+ if( shortage > 0 )\r
+ NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_RESOURCES );\r
+ else\r
+ NDIS_SET_PACKET_STATUS( p_packet, NDIS_STATUS_SUCCESS );\r
+\r
cl_spinlock_release( &p_port->recv_lock );\r
cl_perf_start( ReturnNdisIndicate );\r
NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,\r
&p_packet, 1 );\r
cl_perf_stop( &p_port->p_adapter->perf, ReturnNdisIndicate );\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
+ if( shortage > 0 )\r
+ {\r
+ cl_perf_start( ReturnPutRecv );\r
+ __buf_mgr_put_recv( p_port, p_desc, p_packet );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnPutRecv );\r
+\r
+ /* Repost buffers. */\r
+ cl_perf_start( ReturnRepostRecv );\r
+ shortage = __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, ReturnRepostRecv );\r
+ }\r
}\r
else if( status != IB_NOT_DONE )\r
{\r
p_port->p_adapter->p_ifc->get_err_str( status )) );\r
/* Return the item to the head of the list. */\r
cl_qlist_insert_head( &p_port->recv_mgr.done_list, p_item );\r
- cl_spinlock_release( &p_port->recv_lock );\r
- }\r
- else\r
- {\r
- p_item = cl_qlist_remove_head( &p_port->recv_mgr.done_list );\r
+ break;\r
}\r
-\r
- } while( status == IB_NOT_DONE );\r
+ }\r
+ cl_spinlock_release( &p_port->recv_lock );\r
cl_perf_stop( &p_port->p_adapter->perf, ReturnPacket );\r
\r
IPOIB_EXIT( IPOIB_DBG_RECV );\r
ipoib_port_t *p_port;\r
ib_api_status_t status;\r
ib_wc_t wc[MAX_RECV_WC], *p_free, *p_wc;\r
- uint32_t pkt_cnt, recv_cnt = 0;\r
+ int32_t pkt_cnt, recv_cnt = 0, shortage, discarded;\r
cl_qlist_t done_list, bad_list;\r
size_t i;\r
PERF_DECLARE( RecvCompBundle );\r
/* We're done looking at the endpoint map, release the reference. */\r
cl_atomic_dec( &p_port->endpt_rdr );\r
\r
+ cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );\r
+\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+\r
/* Update our posted depth. */\r
- cl_atomic_sub( &p_port->recv_mgr.depth, recv_cnt );\r
+ p_port->recv_mgr.depth -= recv_cnt;\r
\r
- cl_perf_start( BuildPktArray );\r
- /* Notify NDIS of any and all possible receive buffers. */\r
- pkt_cnt = __recv_mgr_build_pkt_array( p_port, &done_list );\r
- cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray );\r
+ /* Return any discarded receives to the pool */\r
+ cl_perf_start( PutRecvList );\r
+ __buf_mgr_put_recv_list( p_port, &bad_list );\r
+ cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );\r
\r
- /* Only indicate receives if we actually had any. */\r
- if( pkt_cnt )\r
+ do\r
{\r
+ /* Repost ASAP so we don't starve the RQ. */\r
+ cl_perf_start( RepostRecv );\r
+ shortage = __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
+\r
+ cl_perf_start( BuildPktArray );\r
+ /* Notify NDIS of any and all possible receive buffers. */\r
+ pkt_cnt = __recv_mgr_build_pkt_array(\r
+ p_port, shortage, &done_list, &discarded );\r
+ cl_perf_stop( &p_port->p_adapter->perf, BuildPktArray );\r
+\r
+ /* Only indicate receives if we actually had any. */\r
+ if( discarded && shortage > 0 )\r
+ {\r
+ /* We may have thrown away packets, and have a shortage */\r
+ cl_perf_start( RepostRecv );\r
+ __recv_mgr_repost( p_port );\r
+ cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
+ }\r
+\r
+ if( !pkt_cnt )\r
+ break;\r
+\r
+ cl_spinlock_release( &p_port->recv_lock );\r
+\r
cl_perf_start( RecvNdisIndicate );\r
NdisMIndicateReceivePacket( p_port->p_adapter->h_adapter,\r
p_port->recv_mgr.recv_pkt_array, pkt_cnt );\r
cl_perf_stop( &p_port->p_adapter->perf, RecvNdisIndicate );\r
- }\r
\r
- cl_spinlock_acquire( &p_port->recv_lock );\r
+ /*\r
+ * Cap the number of receives to put back to what we just indicated\r
+ * with NDIS_STATUS_RESOURCES.\r
+ */\r
+ if( shortage > 0 )\r
+ {\r
+ if( pkt_cnt < shortage )\r
+ shortage = pkt_cnt;\r
\r
- /* Return any discarded receives to the pool */\r
- cl_perf_start( PutRecvList );\r
- __buf_mgr_put_recv_list( p_port, &bad_list );\r
- cl_perf_stop( &p_port->p_adapter->perf, PutRecvList );\r
+ /* Return all but the last packet to the pool. */\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
+ while( shortage-- > 1 )\r
+ {\r
+ __buf_mgr_put_recv( p_port,\r
+ IPOIB_RECV_FROM_PACKET( p_port->recv_mgr.recv_pkt_array[shortage] ),\r
+ p_port->recv_mgr.recv_pkt_array[shortage] );\r
+ }\r
+ cl_spinlock_release( &p_port->recv_lock );\r
\r
- /* Repost receives. */\r
- cl_perf_start( RepostRecv );\r
- __recv_mgr_repost( p_port );\r
- cl_perf_stop( &p_port->p_adapter->perf, RepostRecv );\r
+ /*\r
+ * Return the last packet as if NDIS returned it, so that we repost\r
+ * and report any other pending receives.\r
+ */\r
+ ipoib_return_packet( NULL, p_port->recv_mgr.recv_pkt_array[0] );\r
+ }\r
+ cl_spinlock_acquire( &p_port->recv_lock );\r
\r
+ } while( pkt_cnt );\r
cl_spinlock_release( &p_port->recv_lock );\r
\r
/*\r
cl_obj_deref( &p_port->obj );\r
\r
cl_perf_stop( &p_port->p_adapter->perf, RecvCb );\r
- cl_perf_log( &p_port->p_adapter->perf, RecvCompBundle, recv_cnt );\r
\r
IPOIB_EXIT( IPOIB_DBG_RECV );\r
}\r
}\r
\r
\r
-static uint32_t\r
+static int32_t\r
__recv_mgr_filter(\r
IN ipoib_port_t* const p_port,\r
IN ib_wc_t* const p_done_wc_list,\r
eth_pkt_t *p_eth;\r
ipoib_endpt_t *p_src, *p_dst;\r
ib_api_status_t status;\r
- uint32_t len, recv_cnt = 0;\r
+ uint32_t len;\r
+ int32_t recv_cnt = 0;\r
PERF_DECLARE( GetRecvEndpts );\r
PERF_DECLARE( RecvGen );\r
PERF_DECLARE( RecvTcp );\r
static uint32_t\r
__recv_mgr_build_pkt_array(\r
IN ipoib_port_t* const p_port,\r
- OUT cl_qlist_t* const p_done_list )\r
+ IN int32_t shortage,\r
+ OUT cl_qlist_t* const p_done_list,\r
+ OUT int32_t* const p_discarded )\r
{\r
cl_list_item_t *p_item;\r
ipoib_recv_desc_t *p_desc;\r
\r
IPOIB_ENTER( IPOIB_DBG_RECV );\r
\r
- cl_spinlock_acquire( &p_port->recv_lock );\r
+ *p_discarded = 0;\r
\r
/* Move any existing receives to the head to preserve ordering. */\r
cl_qlist_insert_list_head( p_done_list, &p_port->recv_mgr.done_list );\r
if( status == IB_SUCCESS )\r
{\r
CL_ASSERT( p_port->recv_mgr.recv_pkt_array[i] );\r
+ if( shortage-- > 0 )\r
+ {\r
+ NDIS_SET_PACKET_STATUS(\r
+ p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_RESOURCES );\r
+ }\r
+ else\r
+ {\r
+ NDIS_SET_PACKET_STATUS(\r
+ p_port->recv_mgr.recv_pkt_array[i], NDIS_STATUS_SUCCESS );\r
+ }\r
i++;\r
}\r
- else if( status != IB_NOT_DONE )\r
+ else if( status == IB_NOT_DONE )\r
+ {\r
+ (*p_discarded)++;\r
+ }\r
+ else\r
{\r
IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_RECV,\r
("__recv_mgr_prepare_pkt returned %s\n",\r
p_item = cl_qlist_remove_head( p_done_list );\r
}\r
\r
- cl_spinlock_release( &p_port->recv_lock );\r
-\r
IPOIB_EXIT( IPOIB_DBG_RECV );\r
return i;\r
}\r