net: mscc: ocelot: fix oversize frame dropping for preemptible TCs
[platform/kernel/linux-rpi.git] / drivers / net / dsa / ocelot / felix_vsc9959.c
index d7caadd..1c11395 100644 (file)
@@ -1209,11 +1209,13 @@ static u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc)
 static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
 {
        struct ocelot_port *ocelot_port = ocelot->ports[port];
+       struct ocelot_mm_state *mm = &ocelot->mm[port];
        struct tc_taprio_qopt_offload *taprio;
        u64 min_gate_len[OCELOT_NUM_TC];
+       u32 val, maxlen, add_frag_size;
+       u64 needed_min_frag_time_ps;
        int speed, picos_per_byte;
        u64 needed_bit_time_ps;
-       u32 val, maxlen;
        u8 tas_speed;
        int tc;
 
@@ -1253,9 +1255,18 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
         */
        needed_bit_time_ps = (u64)(maxlen + 24) * picos_per_byte;
 
+       /* Preemptible TCs don't need to pass a full MTU, the port will
+        * automatically emit a HOLD request when a preemptible TC gate closes
+        */
+       val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port);
+       add_frag_size = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
+       needed_min_frag_time_ps = picos_per_byte *
+               (u64)(24 + 2 * ethtool_mm_frag_size_add_to_min(add_frag_size));
+
        dev_dbg(ocelot->dev,
-               "port %d: max frame size %d needs %llu ps at speed %d\n",
-               port, maxlen, needed_bit_time_ps, speed);
+               "port %d: max frame size %d needs %llu ps, %llu ps for mPackets at speed %d\n",
+               port, maxlen, needed_bit_time_ps, needed_min_frag_time_ps,
+               speed);
 
        vsc9959_tas_min_gate_lengths(taprio, min_gate_len);
 
@@ -1267,7 +1278,9 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
                remaining_gate_len_ps =
                        vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]);
 
-               if (remaining_gate_len_ps > needed_bit_time_ps) {
+               if ((mm->active_preemptible_tcs & BIT(tc)) ?
+                   remaining_gate_len_ps > needed_min_frag_time_ps :
+                   remaining_gate_len_ps > needed_bit_time_ps) {
                        /* Setting QMAXSDU_CFG to 0 disables oversized frame
                         * dropping.
                         */