Merge tag 'arc-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
[cascardo/linux.git] / drivers / net / ethernet / chelsio / cxgb4vf / t4vf_hw.c
index 5422011..fed83d8 100644 (file)
@@ -417,6 +417,61 @@ int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
        return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
 }
 
+/**
+ *     t4vf_fl_pkt_align - return the fl packet alignment
+ *     @adapter: the adapter
+ *
+ *     T4 has a single field to specify the packing and padding boundary.
+ *     T5 onwards has separate fields for this and hence the alignment for
+ *     next packet offset is maximum of these two.  And T6 changes the
+ *     Ingress Padding Boundary Shift, so it's all a mess and it's best
+ *     if we put this in low-level Common Code ...
+ *
+ */
+int t4vf_fl_pkt_align(struct adapter *adapter)
+{
+       u32 sge_control, sge_control2;
+       unsigned int ingpadboundary, ingpackboundary, fl_align, ingpad_shift;
+
+       sge_control = adapter->params.sge.sge_control;
+
+       /* T4 uses a single control field to specify both the PCIe Padding and
+        * Packing Boundary.  T5 introduced the ability to specify these
+        * separately.  The actual Ingress Packet Data alignment boundary
+        * within Packed Buffer Mode is the maximum of these two
+        * specifications.  (Note that it makes no real practical sense to
+        * have the Pading Boudary be larger than the Packing Boundary but you
+        * could set the chip up that way and, in fact, legacy T4 code would
+        * end doing this because it would initialize the Padding Boundary and
+        * leave the Packing Boundary initialized to 0 (16 bytes).)
+        * Padding Boundary values in T6 starts from 8B,
+        * where as it is 32B for T4 and T5.
+        */
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+               ingpad_shift = INGPADBOUNDARY_SHIFT_X;
+       else
+               ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
+
+       ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + ingpad_shift);
+
+       fl_align = ingpadboundary;
+       if (!is_t4(adapter->params.chip)) {
+               /* T5 has a different interpretation of one of the PCIe Packing
+                * Boundary values.
+                */
+               sge_control2 = adapter->params.sge.sge_control2;
+               ingpackboundary = INGPACKBOUNDARY_G(sge_control2);
+               if (ingpackboundary == INGPACKBOUNDARY_16B_X)
+                       ingpackboundary = 16;
+               else
+                       ingpackboundary = 1 << (ingpackboundary +
+                                               INGPACKBOUNDARY_SHIFT_X);
+
+               fl_align = max(ingpadboundary, ingpackboundary);
+       }
+       return fl_align;
+}
+
 /**
  *     t4vf_bar2_sge_qregs - return BAR2 SGE Queue register information
  *     @adapter: the adapter