cxgb4vf: FL Starvation Threshold needs to be larger than the SGE's Egress Congestion...
authorHariprasad Shenai <hariprasad@chelsio.com>
Fri, 7 Nov 2014 11:36:31 +0000 (17:06 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 10 Nov 2014 19:15:03 +0000 (14:15 -0500)
Free List Starvation Threshold needs to be larger than the SGE's Egress
Congestion Threshold or we'll end up in a mutual stall where the driver waits
for Ingress Packets to drive replacing Free List Pointers and the SGE waits for
Free List Pointers before pushing Ingress Packets to the host.

Based on original work by Casey Leedom <leedom@chelsio.com>

Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c

index cd5b7896cb67a942f973cba99d6af7877adbec69..fdd078d7d82c661ec5c63e8198c9ae6d464366c3 100644 (file)
@@ -93,12 +93,6 @@ enum {
        TX_QCHECK_PERIOD = (HZ / 2),
        MAX_TIMER_TX_RECLAIM = 100,
 
-       /*
-        * An FL with <= FL_STARVE_THRES buffers is starving and a periodic
-        * timer will attempt to refill it.
-        */
-       FL_STARVE_THRES = 4,
-
        /*
         * Suspend an Ethernet TX queue with fewer available descriptors than
         * this.  We always want to have room for a maximum sized packet:
@@ -2490,6 +2484,16 @@ int t4vf_sge_init(struct adapter *adapter)
                s->fl_align = max(ingpadboundary, ingpackboundary);
        }
 
+       /* A FL with <= fl_starve_thres buffers is starving and a periodic
+        * timer will attempt to refill it.  This needs to be larger than the
+        * SGE's Egress Congestion Threshold.  If it isn't, then we can get
+        * stuck waiting for new packets while the SGE is waiting for us to
+        * give it more Free List entries.  (Note that the SGE's Egress
+        * Congestion Threshold is in units of 2 Free List pointers.)
+        */
+       s->fl_starve_thres
+               = EGRTHRESHOLD_GET(sge_params->sge_congestion_control)*2 + 1;
+
        /*
         * Set up tasklet timers.
         */
index b5c301d9565e8f8cc8781098c81d8559ec2a6668..4b6a6d14d86d98df42bea1de5a6a507d9820374e 100644 (file)
@@ -140,6 +140,7 @@ struct sge_params {
        u32 sge_user_mode_limits;       /* limits for BAR2 user mode accesses */
        u32 sge_fl_buffer_size[16];     /* free list buffer sizes */
        u32 sge_ingress_rx_threshold;   /* RX counter interrupt threshold[4] */
+       u32 sge_congestion_control;     /* congestion thresholds, etc. */
        u32 sge_timer_value_0_and_1;    /* interrupt coalescing timer values */
        u32 sge_timer_value_2_and_3;
        u32 sge_timer_value_4_and_5;
index dc30d2852850941da1b865e5285f201846669069..1e896b923234f6d1b2e21da52fd73b010d45f214 100644 (file)
@@ -493,10 +493,13 @@ int t4vf_get_sge_params(struct adapter *adapter)
 
        params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
                     FW_PARAMS_PARAM_XYZ(SGE_INGRESS_RX_THRESHOLD));
-       v = t4vf_query_params(adapter, 1, params, vals);
+       params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) |
+                    FW_PARAMS_PARAM_XYZ(SGE_CONM_CTRL));
+       v = t4vf_query_params(adapter, 2, params, vals);
        if (v)
                return v;
        sge_params->sge_ingress_rx_threshold = vals[0];
+       sge_params->sge_congestion_control = vals[1];
 
        return 0;
 }