Author: np
Date: Tue May  2 20:38:10 2017
New Revision: 317702
URL: https://svnweb.freebsd.org/changeset/base/317702

Log:
  cxgbe(4): Support routines for Tx traffic scheduling.
  
  - Create a new file, t4_sched.c, and move all of the code related to
    traffic management from t4_main.c and t4_sge.c to this file.
  - Track both Channel Rate Limiter (ch_rl) and Class Rate Limiter (cl_rl)
    parameters in the PF driver.
  - Initialize all the cl_rl limiters with somewhat arbitrary default
    rates and provide routines to update them on the fly.
  - Provide routines to reserve and release traffic classes.
  
  MFC after:    1 month
  Sponsored by: Chelsio Communications

Added:
  head/sys/dev/cxgbe/t4_sched.c   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/cxgbe/adapter.h
  head/sys/dev/cxgbe/common/common.h
  head/sys/dev/cxgbe/common/t4_hw.c
  head/sys/dev/cxgbe/t4_main.c
  head/sys/dev/cxgbe/t4_sge.c
  head/sys/dev/cxgbe/t4_vf.c
  head/sys/modules/cxgbe/if_cxgbe/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Tue May  2 20:08:04 2017        (r317701)
+++ head/sys/conf/files Tue May  2 20:38:10 2017        (r317702)
@@ -1331,6 +1331,8 @@ dev/cxgbe/t4_main.c               optional cxgbe pci 
        compile-with "${NORMAL_C} -I$S/dev/cxgbe"
 dev/cxgbe/t4_netmap.c          optional cxgbe pci \
        compile-with "${NORMAL_C} -I$S/dev/cxgbe"
+dev/cxgbe/t4_sched.c           optional cxgbe pci \
+       compile-with "${NORMAL_C} -I$S/dev/cxgbe"
 dev/cxgbe/t4_sge.c             optional cxgbe pci \
        compile-with "${NORMAL_C} -I$S/dev/cxgbe"
 dev/cxgbe/t4_l2t.c             optional cxgbe pci \

Modified: head/sys/dev/cxgbe/adapter.h
==============================================================================
--- head/sys/dev/cxgbe/adapter.h        Tue May  2 20:08:04 2017        
(r317701)
+++ head/sys/dev/cxgbe/adapter.h        Tue May  2 20:38:10 2017        
(r317702)
@@ -231,15 +231,36 @@ struct vi_info {
        uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */
 };
 
+struct tx_ch_rl_params {
+       enum fw_sched_params_rate ratemode;     /* %port (REL) or kbps (ABS) */
+       uint32_t maxrate;
+};
+
 enum {
-       /* tx_sched_class flags */
-       TX_SC_OK        = (1 << 0),     /* Set up in hardware, active. */
+       TX_CLRL_REFRESH = (1 << 0),     /* Need to update hardware state. */
+       TX_CLRL_ERROR   = (1 << 1),     /* Error, hardware state unknown. */
 };
 
-struct tx_sched_class {
+struct tx_cl_rl_params {
        int refcount;
-       int flags;
-       struct t4_sched_class_params params;
+       u_int flags;
+       enum fw_sched_params_rate ratemode;     /* %port REL or ABS value */
+       enum fw_sched_params_unit rateunit;     /* kbps or pps (when ABS) */
+       enum fw_sched_params_mode mode;         /* aggr or per-flow */
+       uint32_t maxrate;
+       uint16_t pktsize;
+};
+
+/* Tx scheduler parameters for a channel/port */
+struct tx_sched_params {
+       /* Channel Rate Limiter */
+       struct tx_ch_rl_params ch_rl;
+
+       /* Class WRR */
+       /* XXX */
+
+       /* Class Rate Limiter */
+       struct tx_cl_rl_params cl_rl[];
 };
 
 struct port_info {
@@ -251,7 +272,7 @@ struct port_info {
        int up_vis;
        int uld_vis;
 
-       struct tx_sched_class *tc;      /* traffic classes for this channel */
+       struct tx_sched_params *sched_params;
 
        struct mtx pi_lock;
        char lockname[16];
@@ -825,6 +846,9 @@ struct adapter {
 
        struct memwin memwin[NUM_MEMWIN];       /* memory windows */
 
+       struct mtx tc_lock;
+       struct task tc_task;
+
        const char *last_op;
        const void *last_op_thr;
        int last_op_flags;
@@ -1106,8 +1130,6 @@ int t4_detach_common(device_t);
 int t4_filter_rpl(struct sge_iq *, const struct rss_header *, struct mbuf *);
 int t4_map_bars_0_and_4(struct adapter *);
 int t4_map_bar_2(struct adapter *);
-int t4_set_sched_class(struct adapter *, struct t4_sched_params *);
-int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *);
 int t4_setup_intr_handlers(struct adapter *);
 void t4_sysctls(struct adapter *);
 int begin_synchronized_op(struct adapter *, struct vi_info *, int, char *);
@@ -1168,6 +1190,15 @@ int t4_set_tracer(struct adapter *, stru
 int t4_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *);
 int t5_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *);
 
+/* t4_sched.c */
+int t4_set_sched_class(struct adapter *, struct t4_sched_params *);
+int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *);
+int t4_init_tx_sched(struct adapter *);
+int t4_free_tx_sched(struct adapter *);
+void t4_update_tx_sched(struct adapter *);
+int t4_reserve_cl_rl_kbps(struct adapter *, int, u_int, int *);
+void t4_release_cl_rl_kbps(struct adapter *, int, int);
+
 static inline struct wrqe *
 alloc_wrqe(int wr_len, struct sge_wrq *wrq)
 {

Modified: head/sys/dev/cxgbe/common/common.h
==============================================================================
--- head/sys/dev/cxgbe/common/common.h  Tue May  2 20:08:04 2017        
(r317701)
+++ head/sys/dev/cxgbe/common/common.h  Tue May  2 20:38:10 2017        
(r317702)
@@ -774,6 +774,13 @@ int t4_sched_params(struct adapter *adap
                    int rateunit, int ratemode, int channel, int cl,
                    int minrate, int maxrate, int weight, int pktsize,
                    int sleep_ok);
+int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode,
+                         unsigned int maxrate, int sleep_ok);
+int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl,
+                          int weight, int sleep_ok);
+int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl,
+                              int mode, unsigned int maxrate, int pktsize,
+                              int sleep_ok);
 int t4_config_watchdog(struct adapter *adapter, unsigned int mbox,
                       unsigned int pf, unsigned int vf,
                       unsigned int timeout, unsigned int action);

Modified: head/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- head/sys/dev/cxgbe/common/t4_hw.c   Tue May  2 20:08:04 2017        
(r317701)
+++ head/sys/dev/cxgbe/common/t4_hw.c   Tue May  2 20:38:10 2017        
(r317702)
@@ -9396,6 +9396,79 @@ int t4_sched_params(struct adapter *adap
                               NULL, sleep_ok);
 }
 
+int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode,
+    unsigned int maxrate, int sleep_ok)
+{
+       struct fw_sched_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
+                                     F_FW_CMD_REQUEST |
+                                     F_FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+       cmd.u.params.sc = FW_SCHED_SC_PARAMS;
+       cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED;
+       cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CH_RL;
+       cmd.u.params.ch = channel;
+       cmd.u.params.rate = ratemode;           /* REL or ABS */
+       cmd.u.params.max = cpu_to_be32(maxrate);/*  %  or kbps */
+
+       return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
+                              NULL, sleep_ok);
+}
+
+int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl,
+    int weight, int sleep_ok)
+{
+       struct fw_sched_cmd cmd;
+
+       if (weight < 0 || weight > 100)
+               return -EINVAL;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
+                                     F_FW_CMD_REQUEST |
+                                     F_FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+       cmd.u.params.sc = FW_SCHED_SC_PARAMS;
+       cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED;
+       cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
+       cmd.u.params.ch = channel;
+       cmd.u.params.cl = cl;
+       cmd.u.params.weight = cpu_to_be16(weight);
+
+       return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
+                              NULL, sleep_ok);
+}
+
+int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl,
+    int mode, unsigned int maxrate, int pktsize, int sleep_ok)
+{
+       struct fw_sched_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
+                                     F_FW_CMD_REQUEST |
+                                     F_FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+       cmd.u.params.sc = FW_SCHED_SC_PARAMS;
+       cmd.u.params.type = FW_SCHED_TYPE_PKTSCHED;
+       cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_RL;
+       cmd.u.params.mode = mode;
+       cmd.u.params.ch = channel;
+       cmd.u.params.cl = cl;
+       cmd.u.params.unit = FW_SCHED_PARAMS_UNIT_BITRATE;
+       cmd.u.params.rate = FW_SCHED_PARAMS_RATE_ABS;
+       cmd.u.params.max = cpu_to_be32(maxrate);
+       cmd.u.params.pktsize = cpu_to_be16(pktsize);
+
+       return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
+                              NULL, sleep_ok);
+}
+
 /*
  *     t4_config_watchdog - configure (enable/disable) a watchdog timer
  *     @adapter: the adapter

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c        Tue May  2 20:08:04 2017        
(r317701)
+++ head/sys/dev/cxgbe/t4_main.c        Tue May  2 20:38:10 2017        
(r317702)
@@ -998,9 +998,6 @@ t4_attach(device_t dev)
                mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
                sc->chan_map[pi->tx_chan] = i;
 
-               pi->tc = malloc(sizeof(struct tx_sched_class) *
-                   sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK);
-
                if (port_top_speed(pi) >= 10) {
                        n10g++;
                } else {
@@ -1088,6 +1085,7 @@ t4_attach(device_t dev)
            M_ZERO | M_WAITOK);
 
        t4_init_l2t(sc, M_WAITOK);
+       t4_init_tx_sched(sc);
 
        /*
         * Second pass over the ports.  This time we know the number of rx and
@@ -1312,6 +1310,9 @@ t4_detach_common(device_t dev)
        for (i = 0; i < sc->intr_count; i++)
                t4_free_irq(sc, &sc->irq[i]);
 
+       if ((sc->flags & (IS_VF | FW_OK)) == FW_OK)
+               t4_free_tx_sched(sc);
+
        for (i = 0; i < MAX_NPORTS; i++) {
                pi = sc->port[i];
                if (pi) {
@@ -1321,7 +1322,6 @@ t4_detach_common(device_t dev)
 
                        mtx_destroy(&pi->pi_lock);
                        free(pi->vi, M_CXGBE);
-                       free(pi->tc, M_CXGBE);
                        free(pi, M_CXGBE);
                }
        }
@@ -5338,9 +5338,9 @@ cxgbe_sysctls(struct port_info *pi)
         * dev.(cxgbe|cxl).X.tc.
         */
        oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL,
-           "Tx scheduler traffic classes");
+           "Tx scheduler traffic classes (cl_rl)");
        for (i = 0; i < sc->chip_params->nsched_cls; i++) {
-               struct tx_sched_class *tc = &pi->tc[i];
+               struct tx_cl_rl_params *tc = &pi->sched_params->cl_rl[i];
 
                snprintf(name, sizeof(name), "%d", i);
                children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx,
@@ -7855,10 +7855,9 @@ static int
 sysctl_tc_params(SYSCTL_HANDLER_ARGS)
 {
        struct adapter *sc = arg1;
-       struct tx_sched_class *tc;
-       struct t4_sched_class_params p;
+       struct tx_cl_rl_params tc;
        struct sbuf *sb;
-       int i, rc, port_id, flags, mbps, gbps;
+       int i, rc, port_id, mbps, gbps;
 
        rc = sysctl_wire_old_buffer(req, 0);
        if (rc != 0)
@@ -7873,52 +7872,34 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS)
        MPASS(sc->port[port_id] != NULL);
        i = arg2 & 0xffff;
        MPASS(i < sc->chip_params->nsched_cls);
-       tc = &sc->port[port_id]->tc[i];
-
-       rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
-           "t4tc_p");
-       if (rc)
-               goto done;
-       flags = tc->flags;
-       p = tc->params;
-       end_synchronized_op(sc, LOCK_HELD);
 
-       if ((flags & TX_SC_OK) == 0) {
-               sbuf_printf(sb, "none");
-               goto done;
-       }
+       mtx_lock(&sc->tc_lock);
+       tc = sc->port[port_id]->sched_params->cl_rl[i];
+       mtx_unlock(&sc->tc_lock);
 
-       if (p.level == SCHED_CLASS_LEVEL_CL_WRR) {
-               sbuf_printf(sb, "cl-wrr weight %u", p.weight);
-               goto done;
-       } else if (p.level == SCHED_CLASS_LEVEL_CL_RL)
-               sbuf_printf(sb, "cl-rl");
-       else if (p.level == SCHED_CLASS_LEVEL_CH_RL)
-               sbuf_printf(sb, "ch-rl");
-       else {
-               rc = ENXIO;
+       if (tc.flags & TX_CLRL_ERROR) {
+               sbuf_printf(sb, "error");
                goto done;
        }
 
-       if (p.ratemode == SCHED_CLASS_RATEMODE_REL) {
+       if (tc.ratemode == SCHED_CLASS_RATEMODE_REL) {
                /* XXX: top speed or actual link speed? */
                gbps = port_top_speed(sc->port[port_id]);
-               sbuf_printf(sb, " %u%% of %uGbps", p.maxrate, gbps);
-       }
-       else if (p.ratemode == SCHED_CLASS_RATEMODE_ABS) {
-               switch (p.rateunit) {
+               sbuf_printf(sb, " %u%% of %uGbps", tc.maxrate, gbps);
+       } else if (tc.ratemode == SCHED_CLASS_RATEMODE_ABS) {
+               switch (tc.rateunit) {
                case SCHED_CLASS_RATEUNIT_BITS:
-                       mbps = p.maxrate / 1000;
-                       gbps = p.maxrate / 1000000;
-                       if (p.maxrate == gbps * 1000000)
+                       mbps = tc.maxrate / 1000;
+                       gbps = tc.maxrate / 1000000;
+                       if (tc.maxrate == gbps * 1000000)
                                sbuf_printf(sb, " %uGbps", gbps);
-                       else if (p.maxrate == mbps * 1000)
+                       else if (tc.maxrate == mbps * 1000)
                                sbuf_printf(sb, " %uMbps", mbps);
                        else
-                               sbuf_printf(sb, " %uKbps", p.maxrate);
+                               sbuf_printf(sb, " %uKbps", tc.maxrate);
                        break;
                case SCHED_CLASS_RATEUNIT_PKTS:
-                       sbuf_printf(sb, " %upps", p.maxrate);
+                       sbuf_printf(sb, " %upps", tc.maxrate);
                        break;
                default:
                        rc = ENXIO;
@@ -7926,7 +7907,7 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS)
                }
        }
 
-       switch (p.mode) {
+       switch (tc.mode) {
        case SCHED_CLASS_MODE_CLASS:
                sbuf_printf(sb, " aggregate");
                break;
@@ -8828,225 +8809,6 @@ read_i2c(struct adapter *sc, struct t4_i
        return (rc);
 }
 
-static int
-in_range(int val, int lo, int hi)
-{
-
-       return (val < 0 || (val <= hi && val >= lo));
-}
-
-static int
-set_sched_class_config(struct adapter *sc, int minmax)
-{
-       int rc;
-
-       if (minmax < 0)
-               return (EINVAL);
-
-       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
-       if (rc)
-               return (rc);
-       rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
-       end_synchronized_op(sc, 0);
-
-       return (rc);
-}
-
-static int
-set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
-    int sleep_ok)
-{
-       int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
-       struct port_info *pi;
-       struct tx_sched_class *tc;
-
-       if (p->level == SCHED_CLASS_LEVEL_CL_RL)
-               fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
-       else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
-               fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
-       else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
-               fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
-       else
-               return (EINVAL);
-
-       if (p->mode == SCHED_CLASS_MODE_CLASS)
-               fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
-       else if (p->mode == SCHED_CLASS_MODE_FLOW)
-               fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
-       else
-               return (EINVAL);
-
-       if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS)
-               fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
-       else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS)
-               fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
-       else
-               return (EINVAL);
-
-       if (p->ratemode == SCHED_CLASS_RATEMODE_REL)
-               fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
-       else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS)
-               fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
-       else
-               return (EINVAL);
-
-       /* Vet our parameters ... */
-       if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
-               return (ERANGE);
-
-       pi = sc->port[sc->chan_map[p->channel]];
-       if (pi == NULL)
-               return (ENXIO);
-       MPASS(pi->tx_chan == p->channel);
-       top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
-
-       if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) ||
-           !in_range(p->minrate, 0, top_speed) ||
-           !in_range(p->maxrate, 0, top_speed) ||
-           !in_range(p->weight, 0, 100))
-               return (ERANGE);
-
-       /*
-        * Translate any unset parameters into the firmware's
-        * nomenclature and/or fail the call if the parameters
-        * are required ...
-        */
-       if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0)
-               return (EINVAL);
-
-       if (p->minrate < 0)
-               p->minrate = 0;
-       if (p->maxrate < 0) {
-               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
-                   p->level == SCHED_CLASS_LEVEL_CH_RL)
-                       return (EINVAL);
-               else
-                       p->maxrate = 0;
-       }
-       if (p->weight < 0) {
-               if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
-                       return (EINVAL);
-               else
-                       p->weight = 0;
-       }
-       if (p->pktsize < 0) {
-               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
-                   p->level == SCHED_CLASS_LEVEL_CH_RL)
-                       return (EINVAL);
-               else
-                       p->pktsize = 0;
-       }
-
-       rc = begin_synchronized_op(sc, NULL,
-           sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
-       if (rc)
-               return (rc);
-       tc = &pi->tc[p->cl];
-       tc->params = *p;
-       rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode,
-           fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate,
-           p->weight, p->pktsize, sleep_ok);
-       if (rc == 0)
-               tc->flags |= TX_SC_OK;
-       else {
-               /*
-                * Unknown state at this point, see tc->params for what was
-                * attempted.
-                */
-               tc->flags &= ~TX_SC_OK;
-       }
-       end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
-
-       return (rc);
-}
-
-int
-t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
-{
-
-       if (p->type != SCHED_CLASS_TYPE_PACKET)
-               return (EINVAL);
-
-       if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
-               return (set_sched_class_config(sc, p->u.config.minmax));
-
-       if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
-               return (set_sched_class_params(sc, &p->u.params, 1));
-
-       return (EINVAL);
-}
-
-int
-t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
-{
-       struct port_info *pi = NULL;
-       struct vi_info *vi;
-       struct sge_txq *txq;
-       uint32_t fw_mnem, fw_queue, fw_class;
-       int i, rc;
-
-       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq");
-       if (rc)
-               return (rc);
-
-       if (p->port >= sc->params.nports) {
-               rc = EINVAL;
-               goto done;
-       }
-
-       /* XXX: Only supported for the main VI. */
-       pi = sc->port[p->port];
-       vi = &pi->vi[0];
-       if (!(vi->flags & VI_INIT_DONE)) {
-               /* tx queues not set up yet */
-               rc = EAGAIN;
-               goto done;
-       }
-
-       if (!in_range(p->queue, 0, vi->ntxq - 1) ||
-           !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) {
-               rc = EINVAL;
-               goto done;
-       }
-
-       /*
-        * Create a template for the FW_PARAMS_CMD mnemonic and value (TX
-        * Scheduling Class in this case).
-        */
-       fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
-           V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH));
-       fw_class = p->cl < 0 ? 0xffffffff : p->cl;
-
-       /*
-        * If op.queue is non-negative, then we're only changing the scheduling
-        * on a single specified TX queue.
-        */
-       if (p->queue >= 0) {
-               txq = &sc->sge.txq[vi->first_txq + p->queue];
-               fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
-               rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
-                   &fw_class);
-               goto done;
-       }
-
-       /*
-        * Change the scheduling on all the TX queues for the
-        * interface.
-        */
-       for_each_txq(vi, i, txq) {
-               fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
-               rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
-                   &fw_class);
-               if (rc)
-                       goto done;
-       }
-
-       rc = 0;
-done:
-       end_synchronized_op(sc, 0);
-       return (rc);
-}
-
 int
 t4_os_find_pci_capability(struct adapter *sc, int cap)
 {

Added: head/sys/dev/cxgbe/t4_sched.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/cxgbe/t4_sched.c       Tue May  2 20:38:10 2017        
(r317702)
@@ -0,0 +1,461 @@
+/*-
+ * Copyright (c) 2017 Chelsio Communications, Inc.
+ * All rights reserved.
+ * Written by: Navdeep Parhar <n...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/sbuf.h>
+#include <sys/taskqueue.h>
+#include <sys/sysctl.h>
+
+#include "common/common.h"
+#include "common/t4_regs.h"
+#include "common/t4_regs_values.h"
+#include "common/t4_msg.h"
+
+
+static int
+in_range(int val, int lo, int hi)
+{
+
+       return (val < 0 || (val <= hi && val >= lo));
+}
+
+static int
+set_sched_class_config(struct adapter *sc, int minmax)
+{
+       int rc;
+
+       if (minmax < 0)
+               return (EINVAL);
+
+       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
+       if (rc)
+               return (rc);
+       rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
+       end_synchronized_op(sc, 0);
+
+       return (rc);
+}
+
+static int
+set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
+    int sleep_ok)
+{
+       int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
+       struct port_info *pi;
+       struct tx_cl_rl_params *tc;
+
+       if (p->level == SCHED_CLASS_LEVEL_CL_RL)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
+       else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
+       else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
+       else
+               return (EINVAL);
+
+       if (p->mode == SCHED_CLASS_MODE_CLASS)
+               fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
+       else if (p->mode == SCHED_CLASS_MODE_FLOW)
+               fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
+       else
+               return (EINVAL);
+
+       if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS)
+               fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
+       else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS)
+               fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
+       else
+               return (EINVAL);
+
+       if (p->ratemode == SCHED_CLASS_RATEMODE_REL)
+               fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
+       else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS)
+               fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
+       else
+               return (EINVAL);
+
+       /* Vet our parameters ... */
+       if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
+               return (ERANGE);
+
+       pi = sc->port[sc->chan_map[p->channel]];
+       if (pi == NULL)
+               return (ENXIO);
+       MPASS(pi->tx_chan == p->channel);
+       top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
+
+       if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) ||
+           !in_range(p->minrate, 0, top_speed) ||
+           !in_range(p->maxrate, 0, top_speed) ||
+           !in_range(p->weight, 0, 100))
+               return (ERANGE);
+
+       /*
+        * Translate any unset parameters into the firmware's
+        * nomenclature and/or fail the call if the parameters
+        * are required ...
+        */
+       if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0)
+               return (EINVAL);
+
+       if (p->minrate < 0)
+               p->minrate = 0;
+       if (p->maxrate < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
+                   p->level == SCHED_CLASS_LEVEL_CH_RL)
+                       return (EINVAL);
+               else
+                       p->maxrate = 0;
+       }
+       if (p->weight < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
+                       return (EINVAL);
+               else
+                       p->weight = 0;
+       }
+       if (p->pktsize < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
+                   p->level == SCHED_CLASS_LEVEL_CH_RL)
+                       return (EINVAL);
+               else
+                       p->pktsize = 0;
+       }
+
+       rc = begin_synchronized_op(sc, NULL,
+           sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
+       if (rc)
+               return (rc);
+       if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
+               tc = &pi->sched_params->cl_rl[p->cl];
+               if (tc->refcount > 0) {
+                       rc = EBUSY;
+                       goto done;
+               } else {
+                       tc->ratemode = fw_ratemode;
+                       tc->rateunit = fw_rateunit;
+                       tc->mode = fw_mode;
+                       tc->maxrate = p->maxrate;
+                       tc->pktsize = p->pktsize;
+               }
+       }
+       rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode,
+           fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate,
+           p->weight, p->pktsize, sleep_ok);
+       if (p->level == SCHED_CLASS_LEVEL_CL_RL && rc != 0) {
+               /*
+                * Unknown state at this point, see parameters in tc for what
+                * was attempted.
+                */
+               tc->flags |= TX_CLRL_ERROR;
+       }
+done:
+       end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
+
+       return (rc);
+}
+
+static void
+update_tx_sched(void *context, int pending)
+{
+       int i, j, mode, rateunit, ratemode, maxrate, pktsize, rc;
+       struct port_info *pi;
+       struct tx_cl_rl_params *tc;
+       struct adapter *sc = context;
+       const int n = sc->chip_params->nsched_cls;
+
+       mtx_lock(&sc->tc_lock);
+       for_each_port(sc, i) {
+               pi = sc->port[i];
+               tc = &pi->sched_params->cl_rl[0];
+               for (j = 0; j < n; j++, tc++) {
+                       MPASS(mtx_owned(&sc->tc_lock));
+                       if ((tc->flags & TX_CLRL_REFRESH) == 0)
+                               continue;
+
+                       mode = tc->mode;
+                       rateunit = tc->rateunit;
+                       ratemode = tc->ratemode;
+                       maxrate = tc->maxrate;
+                       pktsize = tc->pktsize;
+                       mtx_unlock(&sc->tc_lock);
+
+                       if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
+                           "t4utxs") != 0) {
+                               mtx_lock(&sc->tc_lock);
+                               continue;
+                       }
+                       rc = t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED,
+                           FW_SCHED_PARAMS_LEVEL_CL_RL, mode, rateunit,
+                           ratemode, pi->tx_chan, j, 0, maxrate, 0, pktsize,
+                           1);
+                       end_synchronized_op(sc, 0);
+
+                       mtx_lock(&sc->tc_lock);
+                       if (rc != 0) {
+                               tc->flags |= TX_CLRL_ERROR;
+                       } else if (tc->mode == mode &&
+                           tc->rateunit == rateunit &&
+                           tc->maxrate == maxrate &&
+                           tc->pktsize == tc->pktsize) {
+                               tc->flags &= ~(TX_CLRL_REFRESH | TX_CLRL_ERROR);
+                       }
+               }
+       }
+       mtx_unlock(&sc->tc_lock);
+}
+
+int
+t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
+{
+
+       if (p->type != SCHED_CLASS_TYPE_PACKET)
+               return (EINVAL);
+
+       if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
+               return (set_sched_class_config(sc, p->u.config.minmax));
+
+       if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
+               return (set_sched_class_params(sc, &p->u.params, 1));
+
+       return (EINVAL);
+}
+
+int
+t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
+{
+       struct port_info *pi = NULL;
+       struct vi_info *vi;
+       struct sge_txq *txq;
+       uint32_t fw_mnem, fw_queue, fw_class;
+       int i, rc;
+
+       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq");
+       if (rc)
+               return (rc);
+
+       if (p->port >= sc->params.nports) {
+               rc = EINVAL;
+               goto done;
+       }
+
+       /* XXX: Only supported for the main VI. */
+       pi = sc->port[p->port];
+       vi = &pi->vi[0];
+       if (!(vi->flags & VI_INIT_DONE)) {
+               /* tx queues not set up yet */
+               rc = EAGAIN;
+               goto done;
+       }
+
+       if (!in_range(p->queue, 0, vi->ntxq - 1) ||
+           !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) {
+               rc = EINVAL;
+               goto done;
+       }
+
+       /*
+        * Create a template for the FW_PARAMS_CMD mnemonic and value (TX
+        * Scheduling Class in this case).
+        */
+       fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
+           V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH));
+       fw_class = p->cl < 0 ? 0xffffffff : p->cl;
+
+       /*
+        * If op.queue is non-negative, then we're only changing the scheduling
+        * on a single specified TX queue.
+        */
+       if (p->queue >= 0) {
+               txq = &sc->sge.txq[vi->first_txq + p->queue];
+               fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
+               rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
+                   &fw_class);
+               goto done;
+       }
+
+       /*
+        * Change the scheduling on all the TX queues for the
+        * interface.
+        */
+       for_each_txq(vi, i, txq) {
+               fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
+               rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
+                   &fw_class);
+               if (rc)
+                       goto done;
+       }
+
+       rc = 0;
+done:
+       end_synchronized_op(sc, 0);
+       return (rc);
+}
+
+int
+t4_init_tx_sched(struct adapter *sc)
+{
+       int i, j;
+       const int n = sc->chip_params->nsched_cls;
+       struct port_info *pi;
+       struct tx_cl_rl_params *tc;
+       static const uint32_t init_kbps[] = {
+               100 * 1000,
+               200 * 1000,
+               400 * 1000,
+               500 * 1000,
+               800 * 1000,
+               1000 * 1000,
+               1200 * 1000,
+               1500 * 1000,
+               1800 * 1000,
+               2000 * 1000,
+               2500 * 1000,
+               3000 * 1000,
+               3500 * 1000,
+               4000 * 1000,
+               5000 * 1000,
+               10000 * 1000
+       };
+
+       mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF);
+       TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc);
+       for_each_port(sc, i) {
+               pi = sc->port[i];
+               pi->sched_params = malloc(sizeof(*pi->sched_params) +
+                   n * sizeof(*tc), M_CXGBE, M_ZERO | M_WAITOK);
+               tc = &pi->sched_params->cl_rl[0];
+               for (j = 0; j < n; j++, tc++) {
+                       tc->flags = TX_CLRL_REFRESH;
+                       tc->refcount = 0;
+                       tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
+                       tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
+                       tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
+                       tc->maxrate = init_kbps[min(j, nitems(init_kbps) - 1)];
+                       tc->pktsize = ETHERMTU; /* XXX */
+
+                       t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j, tc->mode,
+                           tc->maxrate, tc->pktsize, 1);
+               }
+       }
+
+       return (0);
+}
+
+int
+t4_free_tx_sched(struct adapter *sc)
+{
+       int i;
+
+       taskqueue_drain(taskqueue_thread, &sc->tc_task);
+
+       for_each_port(sc, i)
+           free(sc->port[i]->sched_params, M_CXGBE);
+
+       if (mtx_initialized(&sc->tc_lock))
+               mtx_destroy(&sc->tc_lock);
+
+       return (0);
+}
+
+void
+t4_update_tx_sched(struct adapter *sc)
+{
+
+       taskqueue_enqueue(taskqueue_thread, &sc->tc_task);
+}
+
+int
+t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate,
+    int *tc_idx)
+{
+       int rc = 0, fa = -1, i;
+       struct tx_cl_rl_params *tc;
+
+       MPASS(port_id >= 0 && port_id < sc->params.nports);
+
+       tc = &sc->port[port_id]->sched_params->cl_rl[0];
+       mtx_lock(&sc->tc_lock);
+       for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) {
+               if (fa < 0 && tc->refcount == 0)
+                       fa = i;
+
+               if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS &&
+                   tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE &&
+                   tc->mode == FW_SCHED_PARAMS_MODE_FLOW &&
+                   tc->maxrate == maxrate) {
+                       tc->refcount++;
+                       *tc_idx = i;
+                       goto done;
+               }
+       }
+       /* Not found */
+       MPASS(i == sc->chip_params->nsched_cls);
+       if (fa != -1) {
+               tc = &sc->port[port_id]->sched_params->cl_rl[fa];
+               tc->flags = TX_CLRL_REFRESH;
+               tc->refcount = 1;
+               tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
+               tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
+               tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
+               tc->maxrate = maxrate;
+               tc->pktsize = ETHERMTU; /* XXX */
+               *tc_idx = fa;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to