TCA_GRED_PARMS,
        TCA_GRED_STAB,
        TCA_GRED_DPS,
+       TCA_GRED_MAX_P,
           __TCA_GRED_MAX,
 };
 
        TCA_CHOKE_UNSPEC,
        TCA_CHOKE_PARMS,
        TCA_CHOKE_STAB,
+       TCA_CHOKE_MAX_P,
        __TCA_CHOKE_MAX,
 };
 
 
 
 static inline void red_set_parms(struct red_parms *p,
                                 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
-                                u8 Scell_log, u8 *stab)
+                                u8 Scell_log, u8 *stab, u32 max_P)
 {
        int delta = qth_max - qth_min;
+       u32 max_p_delta;
 
        /* Reset average queue length, the value is strictly bound
         * to the parameters below, reseting hurts a bit but leaving
        if (delta < 0)
                delta = 1;
        p->qth_delta    = delta;
-       p->max_P        = red_maxp(Plog);
-       p->max_P        *= delta; /* max_P = (qth_max-qth_min)/2^Plog */
-
-       p->max_P_reciprocal  = reciprocal_value(p->max_P / delta);
+       if (!max_P) {
+               max_P = red_maxp(Plog);
+               max_P *= delta; /* max_P = (qth_max - qth_min)/2^Plog */
+       }
+       p->max_P = max_P;
+       max_p_delta = max_P / delta;
+       max_p_delta = max(max_p_delta, 1U);
+       p->max_P_reciprocal  = reciprocal_value(max_p_delta);
 
        /* RED Adaptative target :
         * [min_th + 0.4*(min_th - max_th),
                p->max_P = (p->max_P/10)*9; /* maxp = maxp * Beta */
 
        max_p_delta = DIV_ROUND_CLOSEST(p->max_P, p->qth_delta);
+       max_p_delta = max(max_p_delta, 1U);
        p->max_P_reciprocal = reciprocal_value(max_p_delta);
 }
 #endif
 
 static const struct nla_policy choke_policy[TCA_CHOKE_MAX + 1] = {
        [TCA_CHOKE_PARMS]       = { .len = sizeof(struct tc_red_qopt) },
        [TCA_CHOKE_STAB]        = { .len = RED_STAB_SIZE },
+       [TCA_CHOKE_MAX_P]       = { .type = NLA_U32 },
 };
 
 
        int err;
        struct sk_buff **old = NULL;
        unsigned int mask;
+       u32 max_P;
 
        if (opt == NULL)
                return -EINVAL;
            tb[TCA_CHOKE_STAB] == NULL)
                return -EINVAL;
 
+       max_P = tb[TCA_CHOKE_MAX_P] ? nla_get_u32(tb[TCA_CHOKE_MAX_P]) : 0;
+
        ctl = nla_data(tb[TCA_CHOKE_PARMS]);
 
        if (ctl->limit > CHOKE_MAX_QUEUE)
 
        red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
                      ctl->Plog, ctl->Scell_log,
-                     nla_data(tb[TCA_CHOKE_STAB]));
+                     nla_data(tb[TCA_CHOKE_STAB]),
+                     max_P);
 
        if (q->head == q->tail)
                red_end_of_idle_period(&q->parms);
                goto nla_put_failure;
 
        NLA_PUT(skb, TCA_CHOKE_PARMS, sizeof(opt), &opt);
+       NLA_PUT_U32(skb, TCA_CHOKE_MAX_P, q->parms.max_P);
        return nla_nest_end(skb, opts);
 
 nla_put_failure:
 
 
 struct gred_sched_data {
        u32             limit;          /* HARD maximal queue length    */
-       u32             DP;             /* the drop pramaters */
+       u32             DP;             /* the drop parameters */
        u32             bytesin;        /* bytes seen on virtualQ so far*/
        u32             packetsin;      /* packets seen on virtualQ so far*/
        u32             backlog;        /* bytes on the virtualQ */
 }
 
 static inline int gred_change_vq(struct Qdisc *sch, int dp,
-                                struct tc_gred_qopt *ctl, int prio, u8 *stab)
+                                struct tc_gred_qopt *ctl, int prio,
+                                u8 *stab, u32 max_P)
 {
        struct gred_sched *table = qdisc_priv(sch);
        struct gred_sched_data *q;
 
        red_set_parms(&q->parms,
                      ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog,
-                     ctl->Scell_log, stab);
+                     ctl->Scell_log, stab, max_P);
 
        return 0;
 }
        [TCA_GRED_PARMS]        = { .len = sizeof(struct tc_gred_qopt) },
        [TCA_GRED_STAB]         = { .len = 256 },
        [TCA_GRED_DPS]          = { .len = sizeof(struct tc_gred_sopt) },
+       [TCA_GRED_MAX_P]        = { .type = NLA_U32 },
 };
 
 static int gred_change(struct Qdisc *sch, struct nlattr *opt)
        struct nlattr *tb[TCA_GRED_MAX + 1];
        int err, prio = GRED_DEF_PRIO;
        u8 *stab;
+       u32 max_P;
 
        if (opt == NULL)
                return -EINVAL;
            tb[TCA_GRED_STAB] == NULL)
                return -EINVAL;
 
+       max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0;
+
        err = -EINVAL;
        ctl = nla_data(tb[TCA_GRED_PARMS]);
        stab = nla_data(tb[TCA_GRED_STAB]);
 
        sch_tree_lock(sch);
 
-       err = gred_change_vq(sch, ctl->DP, ctl, prio, stab);
+       err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P);
        if (err < 0)
                goto errout_locked;
 
        struct gred_sched *table = qdisc_priv(sch);
        struct nlattr *parms, *opts = NULL;
        int i;
+       u32 max_p[MAX_DPs];
        struct tc_gred_sopt sopt = {
                .DPs    = table->DPs,
                .def_DP = table->def,
        if (opts == NULL)
                goto nla_put_failure;
        NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt);
+
+       for (i = 0; i < MAX_DPs; i++) {
+               struct gred_sched_data *q = table->tab[i];
+
+               max_p[i] = q ? q->parms.max_P : 0;
+       }
+       NLA_PUT(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p);
+
        parms = nla_nest_start(skb, TCA_GRED_PARMS);
        if (parms == NULL)
                goto nla_put_failure;
 
 static const struct nla_policy red_policy[TCA_RED_MAX + 1] = {
        [TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) },
        [TCA_RED_STAB]  = { .len = RED_STAB_SIZE },
+       [TCA_RED_MAX_P] = { .type = NLA_U32 },
 };
 
 static int red_change(struct Qdisc *sch, struct nlattr *opt)
        struct tc_red_qopt *ctl;
        struct Qdisc *child = NULL;
        int err;
+       u32 max_P;
 
        if (opt == NULL)
                return -EINVAL;
            tb[TCA_RED_STAB] == NULL)
                return -EINVAL;
 
+       max_P = tb[TCA_RED_MAX_P] ? nla_get_u32(tb[TCA_RED_MAX_P]) : 0;
+
        ctl = nla_data(tb[TCA_RED_PARMS]);
 
        if (ctl->limit > 0) {
        }
 
        red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog,
-                                ctl->Plog, ctl->Scell_log,
-                                nla_data(tb[TCA_RED_STAB]));
+                     ctl->Plog, ctl->Scell_log,
+                     nla_data(tb[TCA_RED_STAB]),
+                     max_P);
 
        del_timer(&q->adapt_timer);
        if (ctl->flags & TC_RED_ADAPTATIVE)