diff --git a/lib/libc/tests/sys/cpuset_test.c b/lib/libc/tests/sys/cpuset_test.c index 52c0dc877ab8..53d6a8215bbc 100644 --- a/lib/libc/tests/sys/cpuset_test.c +++ b/lib/libc/tests/sys/cpuset_test.c @@ -1,694 +1,691 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2020-2021 Kyle Evans * * 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 -__FBSDID("$FreeBSD"); - #include #include #include #include #include #include #include #include #include #include #include #include #define SP_PARENT 0 #define SP_CHILD 1 struct jail_test_info { cpuset_t jail_tidmask; cpusetid_t jail_cpuset; cpusetid_t jail_child_cpuset; }; struct jail_test_cb_params { struct jail_test_info info; cpuset_t mask; cpusetid_t rootid; cpusetid_t setid; }; typedef void (*jail_test_cb)(struct jail_test_cb_params *); #define FAILURE_JAIL 42 #define FAILURE_MASK 43 #define FAILURE_JAILSET 44 #define FAILURE_PIDSET 45 #define FAILURE_SEND 46 #define FAILURE_DEADLK 47 #define FAILURE_ATTACH 48 #define FAILURE_BADAFFIN 49 #define FAILURE_SUCCESS 50 static const char * do_jail_errstr(int error) { switch (error) { case FAILURE_JAIL: return ("jail_set(2) failed"); case FAILURE_MASK: return ("Failed to get the thread cpuset mask"); case FAILURE_JAILSET: return ("Failed to get the jail setid"); case FAILURE_PIDSET: return ("Failed to get the pid setid"); case FAILURE_SEND: return ("Failed to send(2) cpuset information"); case FAILURE_DEADLK: return ("Deadlock hit trying to attach to jail"); case FAILURE_ATTACH: return ("jail_attach(2) failed"); case FAILURE_BADAFFIN: return ("Unexpected post-attach affinity"); case FAILURE_SUCCESS: return ("jail_attach(2) succeeded, but should have failed."); default: return (NULL); } } static void skip_ltncpu(int ncpu, cpuset_t *mask) { CPU_ZERO(mask); ATF_REQUIRE_EQ(0, cpuset_getaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(*mask), mask)); if (CPU_COUNT(mask) < ncpu) atf_tc_skip("Test requires %d or more cores.", ncpu); } ATF_TC(newset); ATF_TC_HEAD(newset, tc) { atf_tc_set_md_var(tc, "descr", "Test cpuset(2)"); } ATF_TC_BODY(newset, tc) { cpusetid_t nsetid, setid, qsetid; /* Obtain our initial set id. */ ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1, &setid)); /* Create a new one. */ ATF_REQUIRE_EQ(0, cpuset(&nsetid)); ATF_CHECK(nsetid != setid); /* Query id again, make sure it's equal to the one we just got. */ ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1, &qsetid)); ATF_CHECK_EQ(nsetid, qsetid); } ATF_TC(transient); ATF_TC_HEAD(transient, tc) { atf_tc_set_md_var(tc, "descr", "Test that transient cpusets are freed."); } ATF_TC_BODY(transient, tc) { cpusetid_t isetid, scratch, setid; ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, &isetid)); ATF_REQUIRE_EQ(0, cpuset(&setid)); ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, setid, &scratch)); /* * Return back to our initial cpuset; the kernel should free the cpuset * we just created. */ ATF_REQUIRE_EQ(0, cpuset_setid(CPU_WHICH_PID, -1, isetid)); ATF_REQUIRE_EQ(-1, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, setid, &scratch)); ATF_CHECK_EQ(ESRCH, errno); } ATF_TC(deadlk); ATF_TC_HEAD(deadlk, tc) { atf_tc_set_md_var(tc, "descr", "Test against disjoint cpusets."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(deadlk, tc) { cpusetid_t setid; cpuset_t dismask, mask, omask; int fcpu, i, found, ncpu, second; /* Make sure we have 3 cpus, so we test partial overlap. */ skip_ltncpu(3, &omask); ATF_REQUIRE_EQ(0, cpuset(&setid)); CPU_ZERO(&mask); CPU_ZERO(&dismask); CPU_COPY(&omask, &mask); CPU_COPY(&omask, &dismask); fcpu = CPU_FFS(&mask); ncpu = CPU_COUNT(&mask); /* * Turn off all but the first two for mask, turn off the first for * dismask and turn them all off for both after the third. */ for (i = fcpu - 1, found = 0; i < CPU_MAXSIZE && found != ncpu; i++) { if (CPU_ISSET(i, &omask)) { found++; if (found == 1) { CPU_CLR(i, &dismask); } else if (found == 2) { second = i; } else if (found >= 3) { CPU_CLR(i, &mask); if (found > 3) CPU_CLR(i, &dismask); } } } ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(mask), &mask)); /* Must be a strict subset! */ ATF_REQUIRE_EQ(-1, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(dismask), &dismask)); ATF_REQUIRE_EQ(EINVAL, errno); /* * We'll set our anonymous set to the 0,1 set that currently matches * the process. If we then set the process to the 1,2 set that's in * dismask, we should then personally be restricted down to the single * overlapping CPOU. */ ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), &mask)); ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(dismask), &dismask)); ATF_REQUIRE_EQ(0, cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), &mask)); ATF_REQUIRE_EQ(1, CPU_COUNT(&mask)); ATF_REQUIRE(CPU_ISSET(second, &mask)); /* * Finally, clearing the overlap and attempting to set the process * cpuset to a completely disjoint mask should fail, because this * process will then not have anything to run on. */ CPU_CLR(second, &dismask); ATF_REQUIRE_EQ(-1, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(dismask), &dismask)); ATF_REQUIRE_EQ(EDEADLK, errno); } static int do_jail(int sock) { struct jail_test_info info; struct iovec iov[2]; char *name; int error; if (asprintf(&name, "cpuset_%d", getpid()) == -1) _exit(42); iov[0].iov_base = "name"; iov[0].iov_len = 5; iov[1].iov_base = name; iov[1].iov_len = strlen(name) + 1; if (jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH) < 0) return (FAILURE_JAIL); /* Record parameters, kick them over, then make a swift exit. */ CPU_ZERO(&info.jail_tidmask); error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(info.jail_tidmask), &info.jail_tidmask); if (error != 0) return (FAILURE_MASK); error = cpuset_getid(CPU_LEVEL_ROOT, CPU_WHICH_TID, -1, &info.jail_cpuset); if (error != 0) return (FAILURE_JAILSET); error = cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1, &info.jail_child_cpuset); if (error != 0) return (FAILURE_PIDSET); if (send(sock, &info, sizeof(info), 0) != sizeof(info)) return (FAILURE_SEND); return (0); } static void do_jail_test(int ncpu, bool newset, jail_test_cb prologue, jail_test_cb epilogue) { struct jail_test_cb_params cbp; const char *errstr; pid_t pid; int error, sock, sockpair[2], status; memset(&cbp.info, '\0', sizeof(cbp.info)); skip_ltncpu(ncpu, &cbp.mask); ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, &cbp.rootid)); if (newset) ATF_REQUIRE_EQ(0, cpuset(&cbp.setid)); else ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, &cbp.setid)); /* Special hack for prison0; it uses cpuset 1 as the root. */ if (cbp.rootid == 0) cbp.rootid = 1; /* Not every test needs early setup. */ if (prologue != NULL) (*prologue)(&cbp); ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair)); ATF_REQUIRE((pid = fork()) != -1); if (pid == 0) { /* Child */ close(sockpair[SP_PARENT]); sock = sockpair[SP_CHILD]; _exit(do_jail(sock)); } else { /* Parent */ sock = sockpair[SP_PARENT]; close(sockpair[SP_CHILD]); while ((error = waitpid(pid, &status, 0)) == -1 && errno == EINTR) { } ATF_REQUIRE_EQ(sizeof(cbp.info), recv(sock, &cbp.info, sizeof(cbp.info), 0)); /* Sanity check the exit info. */ ATF_REQUIRE_EQ(pid, error); ATF_REQUIRE(WIFEXITED(status)); if (WEXITSTATUS(status) != 0) { errstr = do_jail_errstr(WEXITSTATUS(status)); if (errstr != NULL) atf_tc_fail("%s", errstr); else atf_tc_fail("Unknown error '%d'", WEXITSTATUS(status)); } epilogue(&cbp); } } static void jail_attach_mutate_pro(struct jail_test_cb_params *cbp) { cpuset_t *mask; int count; mask = &cbp->mask; /* Knock out the first cpu. */ count = CPU_COUNT(mask); CPU_CLR(CPU_FFS(mask) - 1, mask); ATF_REQUIRE_EQ(count - 1, CPU_COUNT(mask)); ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(*mask), mask)); } static void jail_attach_newbase_epi(struct jail_test_cb_params *cbp) { struct jail_test_info *info; cpuset_t *mask; info = &cbp->info; mask = &cbp->mask; /* * The rootid test has been thrown in because a bug was discovered * where any newly derived cpuset during attach would be parented to * the wrong cpuset. Otherwise, we should observe that a new cpuset * has been created for this process. */ ATF_REQUIRE(info->jail_cpuset != cbp->rootid); ATF_REQUIRE(info->jail_cpuset != cbp->setid); ATF_REQUIRE(info->jail_cpuset != info->jail_child_cpuset); ATF_REQUIRE_EQ(0, CPU_CMP(mask, &info->jail_tidmask)); } ATF_TC(jail_attach_newbase); ATF_TC_HEAD(jail_attach_newbase, tc) { atf_tc_set_md_var(tc, "descr", "Test jail attachment effect on affinity with a new base cpuset."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(jail_attach_newbase, tc) { /* Need >= 2 cpus to test restriction. */ do_jail_test(2, true, &jail_attach_mutate_pro, &jail_attach_newbase_epi); } ATF_TC(jail_attach_newbase_plain); ATF_TC_HEAD(jail_attach_newbase_plain, tc) { atf_tc_set_md_var(tc, "descr", "Test jail attachment effect on affinity with a new, unmodified base cpuset."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(jail_attach_newbase_plain, tc) { do_jail_test(2, true, NULL, &jail_attach_newbase_epi); } /* * Generic epilogue for tests that are expecting to use the jail's root cpuset * with their own mask, whether that's been modified or not. */ static void jail_attach_jset_epi(struct jail_test_cb_params *cbp) { struct jail_test_info *info; cpuset_t *mask; info = &cbp->info; mask = &cbp->mask; ATF_REQUIRE(info->jail_cpuset != cbp->setid); ATF_REQUIRE_EQ(info->jail_cpuset, info->jail_child_cpuset); ATF_REQUIRE_EQ(0, CPU_CMP(mask, &info->jail_tidmask)); } ATF_TC(jail_attach_prevbase); ATF_TC_HEAD(jail_attach_prevbase, tc) { atf_tc_set_md_var(tc, "descr", "Test jail attachment effect on affinity without a new base."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(jail_attach_prevbase, tc) { do_jail_test(2, false, &jail_attach_mutate_pro, &jail_attach_jset_epi); } static void jail_attach_plain_pro(struct jail_test_cb_params *cbp) { if (cbp->setid != cbp->rootid) atf_tc_skip("Must be running with the root cpuset."); } ATF_TC(jail_attach_plain); ATF_TC_HEAD(jail_attach_plain, tc) { atf_tc_set_md_var(tc, "descr", "Test jail attachment effect on affinity without specialization."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(jail_attach_plain, tc) { do_jail_test(1, false, &jail_attach_plain_pro, &jail_attach_jset_epi); } static int jail_attach_disjoint_newjail(int fd) { struct iovec iov[2]; char *name; int jid; if (asprintf(&name, "cpuset_%d", getpid()) == -1) _exit(42); iov[0].iov_base = "name"; iov[0].iov_len = sizeof("name"); iov[1].iov_base = name; iov[1].iov_len = strlen(name) + 1; if ((jid = jail_set(iov, 2, JAIL_CREATE | JAIL_ATTACH)) < 0) return (FAILURE_JAIL); /* Signal that we're ready. */ write(fd, &jid, sizeof(jid)); for (;;) { /* Spin */ } } static int wait_jail(int fd, int pfd) { fd_set lset; struct timeval tv; int error, jid, maxfd; FD_ZERO(&lset); FD_SET(fd, &lset); FD_SET(pfd, &lset); maxfd = MAX(fd, pfd); tv.tv_sec = 5; tv.tv_usec = 0; /* Wait for jid to be written. */ do { error = select(maxfd + 1, &lset, NULL, NULL, &tv); } while (error == -1 && errno == EINTR); if (error == 0) { atf_tc_fail("Jail creator did not respond in time."); } ATF_REQUIRE_MSG(error > 0, "Unexpected error %d from select()", errno); if (FD_ISSET(pfd, &lset)) { /* Process died */ atf_tc_fail("Jail creator died unexpectedly."); } ATF_REQUIRE(FD_ISSET(fd, &lset)); ATF_REQUIRE_EQ(sizeof(jid), recv(fd, &jid, sizeof(jid), 0)); return (jid); } static int try_attach_child(int jid, cpuset_t *expected_mask) { cpuset_t mask; if (jail_attach(jid) == -1) { if (errno == EDEADLK) return (FAILURE_DEADLK); return (FAILURE_ATTACH); } if (expected_mask == NULL) return (FAILURE_SUCCESS); /* If we had an expected mask, check it against the new process mask. */ CPU_ZERO(&mask); if (cpuset_getaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, sizeof(mask), &mask) != 0) { return (FAILURE_MASK); } if (CPU_CMP(expected_mask, &mask) != 0) return (FAILURE_BADAFFIN); return (0); } static void try_attach(int jid, cpuset_t *expected_mask) { const char *errstr; pid_t pid; int error, fail, status; ATF_REQUIRE(expected_mask != NULL); ATF_REQUIRE((pid = fork()) != -1); if (pid == 0) _exit(try_attach_child(jid, expected_mask)); while ((error = waitpid(pid, &status, 0)) == -1 && errno == EINTR) { /* Try again. */ } /* Sanity check the exit info. */ ATF_REQUIRE_EQ(pid, error); ATF_REQUIRE(WIFEXITED(status)); if ((fail = WEXITSTATUS(status)) != 0) { errstr = do_jail_errstr(fail); if (errstr != NULL) atf_tc_fail("%s", errstr); else atf_tc_fail("Unknown error '%d'", WEXITSTATUS(status)); } } ATF_TC(jail_attach_disjoint); ATF_TC_HEAD(jail_attach_disjoint, tc) { atf_tc_set_md_var(tc, "descr", "Test root attachment into completely disjoint jail cpuset."); atf_tc_set_md_var(tc, "require.user", "root"); } ATF_TC_BODY(jail_attach_disjoint, tc) { cpuset_t smask, jmask; int sockpair[2]; cpusetid_t setid; pid_t pid; int fcpu, jid, pfd, sock, scpu; ATF_REQUIRE_EQ(0, cpuset(&setid)); skip_ltncpu(2, &jmask); fcpu = CPU_FFS(&jmask) - 1; ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sockpair)); /* We'll wait on the procdesc, too, so we can fail faster if it dies. */ ATF_REQUIRE((pid = pdfork(&pfd, 0)) != -1); if (pid == 0) { /* First child sets up the jail. */ sock = sockpair[SP_CHILD]; close(sockpair[SP_PARENT]); _exit(jail_attach_disjoint_newjail(sock)); } close(sockpair[SP_CHILD]); sock = sockpair[SP_PARENT]; ATF_REQUIRE((jid = wait_jail(sock, pfd)) > 0); /* * This process will be clamped down to the first cpu, while the jail * will simply have the first CPU removed to make it a completely * disjoint operation. */ CPU_ZERO(&smask); CPU_SET(fcpu, &smask); CPU_CLR(fcpu, &jmask); /* * We'll test with the first and second cpu set as well. Only the * second cpu should be used. */ scpu = CPU_FFS(&jmask) - 1; ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_ROOT, CPU_WHICH_JAIL, jid, sizeof(jmask), &jmask)); ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, setid, sizeof(smask), &smask)); try_attach(jid, &jmask); CPU_SET(scpu, &smask); ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, setid, sizeof(smask), &smask)); CPU_CLR(fcpu, &smask); try_attach(jid, &smask); } ATF_TC(badparent); ATF_TC_HEAD(badparent, tc) { atf_tc_set_md_var(tc, "descr", "Test parent assignment when assigning a new cpuset."); } ATF_TC_BODY(badparent, tc) { cpuset_t mask; cpusetid_t finalsetid, origsetid, setid; /* Need to mask off at least one CPU. */ skip_ltncpu(2, &mask); ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1, &origsetid)); ATF_REQUIRE_EQ(0, cpuset(&setid)); /* * Mask off the first CPU, then we'll reparent ourselves to our original * set. */ CPU_CLR(CPU_FFS(&mask) - 1, &mask); ATF_REQUIRE_EQ(0, cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask), &mask)); ATF_REQUIRE_EQ(0, cpuset_setid(CPU_WHICH_PID, -1, origsetid)); ATF_REQUIRE_EQ(0, cpuset_getid(CPU_LEVEL_CPUSET, CPU_WHICH_TID, -1, &finalsetid)); ATF_REQUIRE_EQ(finalsetid, origsetid); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, newset); ATF_TP_ADD_TC(tp, transient); ATF_TP_ADD_TC(tp, deadlk); ATF_TP_ADD_TC(tp, jail_attach_newbase); ATF_TP_ADD_TC(tp, jail_attach_newbase_plain); ATF_TP_ADD_TC(tp, jail_attach_prevbase); ATF_TP_ADD_TC(tp, jail_attach_plain); ATF_TP_ADD_TC(tp, jail_attach_disjoint); ATF_TP_ADD_TC(tp, badparent); return (atf_no_error()); } diff --git a/sys/arm/mv/clk/armada38x_coreclk.c b/sys/arm/mv/clk/armada38x_coreclk.c index 14887ce88fb3..21e630d18b06 100644 --- a/sys/arm/mv/clk/armada38x_coreclk.c +++ b/sys/arm/mv/clk/armada38x_coreclk.c @@ -1,222 +1,219 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2022 Semihalf. * * 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 ``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 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 -__FBSDID("$FressBSD$"); - #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "clkdev_if.h" #define ARMADA38X_CORECLK_MAXREG 0 static struct resource_spec armada38x_coreclk_specs[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; struct armada38x_coreclk_softc { struct resource *res; struct clkdom *clkdom; struct mtx mtx; }; static int armada38x_coreclk_attach(device_t dev); static int armada38x_coreclk_probe(device_t dev); static struct armada38x_gen_clknode_def gen_nodes[] = { { .def = { .name = "coreclk_0", .id = 0, .parent_cnt = 0, }, }, { .def = { .name = "coreclk_2", .id = 1, .parent_cnt = 0, }, } }; static int armada38x_coreclk_read_4(device_t dev, bus_addr_t addr, uint32_t *val) { struct armada38x_coreclk_softc *sc; sc = device_get_softc(dev); if (addr > ARMADA38X_CORECLK_MAXREG) return (EINVAL); *val = bus_read_4(sc->res, addr); return (0); } static int armada38x_coreclk_write_4(device_t dev, bus_addr_t addr, uint32_t val) { struct armada38x_coreclk_softc *sc; sc = device_get_softc(dev); if (addr > ARMADA38X_CORECLK_MAXREG) return (EINVAL); bus_write_4(sc->res, addr, val); return (0); } static void armada38x_coreclk_device_lock(device_t dev) { struct armada38x_coreclk_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->mtx); } static void armada38x_coreclk_device_unlock(device_t dev) { struct armada38x_coreclk_softc *sc; sc = device_get_softc(dev); mtx_unlock(&sc->mtx); } static int armada38x_coreclk_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "marvell,armada-380-core-clock")) return (ENXIO); device_set_desc(dev, "ARMADA38X core-clock"); return (BUS_PROBE_DEFAULT); } static int armada38x_coreclk_create_coreclk(device_t dev) { struct armada38x_coreclk_softc *sc; int rv, i; sc = device_get_softc(dev); for (i = 0; i < nitems(gen_nodes); ++i) { rv = armada38x_gen_register(sc->clkdom, &gen_nodes[i]); if (rv) return (rv); } return (rv); } static int armada38x_coreclk_attach(device_t dev) { struct armada38x_coreclk_softc *sc; int error; sc = device_get_softc(dev); if (bus_alloc_resources(dev, armada38x_coreclk_specs, &sc->res) != 0) { device_printf(dev, "Cannot allocate resources.\n"); return (ENXIO); } mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); sc->clkdom = clkdom_create(dev); if (NULL == sc->clkdom) { device_printf(dev, "Cannot create clkdom\n"); return (ENXIO); } error = armada38x_coreclk_create_coreclk(dev); if (0 != error) { device_printf(dev, "Cannot create coreclk.\n"); return (error); } if (clkdom_finit(sc->clkdom) != 0) panic("Cannot finalize clock domain initialization.\n"); if (bootverbose) clkdom_dump(sc->clkdom); return (0); } static device_method_t amada38x_coreclk_methods[] = { DEVMETHOD(clkdev_write_4, armada38x_coreclk_write_4), DEVMETHOD(clkdev_read_4, armada38x_coreclk_read_4), DEVMETHOD(clkdev_device_lock, armada38x_coreclk_device_lock), DEVMETHOD(clkdev_device_unlock, armada38x_coreclk_device_unlock), DEVMETHOD(device_attach, armada38x_coreclk_attach), DEVMETHOD(device_probe, armada38x_coreclk_probe), DEVMETHOD_END }; static driver_t armada38x_coreclk_driver = { "armada38x_coreclk", amada38x_coreclk_methods, sizeof(struct armada38x_coreclk_softc), }; EARLY_DRIVER_MODULE(armada38x_coreclk, simplebus, armada38x_coreclk_driver, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/dev/enic/enic.h b/sys/dev/enic/enic.h index a2a40334986f..6d0eb8563efd 100644 --- a/sys/dev/enic/enic.h +++ b/sys/dev/enic/enic.h @@ -1,406 +1,403 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright 2008-2017 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. */ -#include -__FBSDID("$FreeBSD: $"); - #ifndef _ENIC_H #define _ENIC_H #include #include #include #include #include #include #include #include #include #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define u64 uint64_t struct enic_bar_info { struct resource *res; bus_space_tag_t tag; bus_space_handle_t handle; bus_size_t size; int rid; int offset; }; #define ENIC_BUS_WRITE_8(res, index, value) \ bus_space_write_8(res->bar.tag, res->bar.handle, \ res->bar.offset + (index), value) #define ENIC_BUS_WRITE_4(res, index, value) \ bus_space_write_4(res->bar.tag, res->bar.handle, \ res->bar.offset + (index), value) #define ENIC_BUS_WRITE_REGION_4(res, index, values, count) \ bus_space_write_region_4(res->bar.tag, res->bar.handle, \ res->bar.offset + (index), values, count); #define ENIC_BUS_READ_8(res, index) \ bus_space_read_8(res->bar.tag, res->bar.handle, \ res->bar.offset + (index)) #define ENIC_BUS_READ_4(res, index) \ bus_space_read_4(res->bar.tag, res->bar.handle, \ res->bar.offset + (index)) #define ENIC_BUS_READ_REGION_4(res, type, index, values, count) \ bus_space_read_region_4(res->type.tag, res->type.handle, \ res->type.offset + (index), values, count); struct vnic_res { unsigned int count; struct enic_bar_info bar; }; #include "vnic_enet.h" #include "vnic_dev.h" #include "vnic_wq.h" #include "vnic_rq.h" #include "vnic_cq.h" #include "vnic_intr.h" #include "vnic_stats.h" #include "vnic_nic.h" #include "vnic_rss.h" #include "enic_res.h" #include "cq_enet_desc.h" #define ENIC_LOCK(_softc) mtx_lock(&(_softc)->enic_lock) #define ENIC_UNLOCK(_softc) mtx_unlock(&(_softc)->enic_lock) #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC" #define DRV_COPYRIGHT "Copyright 2008-2015 Cisco Systems, Inc" #define ENIC_MAX_MAC_ADDR 64 #define VLAN_ETH_HLEN 18 #define ENICPMD_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0) #define ENICPMD_BDF_LENGTH 13 /* 0000:00:00.0'\0' */ #define ENIC_CALC_IP_CKSUM 1 #define ENIC_CALC_TCP_UDP_CKSUM 2 #define ENIC_MAX_MTU 9000 #define ENIC_PAGE_SIZE 4096 #define PAGE_ROUND_UP(x) \ ((((unsigned long)(x)) + ENIC_PAGE_SIZE-1) & (~(ENIC_PAGE_SIZE-1))) /* must be >= VNIC_COUNTER_DMA_MIN_PERIOD */ #define VNIC_FLOW_COUNTER_UPDATE_MSECS 500 /* PCI IDs */ #define CISCO_VENDOR_ID 0x1137 #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF 0x0071 /* enet SRIOV VF */ /* Special Filter id for non-specific packet flagging. Don't change value */ #define ENIC_MAGIC_FILTER_ID 0xffff #define ENICPMD_FDIR_MAX 64 /* HW default VXLAN port */ #define ENIC_DEFAULT_VXLAN_PORT 4789 /* * Interrupt 0: LSC and errors * Interrupt 1: rx queue 0 * Interrupt 2: rx queue 1 * ... */ #define ENICPMD_LSC_INTR_OFFSET 0 #define ENICPMD_RXQ_INTR_OFFSET 1 #include "vnic_devcmd.h" enum vnic_proxy_type { PROXY_NONE, PROXY_BY_BDF, PROXY_BY_INDEX, }; struct vnic_intr_coal_timer_info { u32 mul; u32 div; u32 max_usec; }; struct enic_softc; struct vnic_dev { void *priv; struct rte_pci_device *pdev; struct vnic_res res[RES_TYPE_MAX]; enum vnic_dev_intr_mode intr_mode; struct vnic_res __iomem *devcmd; struct vnic_devcmd_notify *notify; struct vnic_devcmd_notify notify_copy; bus_addr_t notify_pa; struct iflib_dma_info notify_res; u32 notify_sz; struct iflib_dma_info linkstatus_res; struct vnic_stats *stats; struct iflib_dma_info stats_res; struct vnic_devcmd_fw_info *fw_info; struct iflib_dma_info fw_info_res; enum vnic_proxy_type proxy; u32 proxy_index; u64 args[VNIC_DEVCMD_NARGS]; int in_reset; struct vnic_intr_coal_timer_info intr_coal_timer_info; void *(*alloc_consistent)(void *priv, size_t size, bus_addr_t *dma_handle, struct iflib_dma_info *res, u8 *name); void (*free_consistent)(void *priv, size_t size, void *vaddr, bus_addr_t dma_handle, struct iflib_dma_info *res); struct vnic_counter_counts *flow_counters; struct iflib_dma_info flow_counters_res; u8 flow_counters_dma_active; struct enic_softc *softc; }; struct enic_soft_stats { uint64_t rx_nombuf; uint64_t rx_packet_errors; uint64_t tx_oversized; }; struct intr_queue { struct if_irq intr_irq; struct resource *res; int rid; struct enic_softc *softc; }; struct enic { struct enic *next; struct rte_pci_device *pdev; struct vnic_enet_config config; struct vnic_dev_bar bar0; struct vnic_dev *vdev; /* * mbuf_initializer contains 64 bits of mbuf rearm_data, used by * the avx2 handler at this time. */ uint64_t mbuf_initializer; unsigned int port_id; bool overlay_offload; char bdf_name[ENICPMD_BDF_LENGTH]; int dev_fd; int iommu_group_fd; int iommu_groupid; int eventfd; uint8_t mac_addr[ETH_ALEN]; pthread_t err_intr_thread; u8 ig_vlan_strip_en; int link_status; u8 hw_ip_checksum; u16 max_mtu; u8 adv_filters; u32 flow_filter_mode; u8 filter_actions; /* HW supported actions */ bool vxlan; bool disable_overlay; /* devargs disable_overlay=1 */ uint8_t enable_avx2_rx; /* devargs enable-avx2-rx=1 */ bool nic_cfg_chk; /* NIC_CFG_CHK available */ bool udp_rss_weak; /* Bodega style UDP RSS */ uint8_t ig_vlan_rewrite_mode; /* devargs ig-vlan-rewrite */ uint16_t vxlan_port; /* current vxlan port pushed to NIC */ unsigned int flags; unsigned int priv_flags; /* work queue (len = conf_wq_count) */ struct vnic_wq *wq; unsigned int wq_count; /* equals eth_dev nb_tx_queues */ /* receive queue (len = conf_rq_count) */ struct vnic_rq *rq; unsigned int rq_count; /* equals eth_dev nb_rx_queues */ /* completion queue (len = conf_cq_count) */ struct vnic_cq *cq; unsigned int cq_count; /* equals rq_count + wq_count */ /* interrupt vectors (len = conf_intr_count) */ struct vnic_intr *intr; struct intr_queue *intr_queues;; unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */ /* software counters */ struct enic_soft_stats soft_stats; /* configured resources on vic */ unsigned int conf_rq_count; unsigned int conf_wq_count; unsigned int conf_cq_count; unsigned int conf_intr_count; /* linked list storing memory allocations */ LIST_HEAD(enic_memzone_list, enic_memzone_entry) memzone_list; LIST_HEAD(enic_flows, rte_flow) flows; int max_flow_counter; /* RSS */ uint16_t reta_size; uint8_t hash_key_size; uint64_t flow_type_rss_offloads; /* 0 indicates RSS not supported */ /* * Keep a copy of current RSS config for queries, as we cannot retrieve * it from the NIC. */ uint8_t rss_hash_type; /* NIC_CFG_RSS_HASH_TYPE flags */ uint8_t rss_enable; uint64_t rss_hf; /* ETH_RSS flags */ union vnic_rss_key rss_key; union vnic_rss_cpu rss_cpu; uint64_t rx_offload_capa; /* DEV_RX_OFFLOAD flags */ uint64_t tx_offload_capa; /* DEV_TX_OFFLOAD flags */ uint64_t tx_queue_offload_capa; /* DEV_TX_OFFLOAD flags */ uint64_t tx_offload_mask; /* PKT_TX flags accepted */ struct enic_softc *softc; int port_mtu; }; struct enic_softc { device_t dev; if_ctx_t ctx; if_softc_ctx_t scctx; if_shared_ctx_t sctx; struct ifmedia *media; if_t ifp; struct mtx enic_lock; struct enic_bar_info mem; struct enic_bar_info io; struct vnic_dev vdev; struct enic enic; int ntxqsets; int nrxqsets; struct if_irq enic_event_intr_irq; struct if_irq enic_err_intr_irq; uint8_t lladdr[ETHER_ADDR_LEN]; int link_active; int stopped; uint8_t mac_addr[ETHER_ADDR_LEN]; int directed; int multicast; int broadcast; int promisc; int allmulti; u_int mc_count; uint8_t *mta; }; /* Per-instance private data structure */ static inline unsigned int enic_vnic_rq_count(struct enic *enic) { return enic->rq_count; } static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq) { return rq; } static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq) { return enic->rq_count + wq; } static inline uint32_t enic_ring_add(uint32_t n_descriptors, uint32_t i0, uint32_t i1) { uint32_t d = i0 + i1; d -= (d >= n_descriptors) ? n_descriptors : 0; return d; } static inline uint32_t enic_ring_sub(uint32_t n_descriptors, uint32_t i0, uint32_t i1) { int32_t d = i1 - i0; return (uint32_t)((d < 0) ? ((int32_t)n_descriptors + d) : d); } static inline uint32_t enic_ring_incr(uint32_t n_descriptors, uint32_t idx) { idx++; if (unlikely(idx == n_descriptors)) idx = 0; return idx; } void enic_free_wq(void *txq); int enic_alloc_intr_resources(struct enic *enic); int enic_setup_finish(struct enic *enic); int enic_alloc_wq(struct enic *enic, uint16_t queue_idx, unsigned int socket_id, uint16_t nb_desc); void enic_start_wq(struct enic *enic, uint16_t queue_idx); int enic_stop_wq(struct enic *enic, uint16_t queue_idx); void enic_start_rq(struct enic *enic, uint16_t queue_idx); void enic_free_rq(void *rxq); int enic_set_vnic_res(struct enic *enic); int enic_init_rss_nic_cfg(struct enic *enic); int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu); int enic_set_vlan_strip(struct enic *enic); int enic_enable(struct enic *enic); int enic_disable(struct enic *enic); void enic_remove(struct enic *enic); int enic_get_link_status(struct enic *enic); void enic_dev_stats_clear(struct enic *enic); void enic_add_packet_filter(struct enic *enic); int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr); int enic_del_mac_address(struct enic *enic, int mac_index); unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq); void enic_post_wq_index(struct vnic_wq *wq); int enic_probe(struct enic *enic); int enic_clsf_init(struct enic *enic); void enic_clsf_destroy(struct enic *enic); int enic_set_mtu(struct enic *enic, uint16_t new_mtu); int enic_link_update(struct enic *enic); bool enic_use_vector_rx_handler(struct enic *enic); void enic_fdir_info(struct enic *enic); void enic_prep_wq_for_simple_tx(struct enic *, uint16_t); struct enic_ring { uint64_t paddr; caddr_t vaddr; struct enic_softc *softc; uint32_t ring_size; /* Must be a power of two */ uint16_t id; /* Logical ID */ uint16_t phys_id; }; struct enic_cp_ring { struct enic_ring ring; struct if_irq irq; uint32_t cons; bool v_bit; /* Value of valid bit */ struct ctx_hw_stats *stats; uint32_t stats_ctx_id; uint32_t last_idx; /* Used by RX rings only * set to the last read pidx */ }; #endif /* _ENIC_H_ */