diff --git a/sys/dev/dpaa2/dpaa2_io.c b/sys/dev/dpaa2/dpaa2_io.c index ef82a726ad82..a4a2ae1810aa 100644 --- a/sys/dev/dpaa2/dpaa2_io.c +++ b/sys/dev/dpaa2/dpaa2_io.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,9 @@ #define DPIO_IRQ_INDEX 0 /* index of the only DPIO IRQ */ #define DPIO_POLL_MAX 32 +#define SWP_HOLDOFF_MS_MIN 100 +#define SWP_HOLDOFF_MS_MAX 10000 + /* * Memory: * 0: cache-enabled part of the QBMan software portal. @@ -196,6 +200,51 @@ err_exit: return (error); } +static int +dpaa2_io_collect_irq_holdoff(SYSCTL_HANDLER_ARGS) +{ + struct dpaa2_io_softc *sc; + struct dpaa2_swp *swp; + uint32_t error, new_value; + + sc = (struct dpaa2_io_softc *)arg1; + swp = sc->swp; + error = SYSCTL_OUT(req, &sc->irq_holdoff, + sizeof(sc->irq_holdoff)); + if (error || req->newptr == NULL) + return error; + error = SYSCTL_IN(req, &new_value, sizeof(new_value)); + if (error) + return error; + if ((new_value < SWP_HOLDOFF_MS_MIN) || (new_value > SWP_HOLDOFF_MS_MAX)) + return EINVAL; + error = dpaa2_swp_set_irq_coalescing(swp, swp->dqrr.ring_size - 1, + new_value); + if (error) + return error; + sc->irq_holdoff = new_value; + return 0; +} + +static void +dpaa2_io_setup_sysctls(struct dpaa2_io_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid *node; + struct sysctl_oid_list *parent; + + ctx = device_get_sysctl_ctx(sc->dev); + parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); + + node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "io", + CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, "io control"); + parent = SYSCTL_CHILDREN(node); + + SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "irq_holdoff", + CTLTYPE_U32 | CTLFLAG_RW, sc, 0, dpaa2_io_collect_irq_holdoff, "IU", + "SWP holdoff time in ms"); +} + static int dpaa2_io_attach(device_t dev) { @@ -223,6 +272,7 @@ dpaa2_io_attach(device_t dev) sc->swp = NULL; sc->intr = NULL; sc->irq_resource = NULL; + sc->irq_holdoff = 120; /* Allocate resources. */ error = bus_alloc_resources(sc->dev, dpaa2_io_spec, sc->res); @@ -308,8 +358,10 @@ dpaa2_io_attach(device_t dev) sc->swp_desc.swp_cycles_ratio = 256000 / (sc->swp_desc.swp_clk / 1000000); + dpaa2_io_setup_sysctls(sc); + /* Initialize QBMan software portal. */ - error = dpaa2_swp_init_portal(&sc->swp, &sc->swp_desc, DPAA2_SWP_DEF); + error = dpaa2_swp_init_portal(sc, DPAA2_SWP_DEF); if (error) { device_printf(dev, "%s: failed to initialize dpaa2_swp: " "error=%d\n", __func__, error); diff --git a/sys/dev/dpaa2/dpaa2_io.h b/sys/dev/dpaa2/dpaa2_io.h index cc3156fcc595..97c5b6210b68 100644 --- a/sys/dev/dpaa2/dpaa2_io.h +++ b/sys/dev/dpaa2/dpaa2_io.h @@ -100,6 +100,9 @@ struct dpaa2_io_softc { int cpu; cpuset_t cpu_mask; + + /* sysctl(9) */ + uint32_t irq_holdoff; /* ms */ }; extern struct resource_spec dpaa2_io_spec[]; diff --git a/sys/dev/dpaa2/dpaa2_swp.c b/sys/dev/dpaa2/dpaa2_swp.c index 5800d7fedd82..a57226bf7e1f 100644 --- a/sys/dev/dpaa2/dpaa2_swp.c +++ b/sys/dev/dpaa2/dpaa2_swp.c @@ -179,15 +179,15 @@ static int dpaa2_swp_wait_for_mgmt_response(struct dpaa2_swp *, static int dpaa2_swp_cyc_diff(uint8_t, uint8_t, uint8_t); int -dpaa2_swp_init_portal(struct dpaa2_swp **swp, struct dpaa2_swp_desc *desc, - uint16_t flags) +dpaa2_swp_init_portal(struct dpaa2_io_softc *sc, uint16_t flags) { struct dpaa2_swp *p; + struct dpaa2_swp_desc *desc; uint32_t reg, mask_size, eqcr_pi; /* EQCR producer index */ - if (!swp || !desc) + if (!sc) return (DPAA2_SWP_STAT_EINVAL); - + desc = &sc->swp_desc; p = malloc(sizeof(struct dpaa2_swp), M_DPAA2_SWP, flags & DPAA2_SWP_NOWAIT_ALLOC ? (M_NOWAIT | M_ZERO) @@ -297,11 +297,13 @@ dpaa2_swp_init_portal(struct dpaa2_swp **swp, struct dpaa2_swp_desc *desc, & p->eqcr.pi_ci_mask; p->eqcr.available = p->eqcr.pi_ring_size; - /* TODO: sysctl(9) for the IRQ timeout? */ - /* Initialize the portal with an IRQ threshold and timeout of 120us. */ - dpaa2_swp_set_irq_coalescing(p, p->dqrr.ring_size - 1, 120); + /* + * Initialize the portal with an IRQ threshold and timeout from the + * device context. + */ + dpaa2_swp_set_irq_coalescing(p, p->dqrr.ring_size - 1, sc->irq_holdoff); - *swp = p; + sc->swp = p; return (0); } diff --git a/sys/dev/dpaa2/dpaa2_swp.h b/sys/dev/dpaa2/dpaa2_swp.h index 20980c6b71b7..124eedf2c284 100644 --- a/sys/dev/dpaa2/dpaa2_swp.h +++ b/sys/dev/dpaa2/dpaa2_swp.h @@ -232,6 +232,11 @@ enum dpaa2_fd_format { DPAA2_FD_SG }; +/** + * Forward declaration to avoid circular include. + */ +struct dpaa2_io_softc; + /** * @brief Enqueue command descriptor. */ @@ -441,8 +446,7 @@ struct dpaa2_swp { }; /* Management routines. */ -int dpaa2_swp_init_portal(struct dpaa2_swp **swp, struct dpaa2_swp_desc *desc, - uint16_t flags); +int dpaa2_swp_init_portal(struct dpaa2_io_softc *softc, uint16_t flags); void dpaa2_swp_free_portal(struct dpaa2_swp *swp); uint32_t dpaa2_swp_set_cfg(uint8_t max_fill, uint8_t wn, uint8_t est, uint8_t rpm, uint8_t dcm, uint8_t epm, int sd, int sp, int se, int dp,