]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
cxgb4: Add MPS tracing support
[thirdparty/kernel/stable.git] / drivers / net / ethernet / chelsio / cxgb4 / t4_hw.c
index 91750ad580ae8fa66063d1ac7c4df9657b4e6ed1..ac368efe2862ac22d19e7da92f8ff1f7e0b0a8cf 100644 (file)
@@ -4264,6 +4264,119 @@ void t4_get_chan_txrate(struct adapter *adap, u64 *nic_rate, u64 *ofld_rate)
        }
 }
 
+/**
+ *     t4_set_trace_filter - configure one of the tracing filters
+ *     @adap: the adapter
+ *     @tp: the desired trace filter parameters
+ *     @idx: which filter to configure
+ *     @enable: whether to enable or disable the filter
+ *
+ *     Configures one of the tracing filters available in HW.  If @enable is
+ *     %0 @tp is not examined and may be %NULL. The user is responsible to
+ *     set the single/multiple trace mode by writing to MPS_TRC_CFG_A register
+ */
+int t4_set_trace_filter(struct adapter *adap, const struct trace_params *tp,
+                       int idx, int enable)
+{
+       int i, ofst = idx * 4;
+       u32 data_reg, mask_reg, cfg;
+       u32 multitrc = TRCMULTIFILTER_F;
+
+       if (!enable) {
+               t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 0);
+               return 0;
+       }
+
+       cfg = t4_read_reg(adap, MPS_TRC_CFG_A);
+       if (cfg & TRCMULTIFILTER_F) {
+               /* If multiple tracers are enabled, then maximum
+                * capture size is 2.5KB (FIFO size of a single channel)
+                * minus 2 flits for CPL_TRACE_PKT header.
+                */
+               if (tp->snap_len > ((10 * 1024 / 4) - (2 * 8)))
+                       return -EINVAL;
+       } else {
+               /* If multiple tracers are disabled, to avoid deadlocks
+                * maximum packet capture size of 9600 bytes is recommended.
+                * Also in this mode, only trace0 can be enabled and running.
+                */
+               multitrc = 0;
+               if (tp->snap_len > 9600 || idx)
+                       return -EINVAL;
+       }
+
+       if (tp->port > (is_t4(adap->params.chip) ? 11 : 19) || tp->invert > 1 ||
+           tp->skip_len > TFLENGTH_M || tp->skip_ofst > TFOFFSET_M ||
+           tp->min_len > TFMINPKTSIZE_M)
+               return -EINVAL;
+
+       /* stop the tracer we'll be changing */
+       t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst, 0);
+
+       idx *= (MPS_TRC_FILTER1_MATCH_A - MPS_TRC_FILTER0_MATCH_A);
+       data_reg = MPS_TRC_FILTER0_MATCH_A + idx;
+       mask_reg = MPS_TRC_FILTER0_DONT_CARE_A + idx;
+
+       for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
+               t4_write_reg(adap, data_reg, tp->data[i]);
+               t4_write_reg(adap, mask_reg, ~tp->mask[i]);
+       }
+       t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B_A + ofst,
+                    TFCAPTUREMAX_V(tp->snap_len) |
+                    TFMINPKTSIZE_V(tp->min_len));
+       t4_write_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst,
+                    TFOFFSET_V(tp->skip_ofst) | TFLENGTH_V(tp->skip_len) |
+                    (is_t4(adap->params.chip) ?
+                    TFPORT_V(tp->port) | TFEN_F | TFINVERTMATCH_V(tp->invert) :
+                    T5_TFPORT_V(tp->port) | T5_TFEN_F |
+                    T5_TFINVERTMATCH_V(tp->invert)));
+
+       return 0;
+}
+
+/**
+ *     t4_get_trace_filter - query one of the tracing filters
+ *     @adap: the adapter
+ *     @tp: the current trace filter parameters
+ *     @idx: which trace filter to query
+ *     @enabled: non-zero if the filter is enabled
+ *
+ *     Returns the current settings of one of the HW tracing filters.
+ */
+void t4_get_trace_filter(struct adapter *adap, struct trace_params *tp, int idx,
+                        int *enabled)
+{
+       u32 ctla, ctlb;
+       int i, ofst = idx * 4;
+       u32 data_reg, mask_reg;
+
+       ctla = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_A_A + ofst);
+       ctlb = t4_read_reg(adap, MPS_TRC_FILTER_MATCH_CTL_B_A + ofst);
+
+       if (is_t4(adap->params.chip)) {
+               *enabled = !!(ctla & TFEN_F);
+               tp->port =  TFPORT_G(ctla);
+               tp->invert = !!(ctla & TFINVERTMATCH_F);
+       } else {
+               *enabled = !!(ctla & T5_TFEN_F);
+               tp->port = T5_TFPORT_G(ctla);
+               tp->invert = !!(ctla & T5_TFINVERTMATCH_F);
+       }
+       tp->snap_len = TFCAPTUREMAX_G(ctlb);
+       tp->min_len = TFMINPKTSIZE_G(ctlb);
+       tp->skip_ofst = TFOFFSET_G(ctla);
+       tp->skip_len = TFLENGTH_G(ctla);
+
+       ofst = (MPS_TRC_FILTER1_MATCH_A - MPS_TRC_FILTER0_MATCH_A) * idx;
+       data_reg = MPS_TRC_FILTER0_MATCH_A + ofst;
+       mask_reg = MPS_TRC_FILTER0_DONT_CARE_A + ofst;
+
+       for (i = 0; i < TRACE_LEN / 4; i++, data_reg += 4, mask_reg += 4) {
+               tp->mask[i] = ~t4_read_reg(adap, mask_reg);
+               tp->data[i] = t4_read_reg(adap, data_reg) & tp->mask[i];
+       }
+}
+
 /**
  *     t4_pmtx_get_stats - returns the HW stats from PMTX
  *     @adap: the adapter