net: ipa: add new most-significant bits to registers
authorAlex Elder <elder@linaro.org>
Wed, 25 Nov 2020 20:45:19 +0000 (14:45 -0600)
committerJakub Kicinski <kuba@kernel.org>
Sat, 28 Nov 2020 20:13:54 +0000 (12:13 -0800)
IPA v4.5 adds a few fields to the endpoint header and extended
header configuration registers that represent new high-order bits
for certain offsets and sizes.  Add code to incorporate these upper
bits into the registers for IPA v4.5.

This includes creating ipa_header_size_encoded(), which handles
encoding the metadata offset field for use in the ENDP_INIT_HDR
register in a way appropriate for the hardware version.  This and
ipa_metadata_offset_encoded() ensure the mask argument passed to
u32_encode_bits() is constant.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ipa/ipa_endpoint.c
drivers/net/ipa/ipa_reg.h

index 9707300..f28ea06 100644 (file)
@@ -485,28 +485,34 @@ static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint)
 static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
 {
        u32 offset = IPA_REG_ENDP_INIT_HDR_N_OFFSET(endpoint->endpoint_id);
+       struct ipa *ipa = endpoint->ipa;
        u32 val = 0;
 
        if (endpoint->data->qmap) {
                size_t header_size = sizeof(struct rmnet_map_header);
+               enum ipa_version version = ipa->version;
 
                /* We might supply a checksum header after the QMAP header */
                if (endpoint->toward_ipa && endpoint->data->checksum)
                        header_size += sizeof(struct rmnet_map_ul_csum_header);
-               val |= u32_encode_bits(header_size, HDR_LEN_FMASK);
+               val |= ipa_header_size_encoded(version, header_size);
 
                /* Define how to fill fields in a received QMAP header */
                if (!endpoint->toward_ipa) {
-                       u32 off;        /* Field offset within header */
+                       u32 offset;     /* Field offset within header */
 
                        /* Where IPA will write the metadata value */
-                       off = offsetof(struct rmnet_map_header, mux_id);
-                       val |= u32_encode_bits(off, HDR_OFST_METADATA_FMASK);
+                       offset = offsetof(struct rmnet_map_header, mux_id);
+                       val |= ipa_metadata_offset_encoded(version, offset);
 
                        /* Where IPA will write the length */
-                       off = offsetof(struct rmnet_map_header, pkt_len);
+                       offset = offsetof(struct rmnet_map_header, pkt_len);
+                       /* Upper bits are stored in HDR_EXT with IPA v4.5 */
+                       if (version == IPA_VERSION_4_5)
+                               offset &= field_mask(HDR_OFST_PKT_SIZE_FMASK);
+
                        val |= HDR_OFST_PKT_SIZE_VALID_FMASK;
-                       val |= u32_encode_bits(off, HDR_OFST_PKT_SIZE_FMASK);
+                       val |= u32_encode_bits(offset, HDR_OFST_PKT_SIZE_FMASK);
                }
                /* For QMAP TX, metadata offset is 0 (modem assumes this) */
                val |= HDR_OFST_METADATA_VALID_FMASK;
@@ -517,13 +523,14 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
                /* HDR_METADATA_REG_VALID is 0 (TX only) */
        }
 
-       iowrite32(val, endpoint->ipa->reg_virt + offset);
+       iowrite32(val, ipa->reg_virt + offset);
 }
 
 static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint)
 {
        u32 offset = IPA_REG_ENDP_INIT_HDR_EXT_N_OFFSET(endpoint->endpoint_id);
        u32 pad_align = endpoint->data->rx.pad_align;
+       struct ipa *ipa = endpoint->ipa;
        u32 val = 0;
 
        val |= HDR_ENDIANNESS_FMASK;            /* big endian */
@@ -545,10 +552,24 @@ static void ipa_endpoint_init_hdr_ext(struct ipa_endpoint *endpoint)
        if (!endpoint->toward_ipa)
                val |= u32_encode_bits(pad_align, HDR_PAD_TO_ALIGNMENT_FMASK);
 
-       iowrite32(val, endpoint->ipa->reg_virt + offset);
+       /* IPA v4.5 adds some most-significant bits to a few fields,
+        * two of which are defined in the HDR (not HDR_EXT) register.
+        */
+       if (ipa->version == IPA_VERSION_4_5) {
+               /* HDR_TOTAL_LEN_OR_PAD_OFFSET is 0, so MSB is 0 */
+               if (endpoint->data->qmap && !endpoint->toward_ipa) {
+                       u32 offset;
+
+                       offset = offsetof(struct rmnet_map_header, pkt_len);
+                       offset >>= hweight32(HDR_OFST_PKT_SIZE_FMASK);
+                       val |= u32_encode_bits(offset,
+                                              HDR_OFST_PKT_SIZE_MSB_FMASK);
+                       /* HDR_ADDITIONAL_CONST_LEN is 0 so MSB is 0 */
+               }
+       }
+       iowrite32(val, ipa->reg_virt + offset);
 }
 
-
 static void ipa_endpoint_init_hdr_metadata_mask(struct ipa_endpoint *endpoint)
 {
        u32 endpoint_id = endpoint->endpoint_id;
index f6ac988..7d10fa6 100644 (file)
@@ -367,6 +367,40 @@ enum ipa_cs_offload_en {
 #define HDR_LEN_MSB_FMASK                      GENMASK(29, 28)
 #define HDR_OFST_METADATA_MSB_FMASK            GENMASK(31, 30)
 
+/* Encoded value for ENDP_INIT_HDR register HDR_LEN* field(s) */
+static inline u32 ipa_header_size_encoded(enum ipa_version version,
+                                         u32 header_size)
+{
+       u32 val;
+
+       val = u32_encode_bits(header_size, HDR_LEN_FMASK);
+       if (version < IPA_VERSION_4_5)
+               return val;
+
+       /* IPA v4.5 adds a few more most-significant bits */
+       header_size >>= hweight32(HDR_LEN_FMASK);
+       val |= u32_encode_bits(header_size, HDR_LEN_MSB_FMASK);
+
+       return val;
+}
+
+/* Encoded value for ENDP_INIT_HDR register OFST_METADATA* field(s) */
+static inline u32 ipa_metadata_offset_encoded(enum ipa_version version,
+                                             u32 offset)
+{
+       u32 val;
+
+       val = u32_encode_bits(offset, HDR_OFST_METADATA_FMASK);
+       if (version < IPA_VERSION_4_5)
+               return val;
+
+       /* IPA v4.5 adds a few more most-significant bits */
+       offset >>= hweight32(HDR_OFST_METADATA_FMASK);
+       val |= u32_encode_bits(offset, HDR_OFST_METADATA_MSB_FMASK);
+
+       return val;
+}
+
 #define IPA_REG_ENDP_INIT_HDR_EXT_N_OFFSET(ep) \
                                        (0x00000814 + 0x0070 * (ep))
 #define HDR_ENDIANNESS_FMASK                   GENMASK(0, 0)
@@ -461,7 +495,7 @@ enum ipa_aggr_type {
 
 #define IPA_REG_ENDP_INIT_RSRC_GRP_N_OFFSET(ep) \
                                        (0x00000838 + 0x0070 * (ep))
-/* Encoded value for RSRC_GRP endpoint register RSRC_GRP field */
+/* Encoded value for ENDP_INIT_RSRC_GRP register RSRC_GRP field */
 static inline u32 rsrc_grp_encoded(enum ipa_version version, u32 rsrc_grp)
 {
        switch (version) {
@@ -492,7 +526,7 @@ static inline u32 rsrc_grp_encoded(enum ipa_version version, u32 rsrc_grp)
  * @IPA_SEQ_INVALID:           invalid sequencer type
  *
  * The values defined here are broken into 4-bit nibbles that are written
- * into fields of the INIT_SEQ_N endpoint registers.
+ * into fields of the ENDP_INIT_SEQ registers.
  */
 enum ipa_seq_type {
        IPA_SEQ_DMA_ONLY                        = 0x0000,