Index: Makefile.inc1 =================================================================== --- Makefile.inc1 +++ Makefile.inc1 @@ -232,6 +232,10 @@ .endif .endfor +# If a full path to an external linker is given, don't build lld. +.if ${XLD:M/*} +MK_LLD_BOOTSTRAP= no +.endif # We must do lib/ and libexec/ before bin/ in case of a mid-install error to # keep the users system reasonably usable. For static->dynamic root upgrades, Index: cddl/lib/libdtrace/ip.d =================================================================== --- cddl/lib/libdtrace/ip.d +++ cddl/lib/libdtrace/ip.d @@ -228,11 +228,11 @@ ((struct ip *)p)->ip_v == 4 ? ntohs(((struct ip *)p)->ip_len) - (((struct ip *)p)->ip_hl << 2): ntohs(((struct ip6_hdr *)p)->ip6_ctlun.ip6_un1.ip6_un1_plen); - ip_saddr = p == NULL ? 0 : + ip_saddr = p == NULL ? "" : ((struct ip *)p)->ip_v == 4 ? inet_ntoa(&((struct ip *)p)->ip_src.s_addr) : inet_ntoa6(&((struct ip6_hdr *)p)->ip6_src); - ip_daddr = p == NULL ? 0 : + ip_daddr = p == NULL ? "" : ((struct ip *)p)->ip_v == 4 ? inet_ntoa(&((struct ip *)p)->ip_dst.s_addr) : inet_ntoa6(&((struct ip6_hdr *)p)->ip6_dst); @@ -246,11 +246,11 @@ ntohs(((struct ip *)m->m_data)->ip_len) - (((struct ip *)m->m_data)->ip_hl << 2): ntohs(((struct ip6_hdr *)m->m_data)->ip6_ctlun.ip6_un1.ip6_un1_plen); - ip_saddr = m == NULL ? 0 : + ip_saddr = m == NULL ? "" : ((struct ip *)m->m_data)->ip_v == 4 ? inet_ntoa(&((struct ip *)m->m_data)->ip_src.s_addr) : inet_ntoa6(&((struct ip6_hdr *)m->m_data)->ip6_src); - ip_daddr = m == NULL ? 0 : + ip_daddr = m == NULL ? "" : ((struct ip *)m->m_data)->ip_v == 4 ? inet_ntoa(&((struct ip *)m->m_data)->ip_dst.s_addr) : inet_ntoa6(&((struct ip6_hdr *)m->m_data)->ip6_dst); Index: cddl/lib/libdtrace/tcp.d =================================================================== --- cddl/lib/libdtrace/tcp.d +++ cddl/lib/libdtrace/tcp.d @@ -190,11 +190,11 @@ tcps_active = -1; /* XXX */ tcps_lport = p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_lport); tcps_rport = p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_fport); - tcps_laddr = p == NULL ? 0 : + tcps_laddr = p == NULL ? "" : p->t_inpcb->inp_vflag == INP_IPV4 ? inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.id46_addr.ia46_addr4.s_addr) : inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.id6_addr); - tcps_raddr = p == NULL ? 0 : + tcps_raddr = p == NULL ? "" : p->t_inpcb->inp_vflag == INP_IPV4 ? inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.id46_addr.ia46_addr4.s_addr) : inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.id6_addr); Index: cddl/lib/libdtrace/udp.d =================================================================== --- cddl/lib/libdtrace/udp.d +++ cddl/lib/libdtrace/udp.d @@ -56,11 +56,11 @@ udps_addr = (uintptr_t)p; udps_lport = p == NULL ? 0 : ntohs(p->inp_inc.inc_ie.ie_lport); udps_rport = p == NULL ? 0 : ntohs(p->inp_inc.inc_ie.ie_fport); - udps_laddr = p == NULL ? "" : + udps_laddr = p == NULL ? "" : p->inp_vflag == INP_IPV4 ? inet_ntoa(&p->inp_inc.inc_ie.ie_dependladdr.id46_addr.ia46_addr4.s_addr) : inet_ntoa6(&p->inp_inc.inc_ie.ie_dependladdr.id6_addr); - udps_raddr = p == NULL ? "" : + udps_raddr = p == NULL ? "" : p->inp_vflag == INP_IPV4 ? inet_ntoa(&p->inp_inc.inc_ie.ie_dependfaddr.id46_addr.ia46_addr4.s_addr) : inet_ntoa6(&p->inp_inc.inc_ie.ie_dependfaddr.id6_addr); Index: contrib/amd/amq/amq.c =================================================================== --- contrib/amd/amq/amq.c +++ contrib/amd/amq/amq.c @@ -79,7 +79,7 @@ static void time_print(time_type tt) { - time_t t = (time_t)*tt; + time_t t = (time_t)(intptr_t)tt; struct tm *tp = localtime(&t); printf("%02d/%02d/%04d %02d:%02d:%02d", tp->tm_mon + 1, tp->tm_mday, Index: lib/libcapsicum/Makefile =================================================================== --- lib/libcapsicum/Makefile +++ lib/libcapsicum/Makefile @@ -6,6 +6,8 @@ MAN+= capsicum_helpers.3 +MLINKS+=capsicum_helpers.3 caph_enter.3 +MLINKS+=capsicum_helpers.3 caph_enter_casper.3 MLINKS+=capsicum_helpers.3 caph_limit_stream.3 MLINKS+=capsicum_helpers.3 caph_limit_stdin.3 MLINKS+=capsicum_helpers.3 caph_limit_stderr.3 Index: lib/libnv/tests/Makefile =================================================================== --- lib/libnv/tests/Makefile +++ lib/libnv/tests/Makefile @@ -7,6 +7,7 @@ nv_tests \ TAP_TESTS_C+= nvlist_add_test +TAP_TESTS_C+= nvlist_append_test TAP_TESTS_C+= nvlist_exists_test TAP_TESTS_C+= nvlist_free_test TAP_TESTS_C+= nvlist_get_test Index: lib/libnv/tests/cnv_tests.cc =================================================================== --- lib/libnv/tests/cnv_tests.cc +++ lib/libnv/tests/cnv_tests.cc @@ -575,7 +575,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - ATF_REQUIRE_EQ(cnvlist_take_bool(nvl, cookie), value); + ATF_REQUIRE_EQ(cnvlist_take_bool(cookie), value); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -618,7 +618,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - ATF_REQUIRE_EQ(cnvlist_take_number(nvl, cookie), value); + ATF_REQUIRE_EQ(cnvlist_take_number(cookie), value); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -662,7 +662,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - out_string = cnvlist_take_string(nvl, cookie); + out_string = cnvlist_take_string(cookie); ATF_REQUIRE(out_string != NULL); ATF_REQUIRE_EQ(strcmp(out_string, value), 0); @@ -725,7 +725,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - result = cnvlist_take_nvlist(nvl, cookie); + result = cnvlist_take_nvlist(cookie); ATF_REQUIRE(!nvlist_exists_nvlist(nvl, key)); ATF_REQUIRE(result == value); @@ -784,7 +784,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - out_array = cnvlist_take_bool_array(nvl, cookie, &nitems); + out_array = cnvlist_take_bool_array(cookie, &nitems); ATF_REQUIRE_EQ(nitems, 16); ATF_REQUIRE(out_array != NULL); for (i = 0; i < 16; i++) @@ -836,7 +836,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - out_array = cnvlist_take_number_array(nvl, cookie, &nitems); + out_array = cnvlist_take_number_array(cookie, &nitems); ATF_REQUIRE(out_array != NULL); ATF_REQUIRE_EQ(nitems, 16); @@ -885,7 +885,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - out_array = cnvlist_take_string_array(nvl, cookie, &nitems); + out_array = cnvlist_take_string_array(cookie, &nitems); ATF_REQUIRE_EQ(nitems, 4); for (i = 0; i < 4; i++) { ATF_REQUIRE(out_array[i] != NULL); @@ -957,7 +957,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - result = cnvlist_take_nvlist_array(nvl, cookie, &num_items); + result = cnvlist_take_nvlist_array(cookie, &num_items); ATF_REQUIRE(result != NULL); ATF_REQUIRE_EQ(num_items, 8); @@ -1022,7 +1022,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - out_binary = cnvlist_take_binary(nvl, cookie, &out_size); + out_binary = cnvlist_take_binary(cookie, &out_size); ATF_REQUIRE_EQ(out_size, in_size); ATF_REQUIRE_EQ(memcmp(in_binary, out_binary, out_size), 0); @@ -1069,7 +1069,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_bool(nvl, cookie); + cnvlist_free_bool(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1112,7 +1112,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_number(nvl, cookie); + cnvlist_free_number(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1155,7 +1155,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_string(nvl, cookie); + cnvlist_free_string(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1215,7 +1215,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_nvlist(nvl, cookie); + cnvlist_free_nvlist(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1262,7 +1262,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_binary(nvl, cookie); + cnvlist_free_binary(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1309,7 +1309,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_bool_array(nvl, cookie); + cnvlist_free_bool_array(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1354,7 +1354,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_number_array(nvl, cookie); + cnvlist_free_number_array(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1396,7 +1396,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_string_array(nvl, cookie); + cnvlist_free_string_array(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); @@ -1459,7 +1459,7 @@ cookie = NULL; ATF_REQUIRE_EQ(strcmp(key, nvlist_next(nvl, &type, &cookie)), 0); - cnvlist_free_nvlist_array(nvl, cookie); + cnvlist_free_nvlist_array(cookie); cookie = NULL; ATF_REQUIRE_EQ(nvlist_error(nvl), 0); Index: lib/libnv/tests/nv_array_tests.cc =================================================================== --- lib/libnv/tests/nv_array_tests.cc +++ lib/libnv/tests/nv_array_tests.cc @@ -312,6 +312,7 @@ for (i = 0; i < num_items; i++) { ATF_REQUIRE_EQ(nvlist_error(result[i]), 0); ATF_REQUIRE(nvlist_get_array_next(result[i]) == NULL); + ATF_REQUIRE(nvlist_get_parent(result[i], NULL) == NULL); ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL); ATF_REQUIRE(!nvlist_in_array(const_result[i])); } Index: lib/libnv/tests/nvlist_append_test.c =================================================================== --- /dev/null +++ lib/libnv/tests/nvlist_append_test.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include + +static int ntest = 1; + +#define CHECK(expr) do { \ + if ((expr)) \ + printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \ + else \ + printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\ + ntest++; \ +} while (0) + +int +main(void) +{ + const bool *bool_result; + const char * const *string_result; + const nvlist_t * const *nvl_result; + nvlist_t *nvl, *nvl1, *nvl2, **items; + unsigned int i; + size_t nitems; + + printf("1..32\n"); + + nvl = nvlist_create(0); + + for (i = 0; i < 16; i++) + nvlist_append_bool_array(nvl, "nvl/bool", i % 2 == 0); + + CHECK(nvlist_error(nvl) == 0); + CHECK(!nvlist_empty(nvl)); + CHECK(nvlist_exists_bool_array(nvl, "nvl/bool")); + + bool_result = nvlist_get_bool_array(nvl, "nvl/bool", &nitems); + CHECK(nitems == 16); + CHECK(bool_result != NULL); + for (i = 0; i < nitems; i++) + CHECK(bool_result[i] == (i % 2 == 0)); + + + nvlist_append_string_array(nvl, "nvl/string", "a"); + nvlist_append_string_array(nvl, "nvl/string", "abc"); + string_result = nvlist_get_string_array(nvl, "nvl/string", &nitems); + CHECK(nitems == 2); + CHECK(strcmp(string_result[0], "a") == 0); + CHECK(strcmp(string_result[1], "abc") == 0); + + + nvl1 = nvlist_create(0); + nvlist_add_string(nvl1, "key1", "test1"); + nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl1); + nvlist_destroy(nvl1); + + nvl2 = nvlist_create(0); + nvlist_add_string(nvl2, "key2", "test2"); + nvlist_append_nvlist_array(nvl, "nvl/nvl", nvl2); + nvlist_destroy(nvl2); + + nvl_result = nvlist_get_nvlist_array(nvl, "nvl/nvl", &nitems); + CHECK(nitems == 2); + CHECK(strcmp(nvlist_get_string(nvl_result[0], "key1"), "test1") == 0); + CHECK(strcmp(nvlist_get_string(nvl_result[1], "key2"), "test2") == 0); + + nvl1 = nvlist_create(0); + nvlist_add_number(nvl1, "key1", 10); + nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl1); + nvlist_destroy(nvl1); + + nvl2 = nvlist_create(0); + nvlist_add_number(nvl2, "key1", 20); + nvlist_append_nvlist_array(nvl, "nvl/nvl_array", nvl2); + nvlist_destroy(nvl2); + + items = nvlist_take_nvlist_array(nvl, "nvl/nvl_array", &nitems); + CHECK(nvlist_get_number(items[0], "key1") == 10); + CHECK(nvlist_get_number(items[1], "key1") == 20); + CHECK(nvlist_error(items[0]) == 0); + CHECK(nvlist_error(items[1]) == 0); + + nvlist_move_nvlist_array(nvl, "nvl/nvl_new_array", items, nitems); + CHECK(nvlist_error(nvl) == 0); + + nvlist_destroy(nvl); + + return (0); +} Index: share/man/man7/hier.7 =================================================================== --- share/man/man7/hier.7 +++ share/man/man7/hier.7 @@ -28,7 +28,7 @@ .\" @(#)hier.7 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd April 2, 2018 +.Dd June 18, 2018 .Dt HIER 7 .Os .Sh NAME @@ -474,7 +474,7 @@ .It Pa ja/ Japanese translations of documents in /usr/share/doc .It Pa legal/ -License files for vendor supplied firmwares +License files for vendor supplied firmware files .It Pa ncurses/ HTML documents pertaining to ncurses; see @@ -623,7 +623,7 @@ source code for files in .Pa /usr/include .It Pa kerberos5/ -build infrastructure for kerberos version 5 +build infrastructure for Kerberos version 5 .It Pa lib/ source code for files in .Pa /lib @@ -801,7 +801,7 @@ .It Pa games/ miscellaneous game status and score files .It Pa heimdal/ -kerberos server databases; see +Kerberos server databases; see .Xr kdc 8 .It Pa log/ miscellaneous system log files Index: share/man/man9/cnv.9 =================================================================== --- share/man/man9/cnv.9 +++ share/man/man9/cnv.9 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 18, 2018 +.Dd June 18, 2018 .Dt CNV 9 .Os .Sh NAME @@ -38,80 +38,80 @@ .Sh SYNOPSIS .In sys/cnv.h .Ft const char * -.Fn cnvlist_name "void *cookiep" +.Fn cnvlist_name "const void *cookie" .Ft int -.Fn cnvlist_type "void *cookiep" +.Fn cnvlist_type "const void *cookie" .\" .Ft bool -.Fn cnvlist_get_bool "void *cookiep" +.Fn cnvlist_get_bool "const void *cookie" .Ft uint64_t -.Fn cnvlist_get_number "void *cookiep" +.Fn cnvlist_get_number "const void *cookie" .Ft "const char *" -.Fn cnvlist_get_string "void *cookiep" +.Fn cnvlist_get_string "const void *cookie" .Ft "const nvlist_t *" -.Fn cnvlist_get_nvlist "void *cookiep" +.Fn cnvlist_get_nvlist "const void *cookie" .Ft "const void *" -.Fn cnvlist_get_binary "void *cookiep" "size_t *sizep" +.Fn cnvlist_get_binary "const void *cookie" "size_t *sizep" .Ft "const bool *" -.Fn cnvlist_get_bool_array "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_get_bool_array "const void *cookie" "size_t *nitemsp" .Ft "const uint64_t *" -.Fn cnvlist_get_number_array "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_get_number_array "const void *cookie" "size_t *nitemsp" .Ft "const char * const *" -.Fn cnvlist_get_string_array "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_get_string_array "const void *cookie" "size_t *nitemsp" .Ft "const nvlist_t * const *" -.Fn cnvlist_get_nvlist_array "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_get_nvlist_array "const void *cookie" "size_t *nitemsp" .Ft int -.Fn cnvlist_get_descriptor "void *cookiep" +.Fn cnvlist_get_descriptor "const void *cookie" .Ft "const int *" -.Fn cnvlist_get_descriptor_array "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_get_descriptor_array "const void *cookie" "size_t *nitemsp" .\" .Ft bool -.Fn cnvlist_take_bool "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_take_bool "void *cookie" .Ft uint64_t -.Fn cnvlist_take_number "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_take_number "void *cookie" .Ft "const char *" -.Fn cnvlist_take_string "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_take_string "void *cookie" .Ft "const nvlist_t *" -.Fn cnvlist_take_nvlist "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_take_nvlist "void *cookie" .Ft "const void *" -.Fn cnvlist_take_binary "nvlist_t *nvl" "void *cookiep" "size_t *sizep" +.Fn cnvlist_take_binary "void *cookie" "size_t *sizep" .Ft "const bool *" -.Fn cnvlist_take_bool_array "nvlist_t *nvl" "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_take_bool_array "void *cookie" "size_t *nitemsp" .Ft "const uint64_t *" -.Fn cnvlist_take_number_array "nvlist_t *nvl" "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_take_number_array "void *cookie" "size_t *nitemsp" .Ft "const char * const *" -.Fn cnvlist_take_string_array "nvlist_t *nvl" "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_take_string_array "void *cookie" "size_t *nitemsp" .Ft "const nvlist_t * const *" -.Fn cnvlist_take_nvlist_array "nvlist_t *nvl" "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_take_nvlist_array "void *cookie" "size_t *nitemsp" .Ft int -.Fn cnvlist_take_descriptor "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_take_descriptor "void *cookie" .Ft "const int *" -.Fn cnvlist_take_descriptor_array "nvlist_t *nvl" "void *cookiep" "size_t *nitemsp" +.Fn cnvlist_take_descriptor_array "void *cookie" "size_t *nitemsp" .\" .Ft void -.Fn cnvlist_free_null "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_null "void *cookie" .Ft void -.Fn cnvlist_free_bool "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_bool "void *cookie" .Ft void -.Fn cnvlist_free_number "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_number "void *cookie" .Ft void -.Fn cnvlist_free_string "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_string "void *cookie" .Ft void -.Fn cnvlist_free_nvlist "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_nvlist "void *cookie" .Ft void -.Fn cnvlist_free_descriptor "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_descriptor "void *cookie" .Ft void -.Fn cnvlist_free_binary "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_binary "void *cookie" .Ft void -.Fn cnvlist_free_bool_array "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_bool_array "void *cookie" .Ft void -.Fn cnvlist_free_number_array "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_number_array "void *cookie" .Ft void -.Fn cnvlist_free_string_array "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_string_array "void *cookie" .Ft void -.Fn cnvlist_free_nvlist_array "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_nvlist_array "void *cookie" .Ft void -.Fn cnvlist_free_descriptor_array "nvlist_t *nvl" "void *cookiep" +.Fn cnvlist_free_descriptor_array "void *cookie" .Sh DESCRIPTION The .Nm libnv @@ -192,8 +192,8 @@ } } -name = cnvlist_take_string(nvl, scookie); -cnvlist_free_bool(nvl, bcookie); +name = cnvlist_take_string(scookie); +cnvlist_free_bool(bcookie); printf("test2: %s\\n", name); free(name); Index: share/man/man9/nv.9 =================================================================== --- share/man/man9/nv.9 +++ share/man/man9/nv.9 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 16, 2017 +.Dd June 19, 2018 .Dt NV 9 .Os .Sh NAME @@ -55,7 +55,8 @@ .Nm nvlist_add , .Nm nvlist_move , .Nm nvlist_get , -.Nm nvlist_take +.Nm nvlist_take , +.Nm nvlist_append .Nd "library for name/value pairs" .Sh LIBRARY .Lb libnv @@ -239,6 +240,17 @@ .Fn nvlist_take_descriptor_array "nvlist_t *nvl" "const char *name" "size_t *nitems" .\" .Ft void +.Fn nvlist_append_bool_array "nvlist_t *nvl" "const char *name" "const bool value" +.Ft void +.Fn nvlist_append_number_array "nvlist_t *nvl" "const char *name" "const uint64_t value" +.Ft void +.Fn nvlist_append_string_array "nvlist_t *nvl" "const char *name" "const char * const value" +.Ft void +.Fn nvlist_append_nvlist_array "nvlist_t *nvl" "const char *name" "const nvlist_t * const value" +.Ft void +.Fn nvlist_append_descriptor_array "nvlist_t *nvl" "const char *name" "int value" +.\" +.Ft void .Fn nvlist_free "nvlist_t *nvl" "const char *name" .Ft void .Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type" @@ -577,7 +589,7 @@ .Fn nvlist_add_nvlist_array , .Fn nvlist_add_descriptor_array functions add element to the given nvlist. -When adding string or binary buffor the functions will allocate memory +When adding string or binary buffer the functions will allocate memory and copy the data over. When adding nvlist, the nvlist will be cloned and clone will be added. When adding descriptor, the descriptor will be duplicated using the @@ -710,6 +722,20 @@ The nvlist must not be in error state. .Pp The +.Fn nvlist_append_bool_array , +.Fn nvlist_append_number_array , +.Fn nvlist_append_string_array , +.Fn nvlist_append_nvlist_array , +.Fn nvlist_append_descriptor_array +functions append an element to the existing array using the same semantics +as the add functions (i.e. the element will be copied when applicable). +If the array for a given key does not exist, then it will be created +as if using the +.Fn nvlist_add__array +function. +The internal error is set on append failure. +.Pp +The .Fn nvlist_free function removes element of the given name from the nvlist (besides of its type) and frees all resources associated with it. @@ -742,6 +768,13 @@ If element of the given name and the given type does not exist, the program will be aborted. The nvlist must not be in error state. +.Sh NOTES +The +.Fn nvlist_pack +and +.Fn nvlist_unpack +functions handle the byte-order conversions, so the binary buffer can be +packed/unpacked by the hosts with the different endianness. .Sh EXAMPLES The following example demonstrates how to prepare an nvlist and send it over .Xr unix 4 Index: stand/Makefile =================================================================== --- stand/Makefile +++ stand/Makefile @@ -21,8 +21,6 @@ S.yes+= defaults S.yes+= man -S.${MK_LOADER_GELI}+= geli - .include S.${MK_EFI}+= efi Index: stand/defs.mk =================================================================== --- stand/defs.mk +++ stand/defs.mk @@ -67,8 +67,7 @@ .endif .if ${MK_LOADER_GELI} == "yes" CFLAGS+= -DLOADER_GELI_SUPPORT -CFLAGS+= -I${BOOTSRC}/geli -LIBGELIBOOT= ${BOOTOBJ}/geli/libgeliboot.a +CFLAGS+= -I${SASRC}/geli .endif # MK_LOADER_GELI .endif # HAVE_GELI Index: stand/geli/Makefile.depend =================================================================== --- stand/geli/Makefile.depend +++ /dev/null @@ -1,15 +0,0 @@ -# $FreeBSD$ -# Autogenerated - do NOT edit! - -DIRDEPS = \ - include \ - include/xlocale \ - lib/libmd \ - secure/lib/libcrypto \ - - -.include - -.if ${DEP_RELDIR} == ${_DEP_RELDIR} -# local dependencies - needed for -jN in clean tree -.endif Index: stand/geli/geliboot.h =================================================================== --- /dev/null +++ stand/geli/geliboot.h @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 2015 Allan Jude - * Copyright (c) 2005-2011 Pawel Jakub Dawidek - * All rights reserved. - * - * 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 AUTHORS 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 AUTHORS 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. - * - * $FreeBSD$ - */ - -#include - -#ifndef _GELIBOOT_H_ -#define _GELIBOOT_H_ - -#ifndef DEV_BSIZE -#define DEV_BSIZE 512 -#endif -#ifndef DEV_GELIBOOT_BSIZE -#define DEV_GELIBOOT_BSIZE 4096 -#endif - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -#define GELI_MAX_KEYS 64 -#define GELI_PW_MAXLEN 256 - -extern void pwgets(char *buf, int n, int hide); - -struct dsk; - -void geli_init(void); -int geli_taste(int read_func(void *vdev, void *priv, off_t off, - void *buf, size_t bytes), struct dsk *dsk, daddr_t lastsector); -int is_geli(struct dsk *dsk); -int geli_read(struct dsk *dsk, off_t offset, u_char *buf, size_t bytes); -int geli_decrypt(u_int algo, u_char *data, size_t datasize, - const u_char *key, size_t keysize, const uint8_t* iv); -int geli_havekey(struct dsk *dskp); -int geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp); - -int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize, - const u_char *key, size_t keysize, u_char *iv); - -void geli_fill_keybuf(struct keybuf *keybuf); -void geli_save_keybuf(struct keybuf *keybuf); - -#endif /* _GELIBOOT_H_ */ Index: stand/geli/geliboot.c =================================================================== --- /dev/null +++ stand/geli/geliboot.c @@ -1,437 +0,0 @@ -/*- - * Copyright (c) 2015 Allan Jude - * Copyright (c) 2005-2011 Pawel Jakub Dawidek - * All rights reserved. - * - * 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 AUTHORS 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 AUTHORS 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. - * - * $FreeBSD$ - */ - -#include "geliboot_internal.h" -#include "geliboot.h" - -SLIST_HEAD(geli_list, geli_entry) geli_head = SLIST_HEAD_INITIALIZER(geli_head); -struct geli_list *geli_headp; - -typedef u_char geli_ukey[G_ELI_USERKEYLEN]; - -static geli_ukey saved_keys[GELI_MAX_KEYS]; -static unsigned int nsaved_keys = 0; - -/* - * Copy keys from local storage to the keybuf struct. - * Destroy the local storage when finished. - */ -void -geli_fill_keybuf(struct keybuf *fkeybuf) -{ - unsigned int i; - - for (i = 0; i < nsaved_keys; i++) { - fkeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_GELI; - memcpy(fkeybuf->kb_ents[i].ke_data, saved_keys[i], - G_ELI_USERKEYLEN); - } - fkeybuf->kb_nents = nsaved_keys; - explicit_bzero(saved_keys, sizeof(saved_keys)); -} - -/* - * Copy keys from a keybuf struct into local storage. - * Zero out the keybuf. - */ -void -geli_save_keybuf(struct keybuf *skeybuf) -{ - unsigned int i; - - for (i = 0; i < skeybuf->kb_nents && i < GELI_MAX_KEYS; i++) { - memcpy(saved_keys[i], skeybuf->kb_ents[i].ke_data, - G_ELI_USERKEYLEN); - explicit_bzero(skeybuf->kb_ents[i].ke_data, - G_ELI_USERKEYLEN); - skeybuf->kb_ents[i].ke_type = KEYBUF_TYPE_NONE; - } - nsaved_keys = skeybuf->kb_nents; - skeybuf->kb_nents = 0; -} - -static void -save_key(geli_ukey key) -{ - - /* - * If we run out of key space, the worst that will happen is - * it will ask the user for the password again. - */ - if (nsaved_keys < GELI_MAX_KEYS) { - memcpy(saved_keys[nsaved_keys], key, G_ELI_USERKEYLEN); - nsaved_keys++; - } -} - -static int -geli_same_device(struct geli_entry *ge, struct dsk *dskp) -{ - - if (ge->dsk->drive == dskp->drive && - dskp->part == 255 && ge->dsk->part == dskp->slice) { - /* - * Sometimes slice = slice, and sometimes part = slice - * If the incoming struct dsk has part=255, it means look at - * the slice instead of the part number - */ - return (0); - } - - /* Is this the same device? */ - if (ge->dsk->drive != dskp->drive || - ge->dsk->slice != dskp->slice || - ge->dsk->part != dskp->part) { - return (1); - } - - return (0); -} - -static int -geli_findkey(struct geli_entry *ge, struct dsk *dskp, u_char *mkey) -{ - u_int keynum; - int i; - - if (ge->keybuf_slot >= 0) { - if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[ge->keybuf_slot], - mkey, &keynum) == 0) { - return (0); - } - } - - for (i = 0; i < nsaved_keys; i++) { - if (g_eli_mkey_decrypt_any(&ge->md, saved_keys[i], mkey, - &keynum) == 0) { - ge->keybuf_slot = i; - return (0); - } - } - - return (1); -} - -void -geli_init(void) -{ - - geli_count = 0; - SLIST_INIT(&geli_head); -} - -/* - * Read the last sector of the drive or partition pointed to by dsk and see - * if it is GELI encrypted - */ -int -geli_taste(int read_func(void *vdev, void *priv, off_t off, void *buf, - size_t bytes), struct dsk *dskp, daddr_t lastsector) -{ - struct g_eli_metadata md; - u_char buf[DEV_GELIBOOT_BSIZE]; - int error; - off_t alignsector; - - alignsector = rounddown2(lastsector * DEV_BSIZE, DEV_GELIBOOT_BSIZE); - if (alignsector + DEV_GELIBOOT_BSIZE > ((lastsector + 1) * DEV_BSIZE)) { - /* Don't read past the end of the disk */ - alignsector = (lastsector * DEV_BSIZE) + DEV_BSIZE - - DEV_GELIBOOT_BSIZE; - } - error = read_func(NULL, dskp, alignsector, &buf, DEV_GELIBOOT_BSIZE); - if (error != 0) { - return (error); - } - /* Extract the last 4k sector of the disk. */ - error = eli_metadata_decode(buf, &md); - if (error != 0) { - /* Try the last 512 byte sector instead. */ - error = eli_metadata_decode(buf + - (DEV_GELIBOOT_BSIZE - DEV_BSIZE), &md); - if (error != 0) { - return (error); - } - } - - if (!(md.md_flags & G_ELI_FLAG_GELIBOOT)) { - /* The GELIBOOT feature is not activated */ - return (1); - } - if ((md.md_flags & G_ELI_FLAG_ONETIME)) { - /* Swap device, skip it. */ - return (1); - } - if (md.md_iterations < 0) { - /* XXX TODO: Support loading key files. */ - /* Disk does not have a passphrase, skip it. */ - return (1); - } - geli_e = malloc(sizeof(struct geli_entry)); - if (geli_e == NULL) - return (2); - - geli_e->dsk = malloc(sizeof(struct dsk)); - if (geli_e->dsk == NULL) - return (2); - memcpy(geli_e->dsk, dskp, sizeof(struct dsk)); - geli_e->part_end = lastsector; - if (dskp->part == 255) { - geli_e->dsk->part = dskp->slice; - } - geli_e->keybuf_slot = -1; - - geli_e->md = md; - eli_metadata_softc(&geli_e->sc, &md, DEV_BSIZE, - (lastsector + DEV_BSIZE) * DEV_BSIZE); - - SLIST_INSERT_HEAD(&geli_head, geli_e, entries); - geli_count++; - - return (0); -} - -/* - * Attempt to decrypt the device - */ -static int -geli_attach(struct geli_entry *ge, struct dsk *dskp, const char *passphrase, - u_char *mkeyp) -{ - u_char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN], *mkp; - u_int keynum; - struct hmac_ctx ctx; - int error; - - if (mkeyp != NULL) { - memcpy(&mkey, mkeyp, G_ELI_DATAIVKEYLEN); - explicit_bzero(mkeyp, G_ELI_DATAIVKEYLEN); - } - - if (mkeyp != NULL || geli_findkey(ge, dskp, mkey) == 0) { - goto found_key; - } - - g_eli_crypto_hmac_init(&ctx, NULL, 0); - /* - * Prepare Derived-Key from the user passphrase. - */ - if (geli_e->md.md_iterations < 0) { - /* XXX TODO: Support loading key files. */ - return (1); - } else if (geli_e->md.md_iterations == 0) { - g_eli_crypto_hmac_update(&ctx, geli_e->md.md_salt, - sizeof(geli_e->md.md_salt)); - g_eli_crypto_hmac_update(&ctx, (const uint8_t *)passphrase, - strlen(passphrase)); - } else if (geli_e->md.md_iterations > 0) { - printf("Calculating GELI Decryption Key disk%dp%d @ %d" - " iterations...\n", dskp->unit, - (dskp->slice > 0 ? dskp->slice : dskp->part), - geli_e->md.md_iterations); - u_char dkey[G_ELI_USERKEYLEN]; - - pkcs5v2_genkey(dkey, sizeof(dkey), geli_e->md.md_salt, - sizeof(geli_e->md.md_salt), passphrase, - geli_e->md.md_iterations); - g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); - explicit_bzero(dkey, sizeof(dkey)); - } - - g_eli_crypto_hmac_final(&ctx, key, 0); - - error = g_eli_mkey_decrypt_any(&geli_e->md, key, mkey, &keynum); - if (error == -1) { - explicit_bzero(mkey, sizeof(mkey)); - explicit_bzero(key, sizeof(key)); - printf("Bad GELI key: bad password?\n"); - return (error); - } else if (error != 0) { - explicit_bzero(mkey, sizeof(mkey)); - explicit_bzero(key, sizeof(key)); - printf("Failed to decrypt GELI master key: %d\n", error); - return (error); - } else { - /* Add key to keychain */ - save_key(key); - explicit_bzero(&key, sizeof(key)); - } - -found_key: - /* Store the keys */ - bcopy(mkey, geli_e->sc.sc_mkey, sizeof(geli_e->sc.sc_mkey)); - bcopy(mkey, geli_e->sc.sc_ivkey, sizeof(geli_e->sc.sc_ivkey)); - mkp = mkey + sizeof(geli_e->sc.sc_ivkey); - if ((geli_e->sc.sc_flags & G_ELI_FLAG_AUTH) == 0) { - bcopy(mkp, geli_e->sc.sc_ekey, G_ELI_DATAKEYLEN); - } else { - /* - * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10) - */ - g_eli_crypto_hmac(mkp, G_ELI_MAXKEYLEN, (const uint8_t *)"\x10", 1, - geli_e->sc.sc_ekey, 0); - } - explicit_bzero(mkey, sizeof(mkey)); - - /* Initialize the per-sector IV. */ - switch (geli_e->sc.sc_ealgo) { - case CRYPTO_AES_XTS: - break; - default: - SHA256_Init(&geli_e->sc.sc_ivctx); - SHA256_Update(&geli_e->sc.sc_ivctx, geli_e->sc.sc_ivkey, - sizeof(geli_e->sc.sc_ivkey)); - break; - } - - return (0); -} - -int -is_geli(struct dsk *dskp) -{ - SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { - if (geli_same_device(geli_e, dskp) == 0) { - return (0); - } - } - - return (1); -} - -int -geli_read(struct dsk *dskp, off_t offset, u_char *buf, size_t bytes) -{ - u_char iv[G_ELI_IVKEYLEN]; - u_char *pbuf; - int error; - off_t dstoff; - uint64_t keyno; - size_t n, nsec, secsize; - struct g_eli_key gkey; - - pbuf = buf; - SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { - if (geli_same_device(geli_e, dskp) != 0) { - continue; - } - - secsize = geli_e->sc.sc_sectorsize; - nsec = bytes / secsize; - if (nsec == 0) { - /* - * A read of less than the GELI sector size has been - * requested. The caller provided destination buffer may - * not be big enough to boost the read to a full sector, - * so just attempt to decrypt the truncated sector. - */ - secsize = bytes; - nsec = 1; - } - - for (n = 0, dstoff = offset; n < nsec; n++, dstoff += secsize) { - - g_eli_crypto_ivgen(&geli_e->sc, dstoff, iv, - G_ELI_IVKEYLEN); - - /* Get the key that corresponds to this offset. */ - keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize; - g_eli_key_fill(&geli_e->sc, &gkey, keyno); - - error = geliboot_crypt(geli_e->sc.sc_ealgo, 0, pbuf, - secsize, gkey.gek_key, - geli_e->sc.sc_ekeylen, iv); - - if (error != 0) { - explicit_bzero(&gkey, sizeof(gkey)); - printf("Failed to decrypt in geli_read()!"); - return (error); - } - pbuf += secsize; - } - explicit_bzero(&gkey, sizeof(gkey)); - return (0); - } - - printf("GELI provider not found\n"); - return (1); -} - -int -geli_havekey(struct dsk *dskp) -{ - u_char mkey[G_ELI_DATAIVKEYLEN]; - - SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { - if (geli_same_device(geli_e, dskp) != 0) { - continue; - } - - if (geli_findkey(geli_e, dskp, mkey) == 0) { - if (geli_attach(geli_e, dskp, NULL, mkey) == 0) { - return (0); - } - } - } - explicit_bzero(mkey, sizeof(mkey)); - - return (1); -} - -int -geli_passphrase(char *pw, int disk, int parttype, int part, struct dsk *dskp) -{ - int i; - - SLIST_FOREACH_SAFE(geli_e, &geli_head, entries, geli_e_tmp) { - if (geli_same_device(geli_e, dskp) != 0) { - continue; - } - - /* TODO: Implement GELI keyfile(s) support */ - for (i = 0; i < 3; i++) { - /* Try cached passphrase */ - if (i == 0 && pw[0] != '\0') { - if (geli_attach(geli_e, dskp, pw, NULL) == 0) { - return (0); - } - } - printf("GELI Passphrase for disk%d%c%d: ", disk, - parttype, part); - pwgets(pw, GELI_PW_MAXLEN, - (geli_e->md.md_flags & G_ELI_FLAG_GELIDISPLAYPASS) == 0); - printf("\n"); - if (geli_attach(geli_e, dskp, pw, NULL) == 0) { - return (0); - } - } - } - - return (1); -} Index: stand/geli/geliboot_internal.h =================================================================== --- /dev/null +++ stand/geli/geliboot_internal.h @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 2015 Allan Jude - * Copyright (c) 2005-2011 Pawel Jakub Dawidek - * All rights reserved. - * - * 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 AUTHORS 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 AUTHORS 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. - * - * $FreeBSD$ - */ - -#ifndef _GELIBOOT_INTERNAL_H_ -#define _GELIBOOT_INTERNAL_H_ - -#define _STRING_H_ -#define _STRINGS_H_ -#define _STDIO_H_ - -#include -#include - -#include -#include - -#include - -/* Pull in the md5, sha256, and sha512 implementations */ -#include -#include -#include - -/* Pull in AES implementation */ -#include - -/* AES-XTS implementation */ -#define _STAND 1 -#define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */ -#include - -struct geli_entry { - struct dsk *dsk; - off_t part_end; - struct g_eli_softc sc; - struct g_eli_metadata md; - int keybuf_slot; - SLIST_ENTRY(geli_entry) entries; -} *geli_e, *geli_e_tmp; - -static int geli_count; - -#endif /* _GELIBOOT_INTERNAL_H_ */ Index: stand/geli/pwgets.c =================================================================== --- /dev/null +++ stand/geli/pwgets.c @@ -1,79 +0,0 @@ -/* $NetBSD: gets.c,v 1.6 1995/10/11 21:16:57 pk Exp $ */ - -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - * - * @(#)gets.c 8.1 (Berkeley) 6/11/93 - */ - -#include -__FBSDID("$FreeBSD$"); - -#include "stand.h" - -/* gets() with constrained input length, for passwords */ - -void -pwgets(char *buf, int n, int hide) -{ - int c; - char *lp; - - for (lp = buf;;) - switch (c = getchar() & 0177) { - case '\n': - case '\r': - *lp = '\0'; - putchar('\n'); - return; - case '\b': - case '\177': - if (lp > buf) { - lp--; - if (hide == 0) { - putchar('\b'); - putchar(' '); - putchar('\b'); - } - } - break; - case 'u'&037: - case 'w'&037: - lp = buf; - putchar('\n'); - break; - default: - if ((n < 1) || ((lp - buf) < n - 1)) { - *lp++ = c; - if (hide == 0) { - putchar('*'); - } - } - } - /*NOTREACHED*/ -} Index: stand/i386/gptboot/Makefile =================================================================== --- stand/i386/gptboot/Makefile +++ stand/i386/gptboot/Makefile @@ -64,7 +64,7 @@ ${OBJCOPY} -S -O binary gptboot.out ${.TARGET} gptboot.out: ${BTXCRT} gptboot.o sio.o crc32.o drv.o cons.o ${OPENCRYPTO_XTS} - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBGELIBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} .include Index: stand/i386/gptzfsboot/Makefile =================================================================== --- stand/i386/gptzfsboot/Makefile +++ stand/i386/gptzfsboot/Makefile @@ -75,7 +75,7 @@ gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o \ ${OPENCRYPTO_XTS} - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBGELIBOOT} ${LIBZFSBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBZFSBOOT} ${LIBSA32} zfsboot.o: ${ZFSSRC}/zfsimpl.c Index: stand/i386/isoboot/Makefile =================================================================== --- stand/i386/isoboot/Makefile +++ stand/i386/isoboot/Makefile @@ -66,6 +66,6 @@ ${OBJCOPY} -S -O binary isoboot.out ${.TARGET} isoboot.out: ${BTXCRT} isoboot.o sio.o crc32.o drv.o cons.o ${OPENCRYPTO_XTS} - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBGELIBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSA32} .include Index: stand/i386/loader/Makefile =================================================================== --- stand/i386/loader/Makefile +++ stand/i386/loader/Makefile @@ -71,8 +71,8 @@ # XXX crt0.o needs to be first for pxeboot(8) to work OBJS= ${BTXCRT} -DPADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBGELIBOOT} ${LIBSA32} -LDADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBGELIBOOT} ${LIBSA32} +DPADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSA32} +LDADD= ${LDR_INTERP32} ${LIBFIREWIRE} ${LIBZFSBOOT} ${LIBI386} ${LIBSA32} .if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -DLOADER_PREFER_AMD64 Index: stand/i386/zfsboot/Makefile =================================================================== --- stand/i386/zfsboot/Makefile +++ stand/i386/zfsboot/Makefile @@ -82,7 +82,7 @@ ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET} zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o - ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBZFSBOOT} ${LIBGELIBOOT} ${LIBSA32} + ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBZFSBOOT} ${LIBSA32} SRCS= zfsboot.c Index: stand/libsa/Makefile =================================================================== --- stand/libsa/Makefile +++ stand/libsa/Makefile @@ -103,7 +103,6 @@ OTHER_INC=stdarg.h errno.h stdint.h beforedepend: - echo beforedepend; \ mkdir -p ${FAKE_DIRS}; \ for i in ${SAFE_INCS}; do \ ln -sf ${SRCTOP}/include/$$i $$i; \ @@ -151,4 +150,9 @@ .PATH: ${SYSDIR}/libkern SRCS+= explicit_bzero.c +# Maybe GELI +.if ${MK_LOADER_GELI} == "yes" +.include "${SASRC}/geli/Makefile.inc" +.endif + .include Index: stand/libsa/geli/Makefile.inc =================================================================== --- stand/libsa/geli/Makefile.inc +++ stand/libsa/geli/Makefile.inc @@ -1,11 +1,9 @@ # $FreeBSD$ -# libgeliboot +# Extra stuff for GELI -DO32=1 +.PATH: ${SASRC}/geli -.include - -LIB= geliboot +CFLAGS+= -I${LDRSRC} # Our password input method SRCS+= pwgets.c @@ -21,10 +19,11 @@ # AES implementation from sys/crypto .PATH: ${SYSDIR}/crypto/rijndael -CFLAGS+= -I${LDRSRC} -# Remove asserts -CFLAGS+= -DNDEBUG -SRCS+= rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c +.for i in rijndael-alg-fst.c rijndael-api-fst.c rijndael-api.c +# Remove asserts XXX BAD +CFLAGS.${i}+= -DNDEBUG +SRCS+= ${i} +.endfor # local GELI Implementation .PATH: ${SYSDIR}/geom/eli @@ -33,5 +32,3 @@ # aes .PATH: ${SYSDIR}/opencrypto SRCS+= xform_aes_xts.c - -.include Index: stand/libsa/geli/geliboot_crypto.c =================================================================== --- stand/libsa/geli/geliboot_crypto.c +++ stand/libsa/geli/geliboot_crypto.c @@ -71,7 +71,7 @@ } if (datasize != (blks / 8)) { printf("Failed to decrypt the entire input: " - "%u != %u\n", blks, datasize); + "%u != %zu\n", blks, datasize); return (1); } break; Index: sys/amd64/conf/GENERIC =================================================================== --- sys/amd64/conf/GENERIC +++ sys/amd64/conf/GENERIC @@ -240,8 +240,8 @@ device ix # Intel PRO/10GbE PCIE PF Ethernet device ixv # Intel PRO/10GbE PCIE VF Ethernet device ixl # Intel XL710 40Gbe PCIE Ethernet -options IXL_IW # Enable iWARP Client Interface in ixl(4) -device ixlv # Intel XL710 40Gbe VF PCIE Ethernet +#options IXL_IW # Enable iWARP Client Interface in ixl(4) +#device ixlv # Intel XL710 40Gbe VF PCIE Ethernet device le # AMD Am7900 LANCE and Am79C9xx PCnet device ti # Alteon Networks Tigon I/II gigabit Ethernet device txp # 3Com 3cR990 (``Typhoon'') Index: sys/amd64/conf/NOTES =================================================================== --- sys/amd64/conf/NOTES +++ sys/amd64/conf/NOTES @@ -333,8 +333,8 @@ device iwi # Intel 2200BG/2225BG/2915ABG wireless NICs. device iwn # Intel 4965/1000/5000/6000 wireless NICs. device ixl # Intel XL710 40Gbe PCIE Ethernet -options IXL_IW # Enable iWARP Client Interface in ixl(4) -device ixlv # Intel XL710 40Gbe VF PCIE Ethernet +#options IXL_IW # Enable iWARP Client Interface in ixl(4) +#device ixlv # Intel XL710 40Gbe VF PCIE Ethernet device mthca # Mellanox HCA InfiniBand device mlx4 # Shared code module between IB and Ethernet device mlx4ib # Mellanox ConnectX HCA InfiniBand Index: sys/arm64/linux/linux_locore.s =================================================================== --- sys/arm64/linux/linux_locore.s +++ sys/arm64/linux/linux_locore.s @@ -1,6 +1,7 @@ /*- - * Copyright (c) 2016 Andriy Voskoboinyk - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2018 Turing Robotic Industries Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,23 +27,32 @@ * $FreeBSD$ */ -#ifndef RTL8821AU_H -#define RTL8821AU_H - -#include - - /* - * Function declarations. + * arm64 Linux VDSO implementation. */ -/* r21au_init.c */ -void r21au_init_tx_agg(struct rtwn_softc *); -void r21au_init_burstlen(struct rtwn_softc *); -/* r21au_dfs.c */ -void r21au_chan_check(void *, int); -int r21au_newstate(struct ieee80211vap *, enum ieee80211_state, int); -void r21au_scan_start(struct ieee80211com *); -void r21au_scan_end(struct ieee80211com *); +#include -#endif /* RTL8821AU_H */ + .data + + .globl linux_platform +linux_platform: + .asciz "arm64" + + .text + +ENTRY(__kernel_rt_sigreturn) + brk #0 /* LINUXTODO: implement __kernel_rt_sigreturn */ + ret + +ENTRY(__kernel_gettimeofday) + brk #0 /* LINUXTODO: implement __kernel_gettimeofday */ + ret + +ENTRY(__kernel_clock_gettime) + brk #0 /* LINUXTODO: implement __kernel_clock_gettime */ + ret + +ENTRY(__kernel_clock_getres) + brk #0 /* LINUXTODO: implement __kernel_clock_getres */ + ret Index: sys/arm64/linux/linux_machdep.c =================================================================== --- /dev/null +++ sys/arm64/linux/linux_machdep.c @@ -0,0 +1,132 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Turing Robotic Industries Inc. + * Copyright (c) 2000 Marcel Moolenaar + * + * 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. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); + +/* DTrace probes */ +LIN_SDT_PROBE_DEFINE0(machdep, linux_set_upcall_kse, todo); +LIN_SDT_PROBE_DEFINE0(machdep, linux_mmap2, todo); +LIN_SDT_PROBE_DEFINE0(machdep, linux_rt_sigsuspend, todo); +LIN_SDT_PROBE_DEFINE0(machdep, linux_sigaltstack, todo); +LIN_SDT_PROBE_DEFINE0(machdep, linux_set_cloned_tls, todo); + +/* + * LINUXTODO: deduplicate; linux_execve is common across archs, except that on + * amd64 compat linuxulator it calls freebsd32_exec_copyin_args. + */ +int +linux_execve(struct thread *td, struct linux_execve_args *uap) +{ + struct image_args eargs; + char *path; + int error; + + LCONVPATHEXIST(td, uap->path, &path); + + error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, + uap->envp); + free(path, M_TEMP); + if (error == 0) + error = linux_common_execve(td, &eargs); + return (error); +} + +/* LINUXTODO: implement (or deduplicate) arm64 linux_set_upcall_kse */ +int +linux_set_upcall_kse(struct thread *td, register_t stack) +{ + + LIN_SDT_PROBE0(machdep, linux_set_upcall_kse, todo); + return (EDOOFUS); +} + +/* LINUXTODO: deduplicate arm64 linux_mmap2 */ +int +linux_mmap2(struct thread *td, struct linux_mmap2_args *uap) +{ + + LIN_SDT_PROBE0(machdep, linux_mmap2, todo); + return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot, + uap->flags, uap->fd, uap->pgoff)); +} + +int +linux_mprotect(struct thread *td, struct linux_mprotect_args *uap) +{ + + return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len, + uap->prot)); +} + +/* LINUXTODO: implement arm64 linux_rt_sigsuspend */ +int +linux_rt_sigsuspend(struct thread *td, struct linux_rt_sigsuspend_args *uap) +{ + + LIN_SDT_PROBE0(machdep, linux_rt_sigsuspend, todo); + return (EDOOFUS); +} + +/* LINUXTODO: implement arm64 linux_sigaltstack */ +int +linux_sigaltstack(struct thread *td, struct linux_sigaltstack_args *uap) +{ + + LIN_SDT_PROBE0(machdep, linux_sigaltstack, todo); + return (EDOOFUS); +} + +/* LINUXTODO: implement arm64 linux_set_cloned_tls */ +int +linux_set_cloned_tls(struct thread *td, void *desc) +{ + + LIN_SDT_PROBE0(machdep, linux_set_cloned_tls, todo); + return (EDOOFUS); +} Index: sys/arm64/linux/linux_ptrace.c =================================================================== --- sys/arm64/linux/linux_ptrace.c +++ sys/arm64/linux/linux_ptrace.c @@ -1,6 +1,7 @@ /*- - * Copyright (c) 2016 Andriy Voskoboinyk - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2018 Turing Robotic Industries Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,27 +27,30 @@ * $FreeBSD$ */ -#ifndef RTL8812AU_H -#define RTL8812AU_H +#include +__FBSDID("$FreeBSD$"); -#include +#include +#include +#include +#include +#include +#include +#include +#include -/* - * Function declarations. - */ -/* r12au_init.c */ -void r12au_init_rx_agg(struct rtwn_softc *); -void r12au_init_burstlen(struct rtwn_softc *); -void r12au_init_ampdu_fwhw(struct rtwn_softc *); -void r12au_init_ampdu(struct rtwn_softc *); -void r12au_post_init(struct rtwn_softc *); +/* DTrace init */ +LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); -/* r12au_rx.c */ -int r12au_classify_intr(struct rtwn_softc *, void *, int); -int r12au_align_rx(int, int); +/* DTrace probes */ +LIN_SDT_PROBE_DEFINE0(ptrace, linux_ptrace, todo); -/* r12au_tx.c */ -void r12au_dump_tx_desc(struct rtwn_softc *, const void *); +int +linux_ptrace(struct thread *td, struct linux_ptrace_args *uap) +{ -#endif /* RTL8812AU_H */ + /* LINUXTODO: implement arm64 linux_ptrace */ + LIN_SDT_PROBE0(ptrace, linux_ptrace, todo); + return (EDOOFUS); +} Index: sys/arm64/linux/linux_support.s =================================================================== --- sys/arm64/linux/linux_support.s +++ sys/arm64/linux/linux_support.s @@ -1,6 +1,7 @@ /*- - * Copyright (c) 2016 Andriy Voskoboinyk - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2018 Turing Robotic Industries Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,23 +27,31 @@ * $FreeBSD$ */ -#ifndef RTL8821AU_H -#define RTL8821AU_H - -#include +#include "linux_assym.h" +#include +#include "assym.inc" /* - * Function declarations. + * LINUXTODO: implement futex_* */ -/* r21au_init.c */ -void r21au_init_tx_agg(struct rtwn_softc *); -void r21au_init_burstlen(struct rtwn_softc *); -/* r21au_dfs.c */ -void r21au_chan_check(void *, int); -int r21au_newstate(struct ieee80211vap *, enum ieee80211_state, int); -void r21au_scan_start(struct ieee80211com *); -void r21au_scan_end(struct ieee80211com *); +ENTRY(futex_xchgl) + brk #0 + ret -#endif /* RTL8821AU_H */ +ENTRY(futex_addl) + brk #0 + ret + +ENTRY(futex_orl) + brk #0 + ret + +ENTRY(futex_andl) + brk #0 + ret + +ENTRY(futex_xorl) + brk #0 + ret Index: sys/arm64/linux/linux_syscall.h =================================================================== --- sys/arm64/linux/linux_syscall.h +++ sys/arm64/linux/linux_syscall.h @@ -23,6 +23,7 @@ #define LINUX_SYS_linux_epoll_create1 20 #define LINUX_SYS_linux_epoll_ctl 21 #define LINUX_SYS_linux_epoll_pwait 22 +#define LINUX_SYS_dup 23 #define LINUX_SYS_linux_dup3 24 #define LINUX_SYS_linux_fcntl 25 #define LINUX_SYS_linux_inotify_init1 26 Index: sys/arm64/linux/linux_syscalls.c =================================================================== --- sys/arm64/linux/linux_syscalls.c +++ sys/arm64/linux/linux_syscalls.c @@ -30,7 +30,7 @@ "linux_epoll_create1", /* 20 = linux_epoll_create1 */ "linux_epoll_ctl", /* 21 = linux_epoll_ctl */ "linux_epoll_pwait", /* 22 = linux_epoll_pwait */ - "#23", /* 23 = linux_dup */ + "dup", /* 23 = dup */ "linux_dup3", /* 24 = linux_dup3 */ "linux_fcntl", /* 25 = linux_fcntl */ "linux_inotify_init1", /* 26 = linux_inotify_init1 */ Index: sys/arm64/linux/linux_sysent.c =================================================================== --- sys/arm64/linux/linux_sysent.c +++ sys/arm64/linux/linux_sysent.c @@ -40,7 +40,7 @@ { AS(linux_epoll_create1_args), (sy_call_t *)linux_epoll_create1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 20 = linux_epoll_create1 */ { AS(linux_epoll_ctl_args), (sy_call_t *)linux_epoll_ctl, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 21 = linux_epoll_ctl */ { AS(linux_epoll_pwait_args), (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 22 = linux_epoll_pwait */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 23 = linux_dup */ + { AS(dup_args), (sy_call_t *)sys_dup, AUE_DUP, NULL, 0, 0, 0, SY_THR_STATIC }, /* 23 = dup */ { AS(linux_dup3_args), (sy_call_t *)linux_dup3, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 24 = linux_dup3 */ { AS(linux_fcntl_args), (sy_call_t *)linux_fcntl, AUE_FCNTL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 25 = linux_fcntl */ { AS(linux_inotify_init1_args), (sy_call_t *)linux_inotify_init1, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 26 = linux_inotify_init1 */ Index: sys/arm64/linux/linux_systrace_args.c =================================================================== --- sys/arm64/linux/linux_systrace_args.c +++ sys/arm64/linux/linux_systrace_args.c @@ -122,6 +122,13 @@ *n_args = 6; break; } + /* dup */ + case 23: { + struct dup_args *p = params; + uarg[0] = p->fd; /* u_int */ + *n_args = 1; + break; + } /* linux_dup3 */ case 24: { struct linux_dup3_args *p = params; @@ -2234,6 +2241,16 @@ break; }; break; + /* dup */ + case 23: + switch(ndx) { + case 0: + p = "u_int"; + break; + default: + break; + }; + break; /* linux_dup3 */ case 24: switch(ndx) { @@ -5499,6 +5516,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* dup */ + case 23: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_dup3 */ case 24: if (ndx == 0 || ndx == 1) Index: sys/arm64/linux/syscalls.master =================================================================== --- sys/arm64/linux/syscalls.master +++ sys/arm64/linux/syscalls.master @@ -42,7 +42,7 @@ struct epoll_event *events, \ l_int maxevents, l_int timeout, \ l_sigset_t *mask, l_size_t sigsetsize); } -23 AUE_NULL UNIMPL linux_dup +23 AUE_DUP NOPROTO { int dup(u_int fd); } 24 AUE_NULL STD { int linux_dup3(l_int oldfd, l_int newfd, \ l_int flags); } 25 AUE_FCNTL STD { int linux_fcntl(l_uint fd, l_uint cmd, \ Index: sys/compat/linsysfs/linsysfs.c =================================================================== --- sys/compat/linsysfs/linsysfs.c +++ sys/compat/linsysfs/linsysfs.c @@ -557,7 +557,7 @@ } PSEUDOFS(linsysfs, 1, VFCF_JAIL); -#if defined(__amd64__) +#if defined(__aarch64__) || defined(__amd64__) MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); #else MODULE_DEPEND(linsysfs, linux, 1, 1, 1); Index: sys/compat/linux/linux_misc.c =================================================================== --- sys/compat/linux/linux_misc.c +++ sys/compat/linux/linux_misc.c @@ -1895,6 +1895,11 @@ return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { +#ifdef DEBUG + if (ldebug(capget)) + printf(LMSG("invalid capget capability version 0x%x"), + luch.version); +#endif luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) @@ -1934,6 +1939,11 @@ return (error); if (luch.version != _LINUX_CAPABILITY_VERSION) { +#ifdef DEBUG + if (ldebug(capset)) + printf(LMSG("invalid capset capability version 0x%x"), + luch.version); +#endif luch.version = _LINUX_CAPABILITY_VERSION; error = copyout(&luch, args->hdrp, sizeof(luch)); if (error) Index: sys/conf/files.amd64 =================================================================== --- sys/conf/files.amd64 +++ sys/conf/files.amd64 @@ -270,12 +270,12 @@ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/ixl_pf_i2c.c optional ixl pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" -dev/ixl/ixl_iw.c optional ixl pci \ - compile-with "${NORMAL_C} -I$S/dev/ixl" -dev/ixl/if_ixlv.c optional ixlv pci \ - compile-with "${NORMAL_C} -I$S/dev/ixl" -dev/ixl/ixlvc.c optional ixlv pci \ - compile-with "${NORMAL_C} -I$S/dev/ixl" +#dev/ixl/ixl_iw.c optional ixl pci \ +# compile-with "${NORMAL_C} -I$S/dev/ixl" +#dev/ixl/if_ixlv.c optional ixlv pci \ +# compile-with "${NORMAL_C} -I$S/dev/ixl" +#dev/ixl/ixlvc.c optional ixlv pci \ +# compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/ixl_txrx.c optional ixl pci | ixlv pci \ compile-with "${NORMAL_C} -I$S/dev/ixl" dev/ixl/i40e_osdep.c optional ixl pci | ixlv pci \ Index: sys/contrib/libnv/cnvlist.c =================================================================== --- sys/contrib/libnv/cnvlist.c +++ sys/contrib/libnv/cnvlist.c @@ -56,29 +56,29 @@ #include "nvpair_impl.h" const char * -cnvlist_name(void *cookiep) +cnvlist_name(const void *cookie) { - return (nvpair_name(cookiep)); + return (nvpair_name(cookie)); } int -cnvlist_type(void *cookiep) +cnvlist_type(const void *cookie) { - return (nvpair_type(cookiep)); + return (nvpair_type(cookie)); } #define CNVLIST_GET(ftype, type, NVTYPE) \ ftype \ -cnvlist_get_##type(void *cookiep) \ +cnvlist_get_##type(const void *cookie) \ { \ \ - if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \ + if (nvpair_type(cookie) != NV_TYPE_##NVTYPE) { \ nvlist_report_missing(NV_TYPE_##NVTYPE, \ - nvpair_name(cookiep)); \ + nvpair_name(cookie)); \ } \ - return (nvpair_get_##type(cookiep)); \ + return (nvpair_get_##type(cookie)); \ } CNVLIST_GET(bool, bool, BOOL) @@ -93,14 +93,14 @@ #define CNVLIST_GET_ARRAY(ftype, type, NVTYPE) \ ftype \ -cnvlist_get_##type(void *cookiep, size_t *nitemsp) \ +cnvlist_get_##type(const void *cookie, size_t *nitemsp) \ { \ \ - if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \ + if (nvpair_type(cookie) != NV_TYPE_##NVTYPE) { \ nvlist_report_missing(NV_TYPE_##NVTYPE, \ - nvpair_name(cookiep)); \ + nvpair_name(cookie)); \ } \ - return (nvpair_get_##type(cookiep, nitemsp)); \ + return (nvpair_get_##type(cookie, nitemsp)); \ } CNVLIST_GET_ARRAY(const bool *, bool_array, BOOL_ARRAY) @@ -114,27 +114,29 @@ #undef CNVLIST_GET_ARRAY const void * -cnvlist_get_binary(void *cookiep, size_t *sizep) +cnvlist_get_binary(const void *cookie, size_t *sizep) { - if (nvpair_type(cookiep) != NV_TYPE_BINARY) - nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookiep)); - return (nvpair_get_binary(cookiep, sizep)); + if (nvpair_type(cookie) != NV_TYPE_BINARY) + nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookie)); + return (nvpair_get_binary(cookie, sizep)); } #define CNVLIST_TAKE(ftype, type, NVTYPE) \ ftype \ -cnvlist_take_##type(nvlist_t *nvl, void *cookiep) \ +cnvlist_take_##type(void *cookie) \ { \ ftype value; \ + nvlist_t *nvl; \ \ - if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \ + if (nvpair_type(cookie) != NV_TYPE_##NVTYPE) { \ nvlist_report_missing(NV_TYPE_##NVTYPE, \ - nvpair_name(cookiep)); \ + nvpair_name(cookie)); \ } \ - value = (ftype)(intptr_t)nvpair_get_##type(cookiep); \ - nvlist_remove_nvpair(nvl, cookiep); \ - nvpair_free_structure(cookiep); \ + nvl = nvpair_nvlist(cookie); \ + value = (ftype)(intptr_t)nvpair_get_##type(cookie); \ + nvlist_remove_nvpair(nvl, cookie); \ + nvpair_free_structure(cookie); \ return (value); \ } @@ -150,17 +152,19 @@ #define CNVLIST_TAKE_ARRAY(ftype, type, NVTYPE) \ ftype \ -cnvlist_take_##type(nvlist_t *nvl, void *cookiep, size_t *nitemsp) \ +cnvlist_take_##type(void *cookie, size_t *nitemsp) \ { \ ftype value; \ + nvlist_t *nvl; \ \ - if (nvpair_type(cookiep) != NV_TYPE_##NVTYPE) { \ + if (nvpair_type(cookie) != NV_TYPE_##NVTYPE) { \ nvlist_report_missing(NV_TYPE_##NVTYPE, \ - nvpair_name(cookiep)); \ + nvpair_name(cookie)); \ } \ - value = (ftype)(intptr_t)nvpair_get_##type(cookiep, nitemsp); \ - nvlist_remove_nvpair(nvl, cookiep); \ - nvpair_free_structure(cookiep); \ + nvl = nvpair_nvlist(cookie); \ + value = (ftype)(intptr_t)nvpair_get_##type(cookie, nitemsp); \ + nvlist_remove_nvpair(nvl, cookie); \ + nvpair_free_structure(cookie); \ return (value); \ } @@ -175,25 +179,27 @@ #undef CNVLIST_TAKE_ARRAY void * -cnvlist_take_binary(nvlist_t *nvl, void *cookiep, size_t *sizep) +cnvlist_take_binary(void *cookie, size_t *sizep) { void *value; + nvlist_t *nvl; - if (nvpair_type(cookiep) != NV_TYPE_BINARY) - nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookiep)); - value = (void *)(intptr_t)nvpair_get_binary(cookiep, sizep); - nvlist_remove_nvpair(nvl, cookiep); - nvpair_free_structure(cookiep); + if (nvpair_type(cookie) != NV_TYPE_BINARY) + nvlist_report_missing(NV_TYPE_BINARY, nvpair_name(cookie)); + nvl = nvpair_nvlist(cookie); + value = (void *)(intptr_t)nvpair_get_binary(cookie, sizep); + nvlist_remove_nvpair(nvl, cookie); + nvpair_free_structure(cookie); return (value); } #define CNVLIST_FREE(type) \ void \ -cnvlist_free_##type(nvlist_t *nvl, void *cookiep) \ +cnvlist_free_##type(void *cookie) \ { \ \ - nvlist_free_nvpair(nvl, cookiep); \ + nvlist_free_nvpair(nvpair_nvlist(cookie), cookie); \ } CNVLIST_FREE(bool) Index: sys/contrib/libnv/nv_impl.h =================================================================== --- sys/contrib/libnv/nv_impl.h +++ sys/contrib/libnv/nv_impl.h @@ -143,6 +143,12 @@ nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems); nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems); +int nvpair_append_bool_array(nvpair_t *nvp, const bool value); +int nvpair_append_number_array(nvpair_t *nvp, const uint64_t value); +int nvpair_append_string_array(nvpair_t *nvp, const char *value); +int nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value); +int nvpair_append_descriptor_array(nvpair_t *nvp, const int value); + bool nvpair_get_bool(const nvpair_t *nvp); uint64_t nvpair_get_number(const nvpair_t *nvp); const char *nvpair_get_string(const nvpair_t *nvp); Index: sys/contrib/libnv/nvlist.c =================================================================== --- sys/contrib/libnv/nvlist.c +++ sys/contrib/libnv/nvlist.c @@ -1607,6 +1607,37 @@ #undef NVLIST_ADD_ARRAY +#define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \ +void \ +nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\ +{ \ + nvpair_t *nvp; \ + \ + if (nvlist_error(nvl) != 0) { \ + ERRNO_SET(nvlist_error(nvl)); \ + return; \ + } \ + nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ + if (nvp == NULL) { \ + nvlist_add_##type##_array(nvl, name, &value, 1); \ + return; \ + } \ + if (nvpair_append_##type##_array(nvp, value) == -1) { \ + nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ + ERRNO_SET(nvl->nvl_error); \ + } \ +} + +NVLIST_APPEND_ARRAY(const bool, bool, BOOL) +NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER) +NVLIST_APPEND_ARRAY(const char *, string, STRING) +NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST) +#ifndef _KERNEL +NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR) +#endif + +#undef NVLIST_APPEND_ARRAY + bool nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) { Index: sys/contrib/libnv/nvpair.c =================================================================== --- sys/contrib/libnv/nvpair.c +++ sys/contrib/libnv/nvpair.c @@ -144,6 +144,28 @@ return (nvp); } +static int +nvpair_append(nvpair_t *nvp, const void *value, size_t valsize, size_t datasize) +{ + void *olddata, *data, *valp; + size_t oldlen; + + oldlen = nvp->nvp_nitems * valsize; + olddata = (void *)(uintptr_t)nvp->nvp_data; + data = nv_realloc(olddata, oldlen + valsize); + if (data == NULL) { + ERRNO_SET(ENOMEM); + return (-1); + } + valp = (unsigned char *)data + oldlen; + memcpy(valp, value, valsize); + + nvp->nvp_data = (uint64_t)(uintptr_t)data; + nvp->nvp_datasize += datasize; + nvp->nvp_nitems++; + return (0); +} + nvlist_t * nvpair_nvlist(const nvpair_t *nvp) { @@ -206,8 +228,10 @@ /* XXX: DECONST is bad, mkay? */ nvlarray = __DECONST(nvlist_t **, nvpair_get_nvlist_array(nvp, &count)); - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { nvlist_set_array_next(nvlarray[i], NULL); + nvlist_set_parent(nvlarray[i], NULL); + } } void @@ -1911,6 +1935,121 @@ } #endif +int +nvpair_append_bool_array(nvpair_t *nvp, const bool value) +{ + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY); + return (nvpair_append(nvp, &value, sizeof(value), sizeof(value))); +} + +int +nvpair_append_number_array(nvpair_t *nvp, const uint64_t value) +{ + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY); + return (nvpair_append(nvp, &value, sizeof(value), sizeof(value))); +} + +int +nvpair_append_string_array(nvpair_t *nvp, const char *value) +{ + char *str; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY); + if (value == NULL) { + ERRNO_SET(EINVAL); + return (-1); + } + str = nv_strdup(value); + if (str == NULL) { + return (-1); + } + if (nvpair_append(nvp, &str, sizeof(str), strlen(str) + 1) == -1) { + nv_free(str); + return (-1); + } + return (0); +} + +int +nvpair_append_nvlist_array(nvpair_t *nvp, const nvlist_t *value) +{ + nvpair_t *tmpnvp; + nvlist_t *nvl, *prev; + int flags; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY); + if (value == NULL || nvlist_error(value) != 0 || + nvlist_get_pararr(value, NULL) != NULL) { + ERRNO_SET(EINVAL); + return (-1); + } + nvl = nvlist_clone(value); + if (nvl == NULL) { + return (-1); + } + flags = nvlist_flags(nvl) | NV_FLAG_IN_ARRAY; + nvlist_set_flags(nvl, flags); + + tmpnvp = NULL; + if (nvp->nvp_nitems > 0) { + nvlist_t **nvls = (void *)(uintptr_t)nvp->nvp_data; + + prev = nvls[nvp->nvp_nitems - 1]; + PJDLOG_ASSERT(prev != NULL); + + tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST, + (uint64_t)(uintptr_t)nvl, 0, 0); + if (tmpnvp == NULL) { + goto fail; + } + } + if (nvpair_append(nvp, &nvl, sizeof(nvl), 0) == -1) { + goto fail; + } + if (tmpnvp) { + NVPAIR_ASSERT(tmpnvp); + nvlist_set_array_next(prev, tmpnvp); + } + nvlist_set_parent(nvl, nvp); + return (0); +fail: + if (tmpnvp) { + nvpair_free(tmpnvp); + } + nvlist_destroy(nvl); + return (-1); +} + +#ifndef _KERNEL +int +nvpair_append_descriptor_array(nvpair_t *nvp, const int value) +{ + int fd; + + NVPAIR_ASSERT(nvp); + PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY); + if (value < 0 || !fd_is_valid(value)) { + ERRNO_SET(EBADF); + return -1; + } + fd = fcntl(value, F_DUPFD_CLOEXEC, 0); + if (fd == -1) { + return (-1); + } + if (nvpair_append(nvp, &fd, sizeof(fd), sizeof(fd)) == -1) { + close(fd); + return (-1); + } + return (0); +} +#endif + void nvpair_free(nvpair_t *nvp) { Index: sys/dev/cxgbe/common/t4_hw.c =================================================================== --- sys/dev/cxgbe/common/t4_hw.c +++ sys/dev/cxgbe/common/t4_hw.c @@ -239,6 +239,63 @@ be32_to_cpu(asrt->u.assert.y)); } +struct port_tx_state { + uint64_t rx_pause; + uint64_t tx_frames; +}; + +static void +read_tx_state_one(struct adapter *sc, int i, struct port_tx_state *tx_state) +{ + uint32_t rx_pause_reg, tx_frames_reg; + + if (is_t4(sc)) { + tx_frames_reg = PORT_REG(i, A_MPS_PORT_STAT_TX_PORT_FRAMES_L); + rx_pause_reg = PORT_REG(i, A_MPS_PORT_STAT_RX_PORT_PAUSE_L); + } else { + tx_frames_reg = T5_PORT_REG(i, A_MPS_PORT_STAT_TX_PORT_FRAMES_L); + rx_pause_reg = T5_PORT_REG(i, A_MPS_PORT_STAT_RX_PORT_PAUSE_L); + } + + tx_state->rx_pause = t4_read_reg64(sc, rx_pause_reg); + tx_state->tx_frames = t4_read_reg64(sc, tx_frames_reg); +} + +static void +read_tx_state(struct adapter *sc, struct port_tx_state *tx_state) +{ + int i; + + for_each_port(sc, i) + read_tx_state_one(sc, i, &tx_state[i]); +} + +static void +check_tx_state(struct adapter *sc, struct port_tx_state *tx_state) +{ + uint32_t port_ctl_reg; + uint64_t tx_frames, rx_pause; + int i; + + for_each_port(sc, i) { + rx_pause = tx_state[i].rx_pause; + tx_frames = tx_state[i].tx_frames; + read_tx_state_one(sc, i, &tx_state[i]); /* update */ + + if (is_t4(sc)) + port_ctl_reg = PORT_REG(i, A_MPS_PORT_CTL); + else + port_ctl_reg = T5_PORT_REG(i, A_MPS_PORT_CTL); + if (t4_read_reg(sc, port_ctl_reg) & F_PORTTXEN && + rx_pause != tx_state[i].rx_pause && + tx_frames == tx_state[i].tx_frames) { + t4_set_reg_field(sc, port_ctl_reg, F_PORTTXEN, 0); + mdelay(1); + t4_set_reg_field(sc, port_ctl_reg, F_PORTTXEN, F_PORTTXEN); + } + } +} + #define X_CIM_PF_NOACCESS 0xeeeeeeee /** * t4_wr_mbox_meat_timeout - send a command to FW through the given mailbox @@ -280,13 +337,14 @@ }; u32 v; u64 res; - int i, ms, delay_idx, ret; + int i, ms, delay_idx, ret, next_tx_check; const __be64 *p = cmd; u32 data_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_DATA); u32 ctl_reg = PF_REG(mbox, A_CIM_PF_MAILBOX_CTRL); u32 ctl; __be64 cmd_rpl[MBOX_LEN/8]; u32 pcie_fw; + struct port_tx_state tx_state[MAX_NPORTS]; if (adap->flags & CHK_MBOX_ACCESS) ASSERT_SYNCHRONIZED_OP(adap); @@ -375,8 +433,8 @@ CH_DUMP_MBOX(adap, mbox, data_reg); t4_write_reg(adap, ctl_reg, F_MBMSGVALID | V_MBOWNER(X_MBOWNER_FW)); - t4_read_reg(adap, ctl_reg); /* flush write */ - + read_tx_state(adap, &tx_state[0]); /* also flushes the write_reg */ + next_tx_check = 1000; delay_idx = 0; ms = delay[0]; @@ -391,6 +449,12 @@ if (pcie_fw & F_PCIE_FW_ERR) break; } + + if (i >= next_tx_check) { + check_tx_state(adap, &tx_state[0]); + next_tx_check = i + 1000; + } + if (sleep_ok) { ms = delay[delay_idx]; /* last element may repeat */ if (delay_idx < ARRAY_SIZE(delay) - 1) Index: sys/dev/ixl/i40e_adminq.h =================================================================== --- sys/dev/ixl/i40e_adminq.h +++ sys/dev/ixl/i40e_adminq.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_adminq.c =================================================================== --- sys/dev/ixl/i40e_adminq.c +++ sys/dev/ixl/i40e_adminq.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_adminq_cmd.h =================================================================== --- sys/dev/ixl/i40e_adminq_cmd.h +++ sys/dev/ixl/i40e_adminq_cmd.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_alloc.h =================================================================== --- sys/dev/ixl/i40e_alloc.h +++ sys/dev/ixl/i40e_alloc.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_common.c =================================================================== --- sys/dev/ixl/i40e_common.c +++ sys/dev/ixl/i40e_common.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_dcb.h =================================================================== --- sys/dev/ixl/i40e_dcb.h +++ sys/dev/ixl/i40e_dcb.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_dcb.c =================================================================== --- sys/dev/ixl/i40e_dcb.c +++ sys/dev/ixl/i40e_dcb.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_devids.h =================================================================== --- sys/dev/ixl/i40e_devids.h +++ sys/dev/ixl/i40e_devids.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_hmc.h =================================================================== --- sys/dev/ixl/i40e_hmc.h +++ sys/dev/ixl/i40e_hmc.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_hmc.c =================================================================== --- sys/dev/ixl/i40e_hmc.c +++ sys/dev/ixl/i40e_hmc.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_lan_hmc.h =================================================================== --- sys/dev/ixl/i40e_lan_hmc.h +++ sys/dev/ixl/i40e_lan_hmc.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_lan_hmc.c =================================================================== --- sys/dev/ixl/i40e_lan_hmc.c +++ sys/dev/ixl/i40e_lan_hmc.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_nvm.c =================================================================== --- sys/dev/ixl/i40e_nvm.c +++ sys/dev/ixl/i40e_nvm.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_osdep.h =================================================================== --- sys/dev/ixl/i40e_osdep.h +++ sys/dev/ixl/i40e_osdep.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_osdep.c =================================================================== --- sys/dev/ixl/i40e_osdep.c +++ sys/dev/ixl/i40e_osdep.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -132,7 +132,7 @@ bus_dmamap_unload(mem->tag, mem->map); bus_dmamem_free(mem->tag, mem->va, mem->map); bus_dma_tag_destroy(mem->tag); - return (0); + return (I40E_SUCCESS); } void Index: sys/dev/ixl/i40e_prototype.h =================================================================== --- sys/dev/ixl/i40e_prototype.h +++ sys/dev/ixl/i40e_prototype.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_register.h =================================================================== --- sys/dev/ixl/i40e_register.h +++ sys/dev/ixl/i40e_register.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_status.h =================================================================== --- sys/dev/ixl/i40e_status.h +++ sys/dev/ixl/i40e_status.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/i40e_type.h =================================================================== --- sys/dev/ixl/i40e_type.h +++ sys/dev/ixl/i40e_type.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/if_ixl.c =================================================================== --- sys/dev/ixl/if_ixl.c +++ sys/dev/ixl/if_ixl.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -47,64 +47,83 @@ /********************************************************************* * Driver version *********************************************************************/ -#define IXL_DRIVER_VERSION_MAJOR 1 -#define IXL_DRIVER_VERSION_MINOR 9 -#define IXL_DRIVER_VERSION_BUILD 9 +#define IXL_DRIVER_VERSION_MAJOR 2 +#define IXL_DRIVER_VERSION_MINOR 0 +#define IXL_DRIVER_VERSION_BUILD 0 -char ixl_driver_version[] = __XSTRING(IXL_DRIVER_VERSION_MAJOR) "." - __XSTRING(IXL_DRIVER_VERSION_MINOR) "." - __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k"; +#define IXL_DRIVER_VERSION_STRING \ + __XSTRING(IXL_DRIVER_VERSION_MAJOR) "." \ + __XSTRING(IXL_DRIVER_VERSION_MINOR) "." \ + __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k" /********************************************************************* * PCI Device ID Table * * Used by probe to select devices to load on - * Last field stores an index into ixl_strings - * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + * ( Vendor ID, Device ID, Branding String ) *********************************************************************/ -static ixl_vendor_info_t ixl_vendor_info_array[] = +static pci_vendor_info_t ixl_vendor_info_array[] = { - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, 0, 0, 0}, - {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, 0, 0, 0}, + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, "Intel(R) Ethernet Controller X710 for 10GbE SFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, "Intel(R) Ethernet Controller XL710 for 40GbE backplane"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, "Intel(R) Ethernet Controller X710 for 10GbE backplane"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, "Intel(R) Ethernet Controller X710 for 10GbE QSFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, "Intel(R) Ethernet Controller X710 for 10GBASE-T"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, "Intel(R) Ethernet Controller X710/X557-AT 10GBASE-T"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, "Intel(R) Ethernet Connection X722 for 10GbE backplane"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE QSFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 1GbE"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 10GBASE-T"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, "Intel(R) Ethernet Controller XXV710 for 25GbE backplane"), + PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, "Intel(R) Ethernet Controller XXV710 for 25GbE SFP28"), /* required last entry */ - {0, 0, 0, 0, 0} + PVID_END }; -/********************************************************************* - * Table of branding strings - *********************************************************************/ - -static char *ixl_strings[] = { - "Intel(R) Ethernet Connection 700 Series PF Driver" -}; - - /********************************************************************* * Function prototypes *********************************************************************/ -static int ixl_probe(device_t); -static int ixl_attach(device_t); -static int ixl_detach(device_t); -static int ixl_shutdown(device_t); +/*** IFLIB interface ***/ +static void *ixl_register(device_t dev); +static int ixl_if_attach_pre(if_ctx_t ctx); +static int ixl_if_attach_post(if_ctx_t ctx); +static int ixl_if_detach(if_ctx_t ctx); +static int ixl_if_shutdown(if_ctx_t ctx); +static int ixl_if_suspend(if_ctx_t ctx); +static int ixl_if_resume(if_ctx_t ctx); +static int ixl_if_msix_intr_assign(if_ctx_t ctx, int msix); +static void ixl_if_enable_intr(if_ctx_t ctx); +static void ixl_if_disable_intr(if_ctx_t ctx); +static int ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid); +static int ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid); +static int ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets); +static int ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); +static void ixl_if_queues_free(if_ctx_t ctx); +static void ixl_if_update_admin_status(if_ctx_t ctx); +static void ixl_if_multi_set(if_ctx_t ctx); +static int ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu); +static void ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr); +static int ixl_if_media_change(if_ctx_t ctx); +static int ixl_if_promisc_set(if_ctx_t ctx, int flags); +static void ixl_if_timer(if_ctx_t ctx, uint16_t qid); +static void ixl_if_vlan_register(if_ctx_t ctx, u16 vtag); +static void ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag); +static uint64_t ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt); +static void ixl_if_vflr_handle(if_ctx_t ctx); +// static void ixl_if_link_intr_enable(if_ctx_t ctx); +static int ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req); +static int ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data); -static int ixl_save_pf_tunables(struct ixl_pf *); +/*** Other ***/ +static int ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int); +static void ixl_save_pf_tunables(struct ixl_pf *); +static int ixl_allocate_pci_resources(struct ixl_pf *); /********************************************************************* * FreeBSD Device Interface Entry Points @@ -112,16 +131,17 @@ static device_method_t ixl_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, ixl_probe), - DEVMETHOD(device_attach, ixl_attach), - DEVMETHOD(device_detach, ixl_detach), - DEVMETHOD(device_shutdown, ixl_shutdown), + DEVMETHOD(device_register, ixl_register), + DEVMETHOD(device_probe, iflib_device_probe), + DEVMETHOD(device_attach, iflib_device_attach), + DEVMETHOD(device_detach, iflib_device_detach), + DEVMETHOD(device_shutdown, iflib_device_shutdown), #ifdef PCI_IOV DEVMETHOD(pci_iov_init, ixl_iov_init), DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), DEVMETHOD(pci_iov_add_vf, ixl_add_vf), #endif - {0, 0} + DEVMETHOD_END }; static driver_t ixl_driver = { @@ -130,14 +150,51 @@ devclass_t ixl_devclass; DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); - -MODULE_VERSION(ixl, 1); +MODULE_VERSION(ixl, 3); MODULE_DEPEND(ixl, pci, 1, 1, 1); MODULE_DEPEND(ixl, ether, 1, 1, 1); -#if defined(DEV_NETMAP) && __FreeBSD_version >= 1100000 -MODULE_DEPEND(ixl, netmap, 1, 1, 1); -#endif /* DEV_NETMAP */ +MODULE_DEPEND(ixl, iflib, 1, 1, 1); + +static device_method_t ixl_if_methods[] = { + DEVMETHOD(ifdi_attach_pre, ixl_if_attach_pre), + DEVMETHOD(ifdi_attach_post, ixl_if_attach_post), + DEVMETHOD(ifdi_detach, ixl_if_detach), + DEVMETHOD(ifdi_shutdown, ixl_if_shutdown), + DEVMETHOD(ifdi_suspend, ixl_if_suspend), + DEVMETHOD(ifdi_resume, ixl_if_resume), + DEVMETHOD(ifdi_init, ixl_if_init), + DEVMETHOD(ifdi_stop, ixl_if_stop), + DEVMETHOD(ifdi_msix_intr_assign, ixl_if_msix_intr_assign), + DEVMETHOD(ifdi_intr_enable, ixl_if_enable_intr), + DEVMETHOD(ifdi_intr_disable, ixl_if_disable_intr), + //DEVMETHOD(ifdi_link_intr_enable, ixl_if_link_intr_enable), + DEVMETHOD(ifdi_rx_queue_intr_enable, ixl_if_rx_queue_intr_enable), + DEVMETHOD(ifdi_tx_queue_intr_enable, ixl_if_tx_queue_intr_enable), + DEVMETHOD(ifdi_tx_queues_alloc, ixl_if_tx_queues_alloc), + DEVMETHOD(ifdi_rx_queues_alloc, ixl_if_rx_queues_alloc), + DEVMETHOD(ifdi_queues_free, ixl_if_queues_free), + DEVMETHOD(ifdi_update_admin_status, ixl_if_update_admin_status), + DEVMETHOD(ifdi_multi_set, ixl_if_multi_set), + DEVMETHOD(ifdi_mtu_set, ixl_if_mtu_set), + DEVMETHOD(ifdi_media_status, ixl_if_media_status), + DEVMETHOD(ifdi_media_change, ixl_if_media_change), + DEVMETHOD(ifdi_promisc_set, ixl_if_promisc_set), + DEVMETHOD(ifdi_timer, ixl_if_timer), + DEVMETHOD(ifdi_vlan_register, ixl_if_vlan_register), + DEVMETHOD(ifdi_vlan_unregister, ixl_if_vlan_unregister), + DEVMETHOD(ifdi_get_counter, ixl_if_get_counter), + DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle), + DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req), + DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl), + // ifdi_led_func + // ifdi_debug + DEVMETHOD_END +}; + +static driver_t ixl_if_driver = { + "ixl_if", ixl_if_methods, sizeof(struct ixl_pf) +}; /* ** TUNEABLE PARAMETERS: @@ -146,39 +203,6 @@ static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, "IXL driver parameters"); -/* - * MSIX should be the default for best performance, - * but this allows it to be forced off for testing. - */ -static int ixl_enable_msix = 1; -TUNABLE_INT("hw.ixl.enable_msix", &ixl_enable_msix); -SYSCTL_INT(_hw_ixl, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixl_enable_msix, 0, - "Enable MSI-X interrupts"); - -/* -** Number of descriptors per ring -** - TX and RX sizes are independently configurable -*/ -static int ixl_tx_ring_size = IXL_DEFAULT_RING; -TUNABLE_INT("hw.ixl.tx_ring_size", &ixl_tx_ring_size); -SYSCTL_INT(_hw_ixl, OID_AUTO, tx_ring_size, CTLFLAG_RDTUN, - &ixl_tx_ring_size, 0, "TX Descriptor Ring Size"); - -static int ixl_rx_ring_size = IXL_DEFAULT_RING; -TUNABLE_INT("hw.ixl.rx_ring_size", &ixl_rx_ring_size); -SYSCTL_INT(_hw_ixl, OID_AUTO, rx_ring_size, CTLFLAG_RDTUN, - &ixl_rx_ring_size, 0, "RX Descriptor Ring Size"); - -/* -** This can be set manually, if left as 0 the -** number of queues will be calculated based -** on cpus and msix vectors available. -*/ -static int ixl_max_queues = 0; -TUNABLE_INT("hw.ixl.max_queues", &ixl_max_queues); -SYSCTL_INT(_hw_ixl, OID_AUTO, max_queues, CTLFLAG_RDTUN, - &ixl_max_queues, 0, "Number of Queues"); - /* * Leave this on unless you need to send flow control * frames (or other control frames) from software @@ -190,6 +214,13 @@ &ixl_enable_tx_fc_filter, 0, "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); +static int ixl_i2c_access_method = 0; +TUNABLE_INT("hw.ixl.i2c_access_method", + &ixl_i2c_access_method); +SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN, + &ixl_i2c_access_method, 0, + IXL_SYSCTL_HELP_I2C_METHOD); + /* * Different method for processing TX descriptor * completion. @@ -215,20 +246,22 @@ &ixl_shared_debug_mask, 0, "Display debug statements that are printed in shared code"); +#if 0 /* ** Controls for Interrupt Throttling ** - true/false for dynamic adjustment ** - default values for static ITR */ -static int ixl_dynamic_rx_itr = 1; +static int ixl_dynamic_rx_itr = 0; TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); -static int ixl_dynamic_tx_itr = 1; +static int ixl_dynamic_tx_itr = 0; TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); +#endif static int ixl_rx_itr = IXL_ITR_8K; TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); @@ -256,165 +289,131 @@ &ixl_limit_iwarp_msix, 0, "Limit MSIX vectors assigned to iWARP"); #endif -#ifdef DEV_NETMAP -#define NETMAP_IXL_MAIN /* only bring in one part of the netmap code */ -#include -#endif /* DEV_NETMAP */ +extern struct if_txrx ixl_txrx_hwb; +extern struct if_txrx ixl_txrx_dwb; -/********************************************************************* - * Device identification routine - * - * ixl_probe determines if the driver should be loaded on - * the hardware based on PCI vendor/device id of the device. - * - * return BUS_PROBE_DEFAULT on success, positive on failure - *********************************************************************/ +static struct if_shared_ctx ixl_sctx_init = { + .isc_magic = IFLIB_MAGIC, + .isc_q_align = PAGE_SIZE, + .isc_tx_maxsize = IXL_TSO_SIZE, + .isc_tx_maxsegsize = IXL_MAX_DMA_SEG_SIZE, + + .isc_rx_maxsize = 16384, + .isc_rx_nsegments = IXL_MAX_RX_SEGS, + .isc_rx_maxsegsize = IXL_MAX_DMA_SEG_SIZE, + .isc_nfl = 1, + .isc_ntxqs = 1, + .isc_nrxqs = 1, + + .isc_admin_intrcnt = 1, + .isc_vendor_info = ixl_vendor_info_array, + .isc_driver_version = IXL_DRIVER_VERSION_STRING, + .isc_driver = &ixl_if_driver, + .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_NEED_ZERO_CSUM | IFLIB_ADMIN_ALWAYS_RUN, + + .isc_nrxd_min = {IXL_MIN_RING}, + .isc_ntxd_min = {IXL_MIN_RING}, + .isc_nrxd_max = {IXL_MAX_RING}, + .isc_ntxd_max = {IXL_MAX_RING}, + .isc_nrxd_default = {IXL_DEFAULT_RING}, + .isc_ntxd_default = {IXL_DEFAULT_RING}, +}; + +if_shared_ctx_t ixl_sctx = &ixl_sctx_init; + +/*** Functions ***/ +static void * +ixl_register(device_t dev) +{ + return (ixl_sctx); +} static int -ixl_probe(device_t dev) +ixl_allocate_pci_resources(struct ixl_pf *pf) { - ixl_vendor_info_t *ent; + int rid; + struct i40e_hw *hw = &pf->hw; + device_t dev = iflib_get_dev(pf->vsi.ctx); - u16 pci_vendor_id, pci_device_id; - u16 pci_subvendor_id, pci_subdevice_id; - char device_name[256]; - -#if 0 - INIT_DEBUGOUT("ixl_probe: begin"); -#endif - pci_vendor_id = pci_get_vendor(dev); - if (pci_vendor_id != I40E_INTEL_VENDOR_ID) + /* Map BAR0 */ + rid = PCIR_BAR(0); + pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + + if (!(pf->pci_mem)) { + device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); return (ENXIO); - - pci_device_id = pci_get_device(dev); - pci_subvendor_id = pci_get_subvendor(dev); - pci_subdevice_id = pci_get_subdevice(dev); - - ent = ixl_vendor_info_array; - while (ent->vendor_id != 0) { - if ((pci_vendor_id == ent->vendor_id) && - (pci_device_id == ent->device_id) && - - ((pci_subvendor_id == ent->subvendor_id) || - (ent->subvendor_id == 0)) && - - ((pci_subdevice_id == ent->subdevice_id) || - (ent->subdevice_id == 0))) { - sprintf(device_name, "%s, Version - %s", - ixl_strings[ent->index], - ixl_driver_version); - device_set_desc_copy(dev, device_name); - return (BUS_PROBE_DEFAULT); - } - ent++; } - return (ENXIO); -} -/* - * Sanity check and save off tunable values. - */ -static int -ixl_save_pf_tunables(struct ixl_pf *pf) -{ - device_t dev = pf->dev; + /* Save off the PCI information */ + hw->vendor_id = pci_get_vendor(dev); + hw->device_id = pci_get_device(dev); + hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); + hw->subsystem_vendor_id = + pci_read_config(dev, PCIR_SUBVEND_0, 2); + hw->subsystem_device_id = + pci_read_config(dev, PCIR_SUBDEV_0, 2); - /* Save tunable information */ - pf->enable_msix = ixl_enable_msix; - pf->max_queues = ixl_max_queues; - pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; - pf->dynamic_rx_itr = ixl_dynamic_rx_itr; - pf->dynamic_tx_itr = ixl_dynamic_tx_itr; - pf->dbg_mask = ixl_core_debug_mask; - pf->hw.debug_mask = ixl_shared_debug_mask; -#ifdef DEV_NETMAP - if (ixl_enable_head_writeback == 0) - device_printf(dev, "Head writeback mode cannot be disabled " - "when netmap is enabled\n"); - pf->vsi.enable_head_writeback = 1; -#else - pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); -#endif + hw->bus.device = pci_get_slot(dev); + hw->bus.func = pci_get_function(dev); - ixl_vsi_setup_rings_size(&pf->vsi, ixl_tx_ring_size, ixl_rx_ring_size); + /* Save off register access information */ + pf->osdep.mem_bus_space_tag = + rman_get_bustag(pf->pci_mem); + pf->osdep.mem_bus_space_handle = + rman_get_bushandle(pf->pci_mem); + pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); + pf->osdep.flush_reg = I40E_GLGEN_STAT; + pf->osdep.dev = dev; - if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { - device_printf(dev, "Invalid tx_itr value of %d set!\n", - ixl_tx_itr); - device_printf(dev, "tx_itr must be between %d and %d, " - "inclusive\n", - 0, IXL_MAX_ITR); - device_printf(dev, "Using default value of %d instead\n", - IXL_ITR_4K); - pf->tx_itr = IXL_ITR_4K; - } else - pf->tx_itr = ixl_tx_itr; - - if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { - device_printf(dev, "Invalid rx_itr value of %d set!\n", - ixl_rx_itr); - device_printf(dev, "rx_itr must be between %d and %d, " - "inclusive\n", - 0, IXL_MAX_ITR); - device_printf(dev, "Using default value of %d instead\n", - IXL_ITR_8K); - pf->rx_itr = IXL_ITR_8K; - } else - pf->rx_itr = ixl_rx_itr; - - return (0); -} - -/********************************************************************* - * Device initialization routine - * - * The attach entry point is called when the driver is being loaded. - * This routine identifies the type of hardware, allocates all resources - * and initializes the hardware. - * - * return 0 on success, positive on failure - *********************************************************************/ + pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; + pf->hw.back = &pf->osdep; + + return (0); + } static int -ixl_attach(device_t dev) +ixl_if_attach_pre(if_ctx_t ctx) { - struct ixl_pf *pf; - struct i40e_hw *hw; - struct ixl_vsi *vsi; + device_t dev; + struct ixl_pf *pf; + struct i40e_hw *hw; + struct ixl_vsi *vsi; + if_softc_ctx_t scctx; + struct i40e_filter_control_settings filter; enum i40e_status_code status; - int error = 0; + int error = 0; - INIT_DEBUGOUT("ixl_attach: begin"); + INIT_DEBUGOUT("ixl_if_attach_pre: begin"); /* Allocate, clear, and link in our primary soft structure */ - pf = device_get_softc(dev); - pf->dev = pf->osdep.dev = dev; + dev = iflib_get_dev(ctx); + pf = iflib_get_softc(ctx); + vsi = &pf->vsi; + vsi->back = pf; + pf->dev = dev; hw = &pf->hw; /* ** Note this assumes we have a single embedded VSI, ** this could be enhanced later to allocate multiple */ - vsi = &pf->vsi; - vsi->dev = pf->dev; - vsi->back = pf; + //vsi->dev = pf->dev; + vsi->hw = &pf->hw; + vsi->id = 0; + vsi->num_vlans = 0; + vsi->ctx = ctx; + vsi->media = iflib_get_media(ctx); + vsi->shared = scctx = iflib_get_softc_ctx(ctx); /* Save tunable values */ - error = ixl_save_pf_tunables(pf); - if (error) - return (error); - - /* Core Lock Init*/ - IXL_PF_LOCK_INIT(pf, device_get_nameunit(dev)); - - /* Set up the timer callout */ - callout_init_mtx(&pf->timer, &pf->pf_mtx, 0); + ixl_save_pf_tunables(pf); /* Do PCI setup - map BAR0, etc */ if (ixl_allocate_pci_resources(pf)) { device_printf(dev, "Allocation of PCI resources failed\n"); error = ENXIO; - goto err_out; + goto err_pci_res; } /* Establish a clean starting point */ @@ -478,16 +477,11 @@ /* Get capabilities from the device */ error = ixl_get_hw_capabilities(pf); if (error) { - device_printf(dev, "HW capabilities failure!\n"); + device_printf(dev, "get_hw_capabilities failed: %d\n", + error); goto err_get_cap; } - /* - * Allocate interrupts and figure out number of queues to use - * for PF interface - */ - pf->msix = ixl_init_msix(pf); - /* Set up host memory cache */ status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, hw->func_caps.num_rx_qp, 0, 0); @@ -496,7 +490,6 @@ i40e_stat_str(hw, status)); goto err_get_cap; } - status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); if (status) { device_printf(dev, "configure_lan_hmc failed: %s\n", @@ -504,23 +497,6 @@ goto err_mac_hmc; } - /* Init queue allocation manager */ - error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp); - if (error) { - device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", - error); - goto err_mac_hmc; - } - /* reserve a contiguous allocation for the PF's VSI */ - error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); - if (error) { - device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", - error); - goto err_mac_hmc; - } - device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", - pf->qtag.num_allocated, pf->qtag.num_active); - /* Disable LLDP from the firmware for certain NVM versions */ if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || (pf->hw.aq.fw_maj_ver < 4)) { @@ -536,46 +512,120 @@ goto err_mac_hmc; } bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); + iflib_set_mac(ctx, hw->mac.addr); i40e_get_port_mac_addr(hw, hw->mac.port_addr); + /* Set up the device filtering */ + bzero(&filter, sizeof(filter)); + filter.enable_ethtype = TRUE; + filter.enable_macvlan = TRUE; + filter.enable_fdir = FALSE; + filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; + if (i40e_set_filter_control(hw, &filter)) + device_printf(dev, "i40e_set_filter_control() failed\n"); + /* Query device FW LLDP status */ ixl_get_fw_lldp_status(pf); /* Tell FW to apply DCB config on link up */ - if ((hw->mac.type != I40E_MAC_X722) - && ((pf->hw.aq.api_maj_ver > 1) - || (pf->hw.aq.api_maj_ver == 1 && pf->hw.aq.api_min_ver >= 7))) - i40e_aq_set_dcb_parameters(hw, true, NULL); + i40e_aq_set_dcb_parameters(hw, true, NULL); - /* Initialize mac filter list for VSI */ - SLIST_INIT(&vsi->ftl); - - /* Set up SW VSI and allocate queue memory and rings */ - if (ixl_setup_stations(pf)) { - device_printf(dev, "setup stations failed!\n"); - error = ENOMEM; - goto err_mac_hmc; + /* Fill out iflib parameters */ + if (hw->mac.type == I40E_MAC_X722) + scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 128; + else + scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64; + if (vsi->enable_head_writeback) { + scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] + * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN); + scctx->isc_txrx = &ixl_txrx_hwb; + } else { + scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] + * sizeof(struct i40e_tx_desc), DBA_ALIGN); + scctx->isc_txrx = &ixl_txrx_dwb; } + scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] + * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN); + scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR); + scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS; + scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS; + scctx->isc_tx_tso_size_max = IXL_TSO_SIZE; + scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE; + scctx->isc_rss_table_size = pf->hw.func_caps.rss_table_size; + scctx->isc_tx_csum_flags = CSUM_OFFLOAD; + scctx->isc_capenable = IXL_CAPS; + + INIT_DEBUGOUT("ixl_if_attach_pre: end"); + return (0); + +err_mac_hmc: + i40e_shutdown_lan_hmc(hw); +err_get_cap: + i40e_shutdown_adminq(hw); +err_out: + ixl_free_pci_resources(pf); +err_pci_res: + return (error); +} + +static int +ixl_if_attach_post(if_ctx_t ctx) +{ + device_t dev; + struct ixl_pf *pf; + struct i40e_hw *hw; + struct ixl_vsi *vsi; + int error = 0; + enum i40e_status_code status; + + INIT_DEBUGOUT("ixl_if_attach_post: begin"); + + dev = iflib_get_dev(ctx); + pf = iflib_get_softc(ctx); + vsi = &pf->vsi; + vsi->ifp = iflib_get_ifp(ctx); + hw = &pf->hw; /* Setup OS network interface / ifnet */ - if (ixl_setup_interface(dev, vsi)) { + if (ixl_setup_interface(dev, pf)) { device_printf(dev, "interface setup failed!\n"); error = EIO; - goto err_late; + goto err; } /* Determine link state */ if (ixl_attach_get_link_status(pf)) { error = EINVAL; - goto err_late; + goto err; } error = ixl_switch_config(pf); if (error) { device_printf(dev, "Initial ixl_switch_config() failed: %d\n", error); - goto err_late; + goto err; } + /* Add protocol filters to list */ + ixl_init_filters(vsi); + + /* Init queue allocation manager */ + error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp); + if (error) { + device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", + error); + goto err; + } + /* reserve a contiguous allocation for the PF's VSI */ + error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, + max(vsi->num_rx_queues, vsi->num_tx_queues), &pf->qtag); + if (error) { + device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", + error); + goto err; + } + device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", + pf->qtag.num_allocated, pf->qtag.num_active); + /* Limit PHY interrupts to link, autoneg, and modules failure */ status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, NULL); @@ -583,59 +633,16 @@ device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," " aq_err %s\n", i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status)); - goto err_late; + goto err; } - /* Get the bus configuration and set the shared code's config */ + /* Get the bus configuration and set the shared code */ ixl_get_bus_info(pf); - /* - * In MSI-X mode, initialize the Admin Queue interrupt, - * so userland tools can communicate with the adapter regardless of - * the ifnet interface's status. - */ - if (pf->msix > 1) { - error = ixl_setup_adminq_msix(pf); - if (error) { - device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", - error); - goto err_late; - } - error = ixl_setup_adminq_tq(pf); - if (error) { - device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", - error); - goto err_late; - } - ixl_configure_intr0_msix(pf); - ixl_enable_intr0(hw); - - error = ixl_setup_queue_msix(vsi); - if (error) - device_printf(dev, "ixl_setup_queue_msix() error: %d\n", - error); - error = ixl_setup_queue_tqs(vsi); - if (error) - device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", - error); - } else { - error = ixl_setup_legacy(pf); - - error = ixl_setup_adminq_tq(pf); - if (error) { - device_printf(dev, "ixl_setup_adminq_tq() error: %d\n", - error); - goto err_late; - } - - error = ixl_setup_queue_tqs(vsi); - if (error) - device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", - error); - } - - if (error) { - device_printf(dev, "interrupt setup error: %d\n", error); + /* Keep admin queue interrupts active while driver is loaded */ + if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { + ixl_configure_intr0_msix(pf); + ixl_enable_intr0(hw); } /* Set initial advertised speed sysctl value */ @@ -643,31 +650,18 @@ /* Initialize statistics & add sysctls */ ixl_add_device_sysctls(pf); - ixl_pf_reset_stats(pf); ixl_update_stats_counters(pf); ixl_add_hw_stats(pf); - /* Register for VLAN events */ - vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); - vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); + hw->phy.get_link_info = true; + i40e_get_link_status(hw, &pf->link_up); + ixl_update_link_status(pf); #ifdef PCI_IOV ixl_initialize_sriov(pf); #endif -#ifdef DEV_NETMAP - if (vsi->num_rx_desc == vsi->num_tx_desc) { - vsi->queues[0].num_desc = vsi->num_rx_desc; - ixl_netmap_attach(vsi); - } else - device_printf(dev, - "Netmap is not supported when RX and TX descriptor ring sizes differ\n"); - -#endif /* DEV_NETMAP */ - #ifdef IXL_IW if (hw->func_caps.iwarp && ixl_enable_iwarp) { pf->iw_enabled = (pf->iw_msix > 0) ? true : false; @@ -677,7 +671,7 @@ device_printf(dev, "interfacing to iwarp driver failed: %d\n", error); - goto err_late; + goto err; } else device_printf(dev, "iWARP ready\n"); } else @@ -689,94 +683,28 @@ } #endif - INIT_DEBUGOUT("ixl_attach: end"); + INIT_DBG_DEV(dev, "end"); return (0); -err_late: - if (vsi->ifp != NULL) { - ether_ifdetach(vsi->ifp); - if_free(vsi->ifp); - } -err_mac_hmc: - i40e_shutdown_lan_hmc(hw); -err_get_cap: - i40e_shutdown_adminq(hw); -err_out: - ixl_free_pci_resources(pf); - ixl_free_vsi(vsi); - IXL_PF_LOCK_DESTROY(pf); +err: + INIT_DEBUGOUT("end: error %d", error); + /* ixl_if_detach() is called on error from this */ return (error); } -/********************************************************************* - * Device removal routine - * - * The detach entry point is called when the driver is being removed. - * This routine stops the adapter and deallocates all the resources - * that were allocated for driver operation. - * - * return 0 on success, positive on failure - *********************************************************************/ - static int -ixl_detach(device_t dev) +ixl_if_detach(if_ctx_t ctx) { - struct ixl_pf *pf = device_get_softc(dev); - struct i40e_hw *hw = &pf->hw; - struct ixl_vsi *vsi = &pf->vsi; + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = &pf->hw; + device_t dev = pf->dev; enum i40e_status_code status; #if defined(PCI_IOV) || defined(IXL_IW) int error; #endif - INIT_DEBUGOUT("ixl_detach: begin"); - - /* Make sure VLANS are not using driver */ - if (vsi->ifp->if_vlantrunk != NULL) { - device_printf(dev, "Vlan in use, detach first\n"); - return (EBUSY); - } - -#ifdef PCI_IOV - error = pci_iov_detach(dev); - if (error != 0) { - device_printf(dev, "SR-IOV in use; detach first.\n"); - return (error); - } -#endif - - /* Remove all previously allocated media types */ - ifmedia_removeall(&vsi->media); - - ether_ifdetach(vsi->ifp); - if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) - ixl_stop(pf); - - /* Shutdown LAN HMC */ - status = i40e_shutdown_lan_hmc(hw); - if (status) - device_printf(dev, - "Shutdown LAN HMC failed with code %d\n", status); - - /* Teardown LAN queue resources */ - ixl_teardown_queue_msix(vsi); - ixl_free_queue_tqs(vsi); - /* Shutdown admin queue */ - ixl_disable_intr0(hw); - ixl_teardown_adminq_msix(pf); - ixl_free_adminq_tq(pf); - status = i40e_shutdown_adminq(hw); - if (status) - device_printf(dev, - "Shutdown Admin queue failed with code %d\n", status); - - /* Unregister VLAN events */ - if (vsi->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); - if (vsi->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); - - callout_drain(&pf->timer); + INIT_DBG_DEV(dev, "begin"); #ifdef IXL_IW if (ixl_enable_iwarp && pf->iw_enabled) { @@ -787,30 +715,996 @@ } } #endif +#ifdef PCI_IOV + error = pci_iov_detach(dev); + if (error != 0) { + device_printf(dev, "SR-IOV in use; detach first.\n"); + return (error); + } +#endif + /* Remove all previously allocated media types */ + ifmedia_removeall(vsi->media); + + /* Shutdown LAN HMC */ + if (hw->hmc.hmc_obj) { + status = i40e_shutdown_lan_hmc(hw); + if (status) + device_printf(dev, + "i40e_shutdown_lan_hmc() failed with status %s\n", + i40e_stat_str(hw, status)); + } + + /* Shutdown admin queue */ + ixl_disable_intr0(hw); + status = i40e_shutdown_adminq(hw); + if (status) + device_printf(dev, + "i40e_shutdown_adminq() failed with status %s\n", + i40e_stat_str(hw, status)); -#ifdef DEV_NETMAP - netmap_detach(vsi->ifp); -#endif /* DEV_NETMAP */ ixl_pf_qmgr_destroy(&pf->qmgr); ixl_free_pci_resources(pf); - bus_generic_detach(dev); - if_free(vsi->ifp); - ixl_free_vsi(vsi); - IXL_PF_LOCK_DESTROY(pf); + ixl_free_mac_filters(vsi); + INIT_DBG_DEV(dev, "end"); return (0); } -/********************************************************************* - * - * Shutdown entry point - * - **********************************************************************/ +/* TODO: Do shutdown-specific stuff here */ +static int +ixl_if_shutdown(if_ctx_t ctx) +{ + int error = 0; + + INIT_DEBUGOUT("ixl_if_shutdown: begin"); + + /* TODO: Call ixl_if_stop()? */ + + /* TODO: Then setup low power mode */ + + return (error); +} static int -ixl_shutdown(device_t dev) +ixl_if_suspend(if_ctx_t ctx) { - struct ixl_pf *pf = device_get_softc(dev); - ixl_stop(pf); + int error = 0; + + INIT_DEBUGOUT("ixl_if_suspend: begin"); + + /* TODO: Call ixl_if_stop()? */ + + /* TODO: Then setup low power mode */ + + return (error); +} + +static int +ixl_if_resume(if_ctx_t ctx) +{ + struct ifnet *ifp = iflib_get_ifp(ctx); + + INIT_DEBUGOUT("ixl_if_resume: begin"); + + /* Read & clear wake-up registers */ + + /* Required after D3->D0 transition */ + if (ifp->if_flags & IFF_UP) + ixl_if_init(ctx); + return (0); } +/* Set Report Status queue fields to 0 */ +static void +ixl_init_tx_rsqs(struct ixl_vsi *vsi) +{ + if_softc_ctx_t scctx = vsi->shared; + struct ixl_tx_queue *tx_que; + int i, j; + + for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) { + struct tx_ring *txr = &tx_que->txr; + + txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0; + + for (j = 0; j < scctx->isc_ntxd[0]; j++) + txr->tx_rsq[j] = QIDX_INVALID; + } +} + +static void +ixl_init_tx_cidx(struct ixl_vsi *vsi) +{ + struct ixl_tx_queue *tx_que; + int i; + + for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) { + struct tx_ring *txr = &tx_que->txr; + + txr->tx_cidx_processed = 0; + } +} + +void +ixl_if_init(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = &pf->hw; + device_t dev = iflib_get_dev(ctx); + u8 tmpaddr[ETHER_ADDR_LEN]; + int ret; + + /* + * If the aq is dead here, it probably means something outside of the driver + * did something to the adapter, like a PF reset. + * So rebuild the driver's state here if that occurs. + */ + if (!i40e_check_asq_alive(&pf->hw)) { + device_printf(dev, "Admin Queue is down; resetting...\n"); + ixl_teardown_hw_structs(pf); + ixl_reset(pf); + } + + /* Get the latest mac address... User might use a LAA */ + bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETH_ALEN); + if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && + (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { + ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); + bcopy(tmpaddr, hw->mac.addr, ETH_ALEN); + ret = i40e_aq_mac_address_write(hw, + I40E_AQC_WRITE_TYPE_LAA_ONLY, + hw->mac.addr, NULL); + if (ret) { + device_printf(dev, "LLA address change failed!!\n"); + return; + } + ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); + } + + iflib_set_mac(ctx, hw->mac.addr); + + /* Prepare the VSI: rings, hmc contexts, etc... */ + if (ixl_initialize_vsi(vsi)) { + device_printf(dev, "initialize vsi failed!!\n"); + return; + } + + // TODO: Call iflib setup multicast filters here? + // It's called in ixgbe in D5213 + ixl_if_multi_set(ctx); + + /* Set up RSS */ + ixl_config_rss(pf); + + /* Set up MSI/X routing and the ITR settings */ + if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { + ixl_configure_queue_intr_msix(pf); + ixl_configure_itr(pf); + } else + ixl_configure_legacy(pf); + + if (vsi->enable_head_writeback) + ixl_init_tx_cidx(vsi); + else + ixl_init_tx_rsqs(vsi); + + ixl_enable_rings(vsi); + + i40e_aq_set_default_vsi(hw, vsi->seid, NULL); + + ixl_reconfigure_filters(vsi); + +#ifdef IXL_IW + if (ixl_enable_iwarp && pf->iw_enabled) { + ret = ixl_iw_pf_init(pf); + if (ret) + device_printf(dev, + "initialize iwarp failed, code %d\n", ret); + } +#endif +} + +void +ixl_if_stop(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + + INIT_DEBUGOUT("ixl_if_stop: begin\n"); + + // TODO: This may need to be reworked +#ifdef IXL_IW + /* Stop iWARP device */ + if (ixl_enable_iwarp && pf->iw_enabled) + ixl_iw_pf_stop(pf); +#endif + + ixl_disable_rings_intr(vsi); + ixl_disable_rings(vsi); +} + +static int +ixl_if_msix_intr_assign(if_ctx_t ctx, int msix) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct ixl_rx_queue *rx_que = vsi->rx_queues; + struct ixl_tx_queue *tx_que = vsi->tx_queues; + int err, i, rid, vector = 0; + char buf[16]; + + /* Admin Que must use vector 0*/ + rid = vector + 1; + err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN, + ixl_msix_adminq, pf, 0, "aq"); + if (err) { + iflib_irq_free(ctx, &vsi->irq); + device_printf(iflib_get_dev(ctx), + "Failed to register Admin que handler"); + return (err); + } + // TODO: Re-enable this at some point + // iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_IOV, pf, 0, "ixl_iov"); + + /* Now set up the stations */ + for (i = 0, vector = 1; i < vsi->num_rx_queues; i++, vector++, rx_que++) { + rid = vector + 1; + + snprintf(buf, sizeof(buf), "rxq%d", i); + err = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid, + IFLIB_INTR_RX, ixl_msix_que, rx_que, rx_que->rxr.me, buf); + /* XXX: Does the driver work as expected if there are fewer num_rx_queues than + * what's expected in the iflib context? */ + if (err) { + device_printf(iflib_get_dev(ctx), + "Failed to allocate q int %d err: %d", i, err); + vsi->num_rx_queues = i + 1; + goto fail; + } + rx_que->msix = vector; + } + + bzero(buf, sizeof(buf)); + + for (i = 0; i < vsi->num_tx_queues; i++, tx_que++) { + snprintf(buf, sizeof(buf), "txq%d", i); + iflib_softirq_alloc_generic(ctx, + &vsi->rx_queues[i % vsi->num_rx_queues].que_irq, + IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf); + + /* TODO: Maybe call a strategy function for this to figure out which + * interrupts to map Tx queues to. I don't know if there's an immediately + * better way than this other than a user-supplied map, though. */ + tx_que->msix = (i % vsi->num_rx_queues) + 1; + } + + return (0); +fail: + iflib_irq_free(ctx, &vsi->irq); + rx_que = vsi->rx_queues; + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) + iflib_irq_free(ctx, &rx_que->que_irq); + return (err); +} + +/* + * Enable all interrupts + * + * Called in: + * iflib_init_locked, after ixl_if_init() + */ +static void +ixl_if_enable_intr(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + struct ixl_rx_queue *que = vsi->rx_queues; + + ixl_enable_intr0(hw); + /* Enable queue interrupts */ + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + /* TODO: Queue index parameter is probably wrong */ + ixl_enable_queue(hw, que->rxr.me); +} + +/* + * Disable queue interrupts + * + * Other interrupt causes need to remain active. + */ +static void +ixl_if_disable_intr(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + struct ixl_rx_queue *rx_que = vsi->rx_queues; + + if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) + ixl_disable_queue(hw, rx_que->msix - 1); + } else { + // Set PFINT_LNKLST0 FIRSTQ_INDX to 0x7FF + // stops queues from triggering interrupts + wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); + } +} + +static int +ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + struct ixl_rx_queue *rx_que = &vsi->rx_queues[rxqid]; + + ixl_enable_queue(hw, rx_que->msix - 1); + return (0); +} + +static int +ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid]; + + ixl_enable_queue(hw, tx_que->msix - 1); + + return (0); +} + +static int +ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + if_softc_ctx_t scctx = vsi->shared; + struct ixl_tx_queue *que; + // int i; + int i, j, error = 0; + + MPASS(vsi->num_tx_queues > 0); + MPASS(ntxqs == 1); + MPASS(vsi->num_tx_queues == ntxqsets); + + /* Allocate queue structure memory */ + if (!(vsi->tx_queues = + (struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXL, M_NOWAIT | M_ZERO))) { + device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n"); + return (ENOMEM); + } + + for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) { + struct tx_ring *txr = &que->txr; + + txr->me = i; + que->vsi = vsi; + + if (!vsi->enable_head_writeback) { + /* Allocate report status array */ + if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXL, M_NOWAIT))) { + device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n"); + error = ENOMEM; + goto fail; + } + /* Init report status array */ + for (j = 0; j < scctx->isc_ntxd[0]; j++) + txr->tx_rsq[j] = QIDX_INVALID; + } + /* get the virtual and physical address of the hardware queues */ + txr->tail = I40E_QTX_TAIL(txr->me); + txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs]; + txr->tx_paddr = paddrs[i * ntxqs]; + txr->que = que; + } + + return (0); +fail: + ixl_if_queues_free(ctx); + return (error); +} + +static int +ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct ixl_rx_queue *que; + int i, error = 0; + + MPASS(vsi->num_rx_queues > 0); + MPASS(nrxqs == 1); + MPASS(vsi->num_rx_queues == nrxqsets); + + /* Allocate queue structure memory */ + if (!(vsi->rx_queues = + (struct ixl_rx_queue *) malloc(sizeof(struct ixl_rx_queue) * + nrxqsets, M_IXL, M_NOWAIT | M_ZERO))) { + device_printf(iflib_get_dev(ctx), "Unable to allocate RX ring memory\n"); + error = ENOMEM; + goto fail; + } + + for (i = 0, que = vsi->rx_queues; i < nrxqsets; i++, que++) { + struct rx_ring *rxr = &que->rxr; + + rxr->me = i; + que->vsi = vsi; + + /* get the virtual and physical address of the hardware queues */ + rxr->tail = I40E_QRX_TAIL(rxr->me); + rxr->rx_base = (union i40e_rx_desc *)vaddrs[i * nrxqs]; + rxr->rx_paddr = paddrs[i * nrxqs]; + rxr->que = que; + } + + return (0); +fail: + ixl_if_queues_free(ctx); + return (error); +} + +static void +ixl_if_queues_free(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + + if (vsi->enable_head_writeback) { + struct ixl_tx_queue *que; + int i = 0; + + for (i = 0, que = vsi->tx_queues; i < vsi->num_tx_queues; i++, que++) { + struct tx_ring *txr = &que->txr; + if (txr->tx_rsq != NULL) { + free(txr->tx_rsq, M_IXL); + txr->tx_rsq = NULL; + } + } + } + + if (vsi->tx_queues != NULL) { + free(vsi->tx_queues, M_IXL); + vsi->tx_queues = NULL; + } + if (vsi->rx_queues != NULL) { + free(vsi->rx_queues, M_IXL); + vsi->rx_queues = NULL; + } +} + +void +ixl_update_link_status(struct ixl_pf *pf) +{ + struct ixl_vsi *vsi = &pf->vsi; + u64 baudrate; + + if (pf->link_up) { + if (vsi->link_active == FALSE) { + vsi->link_active = TRUE; + baudrate = ixl_max_aq_speed_to_value(pf->link_speed); + iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate); + ixl_link_up_msg(pf); +#ifdef PCI_IOV + ixl_broadcast_link_state(pf); +#endif + + } + } else { /* Link down */ + if (vsi->link_active == TRUE) { + vsi->link_active = FALSE; + iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0); +#ifdef PCI_IOV + ixl_broadcast_link_state(pf); +#endif + } + } +} + +static int +ixl_process_adminq(struct ixl_pf *pf, u16 *pending) +{ + enum i40e_status_code status = I40E_SUCCESS; + struct i40e_arq_event_info event; + struct i40e_hw *hw = &pf->hw; + device_t dev = pf->dev; + u16 opcode; + u32 loop = 0, reg; + + event.buf_len = IXL_AQ_BUF_SZ; + event.msg_buf = malloc(event.buf_len, M_IXL, M_NOWAIT | M_ZERO); + if (!event.msg_buf) { + device_printf(dev, "%s: Unable to allocate memory for Admin" + " Queue event!\n", __func__); + return (ENOMEM); + } + + /* clean and process any events */ + do { + status = i40e_clean_arq_element(hw, &event, pending); + if (status) + break; + opcode = LE16_TO_CPU(event.desc.opcode); + ixl_dbg(pf, IXL_DBG_AQ, + "Admin Queue event: %#06x\n", opcode); + switch (opcode) { + case i40e_aqc_opc_get_link_status: + ixl_link_event(pf, &event); + break; + case i40e_aqc_opc_send_msg_to_pf: +#ifdef PCI_IOV + ixl_handle_vf_msg(pf, &event); +#endif + break; + /* + * This should only occur on no-drop queues, which + * aren't currently configured. + */ + case i40e_aqc_opc_event_lan_overflow: + device_printf(dev, "LAN overflow event\n"); + break; + default: + break; + } + } while (*pending && (loop++ < IXL_ADM_LIMIT)); + + free(event.msg_buf, M_IXL); + + /* Re-enable admin queue interrupt cause */ + reg = rd32(hw, I40E_PFINT_ICR0_ENA); + reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, reg); + + return (status); +} + +static void +ixl_if_update_admin_status(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct i40e_hw *hw = &pf->hw; + u16 pending; + + if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING) + ixl_handle_empr_reset(pf); + + if (pf->state & IXL_PF_STATE_MDD_PENDING) + ixl_handle_mdd_event(pf); + +#ifdef PCI_IOV + if (pf->state & IXL_PF_STATE_VF_RESET_REQ) + iflib_iov_intr_deferred(ctx); +#endif + + ixl_process_adminq(pf, &pending); + ixl_update_link_status(pf); + + /* + * If there are still messages to process, reschedule ourselves. + * Otherwise, re-enable our interrupt and go to sleep. + */ + if (pending > 0) + iflib_admin_intr_deferred(ctx); + else + ixl_enable_intr0(hw); +} + +static void +ixl_if_multi_set(if_ctx_t ctx) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + int mcnt = 0, flags; + + IOCTL_DEBUGOUT("ixl_if_multi_set: begin"); + + mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR); + /* delete existing MC filters */ + ixl_del_multi(vsi); + + if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { + i40e_aq_set_vsi_multicast_promiscuous(hw, + vsi->seid, TRUE, NULL); + return; + } + /* (re-)install filters for all mcast addresses */ + mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi); + + if (mcnt > 0) { + flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); + ixl_add_hw_filters(vsi, flags, mcnt); + } + + IOCTL_DEBUGOUT("ixl_if_multi_set: end"); +} + +static int +ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + + IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); + if (mtu > IXL_MAX_FRAME - ETHER_HDR_LEN - ETHER_CRC_LEN - + ETHER_VLAN_ENCAP_LEN) + return (EINVAL); + + vsi->shared->isc_max_frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + + ETHER_VLAN_ENCAP_LEN; + + return (0); +} + +static void +ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct i40e_hw *hw = &pf->hw; + + INIT_DEBUGOUT("ixl_media_status: begin"); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!pf->link_up) { + return; + } + + ifmr->ifm_status |= IFM_ACTIVE; + /* Hardware is always full-duplex */ + ifmr->ifm_active |= IFM_FDX; + + switch (hw->phy.link_info.phy_type) { + /* 100 M */ + case I40E_PHY_TYPE_100BASE_TX: + ifmr->ifm_active |= IFM_100_TX; + break; + /* 1 G */ + case I40E_PHY_TYPE_1000BASE_T: + ifmr->ifm_active |= IFM_1000_T; + break; + case I40E_PHY_TYPE_1000BASE_SX: + ifmr->ifm_active |= IFM_1000_SX; + break; + case I40E_PHY_TYPE_1000BASE_LX: + ifmr->ifm_active |= IFM_1000_LX; + break; + case I40E_PHY_TYPE_1000BASE_T_OPTICAL: + ifmr->ifm_active |= IFM_1000_T; + break; + /* 10 G */ + case I40E_PHY_TYPE_10GBASE_SFPP_CU: + ifmr->ifm_active |= IFM_10G_TWINAX; + break; + case I40E_PHY_TYPE_10GBASE_SR: + ifmr->ifm_active |= IFM_10G_SR; + break; + case I40E_PHY_TYPE_10GBASE_LR: + ifmr->ifm_active |= IFM_10G_LR; + break; + case I40E_PHY_TYPE_10GBASE_T: + ifmr->ifm_active |= IFM_10G_T; + break; + case I40E_PHY_TYPE_XAUI: + case I40E_PHY_TYPE_XFI: + ifmr->ifm_active |= IFM_10G_TWINAX; + break; + case I40E_PHY_TYPE_10GBASE_AOC: + ifmr->ifm_active |= IFM_10G_AOC; + break; + /* 25 G */ + case I40E_PHY_TYPE_25GBASE_KR: + ifmr->ifm_active |= IFM_25G_KR; + break; + case I40E_PHY_TYPE_25GBASE_CR: + ifmr->ifm_active |= IFM_25G_CR; + break; + case I40E_PHY_TYPE_25GBASE_SR: + ifmr->ifm_active |= IFM_25G_SR; + break; + case I40E_PHY_TYPE_25GBASE_LR: + ifmr->ifm_active |= IFM_25G_LR; + break; + case I40E_PHY_TYPE_25GBASE_AOC: + ifmr->ifm_active |= IFM_25G_AOC; + break; + case I40E_PHY_TYPE_25GBASE_ACC: + ifmr->ifm_active |= IFM_25G_ACC; + break; + /* 40 G */ + case I40E_PHY_TYPE_40GBASE_CR4: + case I40E_PHY_TYPE_40GBASE_CR4_CU: + ifmr->ifm_active |= IFM_40G_CR4; + break; + case I40E_PHY_TYPE_40GBASE_SR4: + ifmr->ifm_active |= IFM_40G_SR4; + break; + case I40E_PHY_TYPE_40GBASE_LR4: + ifmr->ifm_active |= IFM_40G_LR4; + break; + case I40E_PHY_TYPE_XLAUI: + ifmr->ifm_active |= IFM_OTHER; + break; + case I40E_PHY_TYPE_1000BASE_KX: + ifmr->ifm_active |= IFM_1000_KX; + break; + case I40E_PHY_TYPE_SGMII: + ifmr->ifm_active |= IFM_1000_SGMII; + break; + /* ERJ: What's the difference between these? */ + case I40E_PHY_TYPE_10GBASE_CR1_CU: + case I40E_PHY_TYPE_10GBASE_CR1: + ifmr->ifm_active |= IFM_10G_CR1; + break; + case I40E_PHY_TYPE_10GBASE_KX4: + ifmr->ifm_active |= IFM_10G_KX4; + break; + case I40E_PHY_TYPE_10GBASE_KR: + ifmr->ifm_active |= IFM_10G_KR; + break; + case I40E_PHY_TYPE_SFI: + ifmr->ifm_active |= IFM_10G_SFI; + break; + /* Our single 20G media type */ + case I40E_PHY_TYPE_20GBASE_KR2: + ifmr->ifm_active |= IFM_20G_KR2; + break; + case I40E_PHY_TYPE_40GBASE_KR4: + ifmr->ifm_active |= IFM_40G_KR4; + break; + case I40E_PHY_TYPE_XLPPI: + case I40E_PHY_TYPE_40GBASE_AOC: + ifmr->ifm_active |= IFM_40G_XLPPI; + break; + /* Unknown to driver */ + default: + ifmr->ifm_active |= IFM_UNKNOWN; + break; + } + /* Report flow control status as well */ + if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) + ifmr->ifm_active |= IFM_ETH_TXPAUSE; + if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) + ifmr->ifm_active |= IFM_ETH_RXPAUSE; +} + +static int +ixl_if_media_change(if_ctx_t ctx) +{ + struct ifmedia *ifm = iflib_get_media(ctx); + + INIT_DEBUGOUT("ixl_media_change: begin"); + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + if_printf(iflib_get_ifp(ctx), "Media change is not supported.\n"); + return (ENODEV); +} + +static int +ixl_if_promisc_set(if_ctx_t ctx, int flags) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct ifnet *ifp = iflib_get_ifp(ctx); + struct i40e_hw *hw = vsi->hw; + int err; + bool uni = FALSE, multi = FALSE; + + if (flags & IFF_PROMISC) + uni = multi = TRUE; + else if (flags & IFF_ALLMULTI || + if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR) + multi = TRUE; + + err = i40e_aq_set_vsi_unicast_promiscuous(hw, + vsi->seid, uni, NULL, true); + if (err) + return (err); + err = i40e_aq_set_vsi_multicast_promiscuous(hw, + vsi->seid, multi, NULL); + return (err); +} + +static void +ixl_if_timer(if_ctx_t ctx, uint16_t qid) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + //struct i40e_hw *hw = &pf->hw; + //struct ixl_tx_queue *que = &vsi->tx_queues[qid]; + #if 0 + u32 mask; + + /* + ** Check status of the queues + */ + mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); + + /* If queue param has outstanding work, trigger sw irq */ + // TODO: TX queues in iflib don't use HW interrupts; does this do anything? + if (que->busy) + wr32(hw, I40E_PFINT_DYN_CTLN(que->txr.me), mask); +#endif + + if (qid != 0) + return; + + /* Fire off the adminq task */ + iflib_admin_intr_deferred(ctx); + + /* Update stats */ + ixl_update_stats_counters(pf); +} + +static void +ixl_if_vlan_register(if_ctx_t ctx, u16 vtag) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + ++vsi->num_vlans; + ixl_add_filter(vsi, hw->mac.addr, vtag); +} + +static void +ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + struct i40e_hw *hw = vsi->hw; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + --vsi->num_vlans; + ixl_del_filter(vsi, hw->mac.addr, vtag); +} + +static uint64_t +ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ixl_vsi *vsi = &pf->vsi; + if_t ifp = iflib_get_ifp(ctx); + + switch (cnt) { + case IFCOUNTER_IPACKETS: + return (vsi->ipackets); + case IFCOUNTER_IERRORS: + return (vsi->ierrors); + case IFCOUNTER_OPACKETS: + return (vsi->opackets); + case IFCOUNTER_OERRORS: + return (vsi->oerrors); + case IFCOUNTER_COLLISIONS: + /* Collisions are by standard impossible in 40G/10G Ethernet */ + return (0); + case IFCOUNTER_IBYTES: + return (vsi->ibytes); + case IFCOUNTER_OBYTES: + return (vsi->obytes); + case IFCOUNTER_IMCASTS: + return (vsi->imcasts); + case IFCOUNTER_OMCASTS: + return (vsi->omcasts); + case IFCOUNTER_IQDROPS: + return (vsi->iqdrops); + case IFCOUNTER_OQDROPS: + return (vsi->oqdrops); + case IFCOUNTER_NOPROTO: + return (vsi->noproto); + default: + return (if_get_counter_default(ifp, cnt)); + } +} + +static void +ixl_if_vflr_handle(if_ctx_t ctx) +{ + IXL_DEV_ERR(iflib_get_dev(ctx), ""); + + // TODO: call ixl_handle_vflr() +} + +static int +ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + + if (pf->read_i2c_byte == NULL) + return (EINVAL); + + for (int i = 0; i < req->len; i++) + if (pf->read_i2c_byte(pf, req->offset + i, + req->dev_addr, &req->data[i])) + return (EIO); + return (0); +} + +static int +ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data) +{ + struct ixl_pf *pf = iflib_get_softc(ctx); + struct ifdrv *ifd = (struct ifdrv *)data; + int error = 0; + + /* NVM update command */ + if (ifd->ifd_cmd == I40E_NVM_ACCESS) + error = ixl_handle_nvmupd_cmd(pf, ifd); + else + error = EINVAL; + + return (error); +} + +static int +ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count __unused) +{ + struct ixl_vsi *vsi = arg; + + if (ifma->ifma_addr->sa_family != AF_LINK) + return (0); + ixl_add_mc_filter(vsi, + (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); + return (1); +} + +/* + * Sanity check and save off tunable values. + */ +static void +ixl_save_pf_tunables(struct ixl_pf *pf) +{ + device_t dev = pf->dev; + + /* Save tunable information */ + pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; + pf->dbg_mask = ixl_core_debug_mask; + pf->hw.debug_mask = ixl_shared_debug_mask; + pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); +#if 0 + pf->dynamic_rx_itr = ixl_dynamic_rx_itr; + pf->dynamic_tx_itr = ixl_dynamic_tx_itr; +#endif + + if (ixl_i2c_access_method > 3 || ixl_i2c_access_method < 0) + pf->i2c_access_method = 0; + else + pf->i2c_access_method = ixl_i2c_access_method; + + if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { + device_printf(dev, "Invalid tx_itr value of %d set!\n", + ixl_tx_itr); + device_printf(dev, "tx_itr must be between %d and %d, " + "inclusive\n", + 0, IXL_MAX_ITR); + device_printf(dev, "Using default value of %d instead\n", + IXL_ITR_4K); + pf->tx_itr = IXL_ITR_4K; + } else + pf->tx_itr = ixl_tx_itr; + + if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { + device_printf(dev, "Invalid rx_itr value of %d set!\n", + ixl_rx_itr); + device_printf(dev, "rx_itr must be between %d and %d, " + "inclusive\n", + 0, IXL_MAX_ITR); + device_printf(dev, "Using default value of %d instead\n", + IXL_ITR_8K); + pf->rx_itr = IXL_ITR_8K; + } else + pf->rx_itr = ixl_rx_itr; +} + Index: sys/dev/ixl/if_ixlv.c =================================================================== --- sys/dev/ixl/if_ixlv.c +++ sys/dev/ixl/if_ixlv.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -44,102 +44,86 @@ char ixlv_driver_version[] = __XSTRING(IXLV_DRIVER_VERSION_MAJOR) "." __XSTRING(IXLV_DRIVER_VERSION_MINOR) "." - __XSTRING(IXLV_DRIVER_VERSION_BUILD) "-k"; + __XSTRING(IXLV_DRIVER_VERSION_BUILD) "-iflib-k"; /********************************************************************* * PCI Device ID Table * * Used by probe to select devices to load on - * Last field stores an index into ixlv_strings - * Last entry must be all 0s * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } + * ( Vendor ID, Device ID, Branding String ) *********************************************************************/ -static ixl_vendor_info_t ixlv_vendor_info_array[] = +static pci_vendor_info_t ixlv_vendor_info_array[] = { {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_VF, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X722_VF, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_ADAPTIVE_VF, 0, 0, 0}, /* required last entry */ - {0, 0, 0, 0, 0} + PVID_END }; -/********************************************************************* - * Table of branding strings - *********************************************************************/ - -static char *ixlv_strings[] = { - "Intel(R) Ethernet Connection 700 Series VF Driver" -}; - - /********************************************************************* * Function prototypes *********************************************************************/ -static int ixlv_probe(device_t); -static int ixlv_attach(device_t); -static int ixlv_detach(device_t); -static int ixlv_shutdown(device_t); -static void ixlv_init_locked(struct ixlv_sc *); +static void *ixlv_register(device_t dev); +static int ixlv_if_attach_pre(if_ctx_t ctx); +static int ixlv_if_attach_post(if_ctx_t ctx); +static int ixlv_if_detach(if_ctx_t ctx); +static int ixlv_if_shutdown(if_ctx_t ctx); +static int ixlv_if_suspend(if_ctx_t ctx); +static int ixlv_if_resume(if_ctx_t ctx); +static int ixlv_if_msix_intr_assign(if_ctx_t ctx, int msix); +static void ixlv_if_enable_intr(if_ctx_t ctx); +static void ixlv_if_disable_intr(if_ctx_t ctx); +static int ixlv_if_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid); +static int ixlv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets); +static int ixlv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); +static void ixlv_if_queues_free(if_ctx_t ctx); +static void ixlv_if_update_admin_status(if_ctx_t ctx); +static void ixlv_if_multi_set(if_ctx_t ctx); +static int ixlv_if_mtu_set(if_ctx_t ctx, uint32_t mtu); +static void ixlv_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr); +static int ixlv_if_media_change(if_ctx_t ctx); +static int ixlv_if_promisc_set(if_ctx_t ctx, int flags); +static void ixlv_if_timer(if_ctx_t ctx, uint16_t qid); +static void ixlv_if_vlan_register(if_ctx_t ctx, u16 vtag); +static void ixlv_if_vlan_unregister(if_ctx_t ctx, u16 vtag); +static uint64_t ixlv_if_get_counter(if_ctx_t ctx, ift_counter cnt); +static void ixlv_if_stop(if_ctx_t ctx); + static int ixlv_allocate_pci_resources(struct ixlv_sc *); -static void ixlv_free_pci_resources(struct ixlv_sc *); -static int ixlv_assign_msix(struct ixlv_sc *); -static int ixlv_init_msix(struct ixlv_sc *); -static int ixlv_init_taskqueue(struct ixlv_sc *); -static int ixlv_setup_queues(struct ixlv_sc *); -static void ixlv_config_rss(struct ixlv_sc *); -static void ixlv_stop(struct ixlv_sc *); -static void ixlv_add_multi(struct ixl_vsi *); -static void ixlv_del_multi(struct ixl_vsi *); -static void ixlv_free_queue(struct ixlv_sc *sc, struct ixl_queue *que); -static void ixlv_free_queues(struct ixl_vsi *); -static int ixlv_setup_interface(device_t, struct ixlv_sc *); -static int ixlv_teardown_adminq_msix(struct ixlv_sc *); - -static int ixlv_media_change(struct ifnet *); -static void ixlv_media_status(struct ifnet *, struct ifmediareq *); - -static void ixlv_local_timer(void *); - -static int ixlv_add_mac_filter(struct ixlv_sc *, u8 *, u16); -static int ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr); -static void ixlv_init_filters(struct ixlv_sc *); -static void ixlv_free_filters(struct ixlv_sc *); - -static void ixlv_msix_que(void *); -static void ixlv_msix_adminq(void *); -static void ixlv_do_adminq(void *, int); -static void ixlv_do_adminq_locked(struct ixlv_sc *sc); -static void ixlv_handle_que(void *, int); -static int ixlv_reset(struct ixlv_sc *); static int ixlv_reset_complete(struct i40e_hw *); -static void ixlv_set_queue_rx_itr(struct ixl_queue *); -static void ixlv_set_queue_tx_itr(struct ixl_queue *); -static void ixl_init_cmd_complete(struct ixl_vc_cmd *, void *, - enum i40e_status_code); -static void ixlv_configure_itr(struct ixlv_sc *); - +static int ixlv_setup_vc(struct ixlv_sc *); +static int ixlv_reset(struct ixlv_sc *); +static int ixlv_vf_config(struct ixlv_sc *); +static void ixlv_init_filters(struct ixlv_sc *); +static void ixlv_free_pci_resources(struct ixlv_sc *); +static void ixlv_free_filters(struct ixlv_sc *); +static void ixlv_setup_interface(device_t, struct ixl_vsi *); +static void ixlv_add_sysctls(struct ixlv_sc *); static void ixlv_enable_adminq_irq(struct i40e_hw *); static void ixlv_disable_adminq_irq(struct i40e_hw *); static void ixlv_enable_queue_irq(struct i40e_hw *, int); static void ixlv_disable_queue_irq(struct i40e_hw *, int); +static void ixlv_config_rss(struct ixlv_sc *); +static void ixlv_stop(struct ixlv_sc *); + +static int ixlv_add_mac_filter(struct ixlv_sc *, u8 *, u16); +static int ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr); +static int ixlv_msix_que(void *); +static int ixlv_msix_adminq(void *); +static void ixlv_do_adminq_locked(struct ixlv_sc *sc); +static void ixl_init_cmd_complete(struct ixl_vc_cmd *, void *, + enum i40e_status_code); +static void ixlv_configure_itr(struct ixlv_sc *); static void ixlv_setup_vlan_filters(struct ixlv_sc *); -static void ixlv_register_vlan(void *, struct ifnet *, u16); -static void ixlv_unregister_vlan(void *, struct ifnet *, u16); - -static void ixlv_init_hw(struct ixlv_sc *); -static int ixlv_setup_vc(struct ixlv_sc *); -static int ixlv_vf_config(struct ixlv_sc *); - -static void ixlv_cap_txcsum_tso(struct ixl_vsi *, - struct ifnet *, int); static char *ixlv_vc_speed_to_string(enum virtchnl_link_speed link_speed); static int ixlv_sysctl_current_speed(SYSCTL_HANDLER_ARGS); -static void ixlv_add_sysctls(struct ixlv_sc *); +// static void ixlv_add_sysctls(struct ixlv_sc *); #ifdef IXL_DEBUG static int ixlv_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS); static int ixlv_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS); @@ -151,11 +135,12 @@ static device_method_t ixlv_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, ixlv_probe), - DEVMETHOD(device_attach, ixlv_attach), - DEVMETHOD(device_detach, ixlv_detach), - DEVMETHOD(device_shutdown, ixlv_shutdown), - {0, 0} + DEVMETHOD(device_register, ixlv_register), + DEVMETHOD(device_probe, iflib_device_probe), + DEVMETHOD(device_attach, iflib_device_attach), + DEVMETHOD(device_detach, iflib_device_detach), + DEVMETHOD(device_shutdown, iflib_device_shutdown), + DEVMETHOD_END }; static driver_t ixlv_driver = { @@ -167,6 +152,41 @@ MODULE_DEPEND(ixlv, pci, 1, 1, 1); MODULE_DEPEND(ixlv, ether, 1, 1, 1); +MODULE_DEPEND(ixlv, iflib, 1, 1, 1); + +static device_method_t ixlv_if_methods[] = { + DEVMETHOD(ifdi_attach_pre, ixlv_if_attach_pre), + DEVMETHOD(ifdi_attach_post, ixlv_if_attach_post), + DEVMETHOD(ifdi_detach, ixlv_if_detach), + DEVMETHOD(ifdi_shutdown, ixlv_if_shutdown), + DEVMETHOD(ifdi_suspend, ixlv_if_suspend), + DEVMETHOD(ifdi_resume, ixlv_if_resume), + DEVMETHOD(ifdi_init, ixlv_if_init), + DEVMETHOD(ifdi_stop, ixlv_if_stop), + DEVMETHOD(ifdi_msix_intr_assign, ixlv_if_msix_intr_assign), + DEVMETHOD(ifdi_intr_enable, ixlv_if_enable_intr), + DEVMETHOD(ifdi_intr_disable, ixlv_if_disable_intr), + DEVMETHOD(ifdi_queue_intr_enable, ixlv_if_queue_intr_enable), + DEVMETHOD(ifdi_tx_queues_alloc, ixlv_if_tx_queues_alloc), + DEVMETHOD(ifdi_rx_queues_alloc, ixlv_if_rx_queues_alloc), + DEVMETHOD(ifdi_queues_free, ixlv_if_queues_free), + DEVMETHOD(ifdi_update_admin_status, ixlv_if_update_admin_status), + DEVMETHOD(ifdi_multi_set, ixlv_if_multi_set), + DEVMETHOD(ifdi_mtu_set, ixlv_if_mtu_set), + // DEVMETHOD(ifdi_crcstrip_set, ixlv_if_crcstrip_set), + DEVMETHOD(ifdi_media_status, ixlv_if_media_status), + DEVMETHOD(ifdi_media_change, ixlv_if_media_change), + DEVMETHOD(ifdi_promisc_set, ixlv_if_promisc_set), + DEVMETHOD(ifdi_timer, ixlv_if_timer), + DEVMETHOD(ifdi_vlan_register, ixlv_if_vlan_register), + DEVMETHOD(ifdi_vlan_unregister, ixlv_if_vlan_unregister), + DEVMETHOD(ifdi_get_counter, ixlv_if_get_counter), + DEVMETHOD_END +}; + +static driver_t ixlv_if_driver = { + "ixlv_if", ixlv_if_methods, sizeof(struct ixlv_sc) +}; /* ** TUNEABLE PARAMETERS: @@ -195,17 +215,6 @@ SYSCTL_INT(_hw_ixlv, OID_AUTO, max_queues, CTLFLAG_RDTUN, &ixlv_max_queues, 0, "Number of Queues"); -/* -** Number of entries in Tx queue buf_ring. -** Increasing this will reduce the number of -** errors when transmitting fragmented UDP -** packets. -*/ -static int ixlv_txbrsz = DEFAULT_TXBRSZ; -TUNABLE_INT("hw.ixlv.txbrsz", &ixlv_txbrsz); -SYSCTL_INT(_hw_ixlv, OID_AUTO, txbr_size, CTLFLAG_RDTUN, - &ixlv_txbrsz, 0, "TX Buf Ring Size"); - /* * Different method for processing TX descriptor * completion. @@ -242,99 +251,99 @@ SYSCTL_INT(_hw_ixlv, OID_AUTO, tx_itr, CTLFLAG_RDTUN, &ixlv_tx_itr, 0, "TX Interrupt Rate"); -/********************************************************************* - * Device identification routine - * - * ixlv_probe determines if the driver should be loaded on - * the hardware based on PCI vendor/device id of the device. - * - * return BUS_PROBE_DEFAULT on success, positive on failure - *********************************************************************/ +extern struct if_txrx ixl_txrx; + +static struct if_shared_ctx ixlv_sctx_init = { + .isc_magic = IFLIB_MAGIC, + .isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */ + .isc_tx_maxsize = IXL_TSO_SIZE, + + .isc_tx_maxsegsize = PAGE_SIZE, + + // TODO: Review the rx_maxsize and rx_maxsegsize params + // Where are they used in iflib? + .isc_rx_maxsize = 16384, + .isc_rx_nsegments = 1, + .isc_rx_maxsegsize = 16384, + // TODO: What is isc_nfl for? + .isc_nfl = 1, + .isc_ntxqs = 1, + .isc_nrxqs = 1, + + .isc_admin_intrcnt = 1, + .isc_vendor_info = ixlv_vendor_info_array, + .isc_driver_version = ixlv_driver_version, + .isc_driver = &ixlv_if_driver, + + .isc_nrxd_min = {IXL_MIN_RING}, + .isc_ntxd_min = {IXL_MIN_RING}, + .isc_nrxd_max = {IXL_MAX_RING}, + .isc_ntxd_max = {IXL_MAX_RING}, + .isc_nrxd_default = {IXL_DEFAULT_RING}, + .isc_ntxd_default = {IXL_DEFAULT_RING}, +}; + +if_shared_ctx_t ixlv_sctx = &ixlv_sctx_init; + +/*** Functions ***/ + +static void * +ixlv_register(device_t dev) +{ + return (ixlv_sctx); + } static int -ixlv_probe(device_t dev) -{ - ixl_vendor_info_t *ent; - - u16 pci_vendor_id, pci_device_id; - u16 pci_subvendor_id, pci_subdevice_id; - char device_name[256]; - -#if 0 - INIT_DEBUGOUT("ixlv_probe: begin"); -#endif - - pci_vendor_id = pci_get_vendor(dev); - if (pci_vendor_id != I40E_INTEL_VENDOR_ID) - return (ENXIO); - - pci_device_id = pci_get_device(dev); - pci_subvendor_id = pci_get_subvendor(dev); - pci_subdevice_id = pci_get_subdevice(dev); - - ent = ixlv_vendor_info_array; - while (ent->vendor_id != 0) { - if ((pci_vendor_id == ent->vendor_id) && - (pci_device_id == ent->device_id) && - - ((pci_subvendor_id == ent->subvendor_id) || - (ent->subvendor_id == 0)) && - - ((pci_subdevice_id == ent->subdevice_id) || - (ent->subdevice_id == 0))) { - sprintf(device_name, "%s, Version - %s", - ixlv_strings[ent->index], - ixlv_driver_version); - device_set_desc_copy(dev, device_name); - return (BUS_PROBE_DEFAULT); - } - ent++; - } - return (ENXIO); -} - -/********************************************************************* - * Device initialization routine - * - * The attach entry point is called when the driver is being loaded. - * This routine identifies the type of hardware, allocates all resources - * and initializes the hardware. - * - * return 0 on success, positive on failure - *********************************************************************/ - -static int -ixlv_attach(device_t dev) +ixlv_if_attach_pre(if_ctx_t ctx) { + device_t dev; struct ixlv_sc *sc; struct i40e_hw *hw; struct ixl_vsi *vsi; - int error = 0; + if_softc_ctx_t scctx; + int error = 0; INIT_DBG_DEV(dev, "begin"); - /* Allocate, clear, and link in our primary soft structure */ - sc = device_get_softc(dev); - sc->dev = sc->osdep.dev = dev; + dev = iflib_get_dev(ctx); + sc = iflib_get_softc(ctx); hw = &sc->hw; + /* + ** Note this assumes we have a single embedded VSI, + ** this could be enhanced later to allocate multiple + */ vsi = &sc->vsi; vsi->dev = dev; + vsi->back = sc; + vsi->hw = &sc->hw; + // vsi->id = 0; + vsi->num_vlans = 0; + vsi->ctx = ctx; + vsi->media = iflib_get_media(ctx); + vsi->shared = scctx = iflib_get_softc_ctx(ctx); + sc->dev = dev; /* Initialize hw struct */ ixlv_init_hw(sc); - - /* Allocate filter lists */ - ixlv_init_filters(sc); + /* + * These are the same across all current ixl models + */ + vsi->shared->isc_tx_nsegments = IXL_MAX_TX_SEGS; + vsi->shared->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR); + vsi->shared->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS; + vsi->shared->isc_tx_tso_size_max = IXL_TSO_SIZE; + vsi->shared->isc_tx_tso_segsize_max = PAGE_SIZE; /* Save this tunable */ vsi->enable_head_writeback = ixlv_enable_head_writeback; - /* Core Lock Init */ - mtx_init(&sc->mtx, device_get_nameunit(dev), - "IXL SC Lock", MTX_DEF); - - /* Set up the timer callout */ - callout_init_mtx(&sc->timer, &sc->mtx, 0); + scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] + * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN); + scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] + * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN); + /* XXX: No idea what this does */ + /* TODO: This value may depend on resources received */ + scctx->isc_max_txqsets = scctx->isc_max_rxqsets = 16; /* Do PCI setup - map BAR0, etc */ if (ixlv_allocate_pci_resources(sc)) { @@ -346,6 +355,7 @@ INIT_DBG_DEV(dev, "Allocated PCI resources and MSIX vectors"); + /* XXX: This is called by init_shared_code in the PF driver */ error = i40e_set_mac_type(hw); if (error) { device_printf(dev, "%s: set_mac_type failed: %d\n", @@ -362,6 +372,7 @@ INIT_DBG_DEV(dev, "VF Device is ready for configuration"); + /* Sets up Admin Queue */ error = ixlv_setup_vc(sc); if (error) { device_printf(dev, "%s: Error setting up PF comms, %d\n", @@ -409,6 +420,7 @@ error = EIO; goto err_res_buf; } + vsi->id = sc->vsi_res->vsi_id; INIT_DBG_DEV(dev, "Resource Acquisition complete"); @@ -420,38 +432,52 @@ addr[0] |= 0x02; bcopy(addr, hw->mac.addr, sizeof(addr)); } + bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); + iflib_set_mac(ctx, hw->mac.addr); - /* Now that the number of queues for this VF is known, set up interrupts */ - sc->msix = ixlv_init_msix(sc); - /* We fail without MSIX support */ - if (sc->msix == 0) { - error = ENXIO; - goto err_res_buf; - } + // TODO: Is this still safe to call? + // ixl_vsi_setup_rings_size(vsi, ixlv_tx_ring_size, ixlv_rx_ring_size); - vsi->id = sc->vsi_res->vsi_id; - vsi->back = (void *)sc; - vsi->flags |= IXL_FLAGS_IS_VF | IXL_FLAGS_USES_MSIX; + /* Allocate filter lists */ + ixlv_init_filters(sc); - ixl_vsi_setup_rings_size(vsi, ixlv_tx_ring_size, ixlv_rx_ring_size); + /* Fill out more iflib parameters */ + scctx->isc_txrx = &ixl_txrx; + // TODO: Probably needs changing + vsi->shared->isc_rss_table_size = sc->hw.func_caps.rss_table_size; + scctx->isc_tx_csum_flags = CSUM_OFFLOAD; + scctx->isc_capenable = IXL_CAPS; - /* This allocates the memory and early settings */ - if (ixlv_setup_queues(sc) != 0) { - device_printf(dev, "%s: setup queues failed!\n", - __func__); - error = EIO; - goto out; - } + INIT_DBG_DEV(dev, "end"); + return (0); +err_res_buf: + free(sc->vf_res, M_DEVBUF); +err_aq: + i40e_shutdown_adminq(hw); +err_pci_res: + ixlv_free_pci_resources(sc); +err_early: + ixlv_free_filters(sc); + INIT_DBG_DEV(dev, "end: error %d", error); + return (error); +} - /* Do queue interrupt setup */ - if (ixlv_assign_msix(sc) != 0) { - device_printf(dev, "%s: allocating queue interrupts failed!\n", - __func__); - error = ENXIO; - goto out; - } +static int +ixlv_if_attach_post(if_ctx_t ctx) +{ + device_t dev; + struct ixlv_sc *sc; + struct i40e_hw *hw; + struct ixl_vsi *vsi; + int error = 0; - INIT_DBG_DEV(dev, "Queue memory and interrupts setup"); + INIT_DBG_DEV(dev, "begin"); + + dev = iflib_get_dev(ctx); + vsi = iflib_get_softc(ctx); + vsi->ifp = iflib_get_ifp(ctx); + sc = (struct ixlv_sc *)vsi->back; + hw = &sc->hw; /* Setup the stack interface */ if (ixlv_setup_interface(dev, sc) != 0) { @@ -463,99 +489,44 @@ INIT_DBG_DEV(dev, "Interface setup complete"); - /* Start AdminQ taskqueue */ - ixlv_init_taskqueue(sc); - - /* We expect a link state message, so schedule the AdminQ task now */ - taskqueue_enqueue(sc->tq, &sc->aq_irq); - - /* Initialize stats */ + /* Initialize statistics & add sysctls */ bzero(&sc->vsi.eth_stats, sizeof(struct i40e_eth_stats)); ixlv_add_sysctls(sc); - /* Register for VLAN events */ - vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - ixlv_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); - vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - ixlv_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); - /* We want AQ enabled early */ ixlv_enable_adminq_irq(hw); - - /* Set things up to run init */ - sc->init_state = IXLV_INIT_READY; - - ixl_vc_init_mgr(sc, &sc->vc_mgr); - INIT_DBG_DEV(dev, "end"); return (error); - +// TODO: Check if any failures can happen above +#if 0 out: - ixlv_free_queues(vsi); - ixlv_teardown_adminq_msix(sc); -err_res_buf: free(sc->vf_res, M_DEVBUF); -err_aq: i40e_shutdown_adminq(hw); -err_pci_res: ixlv_free_pci_resources(sc); -err_early: - mtx_destroy(&sc->mtx); ixlv_free_filters(sc); INIT_DBG_DEV(dev, "end: error %d", error); return (error); +#endif } -/********************************************************************* - * Device removal routine - * - * The detach entry point is called when the driver is being removed. - * This routine stops the adapter and deallocates all the resources - * that were allocated for driver operation. - * - * return 0 on success, positive on failure - *********************************************************************/ - static int -ixlv_detach(device_t dev) +ixlv_if_detach(if_ctx_t ctx) { - struct ixlv_sc *sc = device_get_softc(dev); - struct ixl_vsi *vsi = &sc->vsi; - struct i40e_hw *hw = &sc->hw; - enum i40e_status_code status; + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixlv_sc *sc = vsi->back; + struct i40e_hw *hw = &sc->hw; + device_t dev = sc->dev; + enum i40e_status_code status; INIT_DBG_DEV(dev, "begin"); - /* Make sure VLANS are not using driver */ - if (vsi->ifp->if_vlantrunk != NULL) { - if_printf(vsi->ifp, "Vlan in use, detach first\n"); - return (EBUSY); - } - /* Remove all the media and link information */ ifmedia_removeall(&sc->media); - /* Stop driver */ - ether_ifdetach(vsi->ifp); - if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) { - mtx_lock(&sc->mtx); - ixlv_stop(sc); - mtx_unlock(&sc->mtx); - } - - /* Unregister VLAN events */ - if (vsi->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); - if (vsi->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); - /* Drain VC mgr */ callout_drain(&sc->vc_mgr.callout); ixlv_disable_adminq_irq(hw); - ixlv_teardown_adminq_msix(sc); - /* Drain admin queue taskqueue */ - taskqueue_free(sc->tq); status = i40e_shutdown_adminq(&sc->hw); if (status != I40E_SUCCESS) { device_printf(dev, @@ -563,123 +534,57 @@ i40e_stat_str(hw, status)); } - if_free(vsi->ifp); free(sc->vf_res, M_DEVBUF); - ixlv_free_queues(vsi); ixlv_free_pci_resources(sc); ixlv_free_filters(sc); - bus_generic_detach(dev); - mtx_destroy(&sc->mtx); INIT_DBG_DEV(dev, "end"); return (0); } -/********************************************************************* - * - * Shutdown entry point - * - **********************************************************************/ - +/* TODO: Do shutdown-specific stuff here */ static int -ixlv_shutdown(device_t dev) +ixlv_if_shutdown(if_ctx_t ctx) { - struct ixlv_sc *sc = device_get_softc(dev); + int error = 0; INIT_DBG_DEV(dev, "begin"); - mtx_lock(&sc->mtx); - ixlv_stop(sc); - mtx_unlock(&sc->mtx); + /* TODO: Call ixl_if_stop()? */ + + return (error); +} + +/* TODO: What is a VF supposed to do in suspend/resume? */ +static int +ixlv_if_suspend(if_ctx_t ctx) +{ + int error = 0; + + INIT_DBG_DEV(dev, "begin"); + + /* TODO: Call ixl_if_stop()? */ + + return (error); +} + +static int +ixlv_if_resume(if_ctx_t ctx) +{ + struct ifnet *ifp = iflib_get_ifp(ctx); + + INIT_DBG_DEV(dev, "begin"); + + /* Read & clear wake-up registers */ + + /* Required after D3->D0 transition */ + if (ifp->if_flags & IFF_UP) + ixlv_if_init(ctx); - INIT_DBG_DEV(dev, "end"); return (0); } -/* - * Configure TXCSUM(IPV6) and TSO(4/6) - * - the hardware handles these together so we - * need to tweak them - */ -static void -ixlv_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) -{ - /* Enable/disable TXCSUM/TSO4 */ - if (!(ifp->if_capenable & IFCAP_TXCSUM) - && !(ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) { - ifp->if_capenable |= IFCAP_TXCSUM; - /* enable TXCSUM, restore TSO if previously enabled */ - if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { - vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; - ifp->if_capenable |= IFCAP_TSO4; - } - } - else if (mask & IFCAP_TSO4) { - ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); - vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; - if_printf(ifp, - "TSO4 requires txcsum, enabling both...\n"); - } - } else if((ifp->if_capenable & IFCAP_TXCSUM) - && !(ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) - ifp->if_capenable &= ~IFCAP_TXCSUM; - else if (mask & IFCAP_TSO4) - ifp->if_capenable |= IFCAP_TSO4; - } else if((ifp->if_capenable & IFCAP_TXCSUM) - && (ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) { - vsi->flags |= IXL_FLAGS_KEEP_TSO4; - ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); - if_printf(ifp, - "TSO4 requires txcsum, disabling both...\n"); - } else if (mask & IFCAP_TSO4) - ifp->if_capenable &= ~IFCAP_TSO4; - } - - /* Enable/disable TXCSUM_IPV6/TSO6 */ - if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && !(ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) { - ifp->if_capenable |= IFCAP_TXCSUM_IPV6; - if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { - vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; - ifp->if_capenable |= IFCAP_TSO6; - } - } else if (mask & IFCAP_TSO6) { - ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); - vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; - if_printf(ifp, - "TSO6 requires txcsum6, enabling both...\n"); - } - } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && !(ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) - ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; - else if (mask & IFCAP_TSO6) - ifp->if_capenable |= IFCAP_TSO6; - } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && (ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) { - vsi->flags |= IXL_FLAGS_KEEP_TSO6; - ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); - if_printf(ifp, - "TSO6 requires txcsum6, disabling both...\n"); - } else if (mask & IFCAP_TSO6) - ifp->if_capenable &= ~IFCAP_TSO6; - } -} - -/********************************************************************* - * Ioctl entry point - * - * ixlv_ioctl is called when the user wants to configure the - * interface. - * - * return 0 on success, positive on failure - **********************************************************************/ - +#if 0 static int ixlv_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { @@ -812,6 +717,7 @@ return (error); } +#endif /* ** To do a reinit on the VF is unfortunately more complicated @@ -893,14 +799,18 @@ } } -static void -ixlv_init_locked(struct ixlv_sc *sc) +void +ixlv_if_init(if_ctx_t ctx) { - struct i40e_hw *hw = &sc->hw; - struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; - struct ifnet *ifp = vsi->ifp; - int error = 0; + struct ixl_vsi *vsi = iflib_get_softc(ctx); + if_softc_ctx_t scctx = vsi->shared; + struct ixlv_sc *sc = vsi->back; + struct i40e_hw *hw = &sc->hw; + struct ifnet *ifp = iflib_get_ifp(ctx); + struct ixl_tx_queue *tx_que = vsi->tx_queues; + struct ixl_rx_queue *rx_que = vsi->rx_queues; + + int error = 0; INIT_DBG_IF(ifp, "begin"); @@ -927,14 +837,6 @@ /* Check for an LAA mac address... */ bcopy(IF_LLADDR(ifp), hw->mac.addr, ETHER_ADDR_LEN); - ifp->if_hwassist = 0; - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist |= (CSUM_OFFLOAD_IPV4 & ~CSUM_IP); - if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) - ifp->if_hwassist |= CSUM_OFFLOAD_IPV6; - /* Add mac filter for this VF to PF */ if (i40e_validate_mac_addr(hw->mac.addr) == I40E_SUCCESS) { error = ixlv_add_mac_filter(sc, hw->mac.addr, 0); @@ -947,17 +849,19 @@ /* Setup vlan's if needed */ ixlv_setup_vlan_filters(sc); + // TODO: Functionize /* Prepare the queues for operation */ - for (int i = 0; i < vsi->num_queues; i++, que++) { - struct rx_ring *rxr = &que->rxr; + for (int i = 0; i < vsi->num_tx_queues; i++, tx_que++) { + // TODO: Necessary? Correct? + ixl_init_tx_ring(vsi, tx_que); + } + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) { + struct rx_ring *rxr = &rx_que->rxr; - ixl_init_tx_ring(que); - - if (vsi->max_frame_size <= MCLBYTES) + if (scctx->isc_max_frame_size <= MCLBYTES) rxr->mbuf_sz = MCLBYTES; else rxr->mbuf_sz = MJUMPAGESIZE; - ixl_init_rx_ring(que); } /* Set initial ITR values */ @@ -978,9 +882,6 @@ ixl_vc_enqueue(&sc->vc_mgr, &sc->enable_queues_cmd, IXLV_FLAG_AQ_ENABLE_QUEUES, ixl_init_cmd_complete, sc); - /* Start the local timer */ - callout_reset(&sc->timer, hz, ixlv_local_timer, sc); - sc->init_state = IXLV_RUNNING; init_done: @@ -988,9 +889,7 @@ return; } -/* -** Init entry point for the stack -*/ +#if 0 void ixlv_init(void *arg) { @@ -1047,6 +946,7 @@ hw->bus.device = pci_get_slot(dev); hw->bus.func = pci_get_function(dev); } +#endif /* * ixlv_attach() helper function; initalizes the admin queue @@ -1216,281 +1116,659 @@ return (ret_error); } -/* - * Allocate MSI/X vectors, setup the AQ vector early - */ static int -ixlv_init_msix(struct ixlv_sc *sc) +ixlv_if_msix_intr_assign(if_ctx_t ctx, int msix) { - device_t dev = sc->dev; - int rid, want, vectors, queues, available; - int auto_max_queues; + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixlv_sc *sc = vsi->back; + struct ixl_rx_queue *que = vsi->rx_queues; + struct ixl_tx_queue *tx_que = vsi->tx_queues; + int err, i, rid, vector = 0; + char buf[16]; - rid = PCIR_BAR(IXL_MSIX_BAR); - sc->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!sc->msix_mem) { - /* May not be enabled */ - device_printf(sc->dev, - "Unable to map MSIX table\n"); - goto fail; + /* Admin Que is vector 0*/ + rid = vector + 1; + + err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN, + ixlv_msix_adminq, sc, 0, "aq"); + if (err) { + iflib_irq_free(ctx, &vsi->irq); + device_printf(iflib_get_dev(ctx), "Failed to register Admin que handler"); + return (err); + } + sc->admvec = vector; + ++vector; + + /* Now set up the stations */ + for (i = 0; i < vsi->num_rx_queues; i++, vector++, que++) { + rid = vector + 1; + + snprintf(buf, sizeof(buf), "rxq%d", i); + err = iflib_irq_alloc_generic(ctx, &que->que_irq, rid, IFLIB_INTR_RX, + ixlv_msix_que, que, que->rxr.me, buf); + if (err) { + device_printf(iflib_get_dev(ctx), "Failed to allocate q int %d err: %d", i, err); + vsi->num_rx_queues = i + 1; + goto fail; + } + que->msix = vector; } - available = pci_msix_count(dev); - if (available == 0) { /* system has msix disabled */ - bus_release_resource(dev, SYS_RES_MEMORY, - rid, sc->msix_mem); - sc->msix_mem = NULL; - goto fail; + for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) { + snprintf(buf, sizeof(buf), "txq%d", i); + rid = que->msix + 1; + iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf); } - /* Clamp queues to number of CPUs and # of MSI-X vectors available */ - auto_max_queues = min(mp_ncpus, available - 1); - /* Clamp queues to # assigned to VF by PF */ - auto_max_queues = min(auto_max_queues, sc->vf_res->num_queue_pairs); - - /* Override with tunable value if tunable is less than autoconfig count */ - if ((ixlv_max_queues != 0) && (ixlv_max_queues <= auto_max_queues)) - queues = ixlv_max_queues; - /* Use autoconfig amount if that's lower */ - else if ((ixlv_max_queues != 0) && (ixlv_max_queues > auto_max_queues)) { - device_printf(dev, "ixlv_max_queues (%d) is too large, using " - "autoconfig amount (%d)...\n", - ixlv_max_queues, auto_max_queues); - queues = auto_max_queues; - } - /* Limit maximum auto-configured queues to 8 if no user value is set */ - else - queues = min(auto_max_queues, 8); - -#ifdef RSS - /* If we're doing RSS, clamp at the number of RSS buckets */ - if (queues > rss_getnumbuckets()) - queues = rss_getnumbuckets(); -#endif - - /* - ** Want one vector (RX/TX pair) per queue - ** plus an additional for the admin queue. - */ - want = queues + 1; - if (want <= available) /* Have enough */ - vectors = want; - else { - device_printf(sc->dev, - "MSIX Configuration Problem, " - "%d vectors available but %d wanted!\n", - available, want); - goto fail; - } - -#ifdef RSS - /* - * If we're doing RSS, the number of queues needs to - * match the number of RSS buckets that are configured. - * - * + If there's more queues than RSS buckets, we'll end - * up with queues that get no traffic. - * - * + If there's more RSS buckets than queues, we'll end - * up having multiple RSS buckets map to the same queue, - * so there'll be some contention. - */ - if (queues != rss_getnumbuckets()) { - device_printf(dev, - "%s: queues (%d) != RSS buckets (%d)" - "; performance will be impacted.\n", - __func__, queues, rss_getnumbuckets()); - } -#endif - - if (pci_alloc_msix(dev, &vectors) == 0) { - device_printf(sc->dev, - "Using MSIX interrupts with %d vectors\n", vectors); - sc->msix = vectors; - sc->vsi.num_queues = queues; - } - - /* Next we need to setup the vector for the Admin Queue */ - rid = 1; /* zero vector + 1 */ - sc->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &rid, RF_SHAREABLE | RF_ACTIVE); - if (sc->res == NULL) { - device_printf(dev, "Unable to allocate" - " bus resource: AQ interrupt \n"); - goto fail; - } - if (bus_setup_intr(dev, sc->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixlv_msix_adminq, sc, &sc->tag)) { - sc->res = NULL; - device_printf(dev, "Failed to register AQ handler"); - goto fail; - } - bus_describe_intr(dev, sc->res, sc->tag, "adminq"); - - return (vectors); - -fail: - /* The VF driver MUST use MSIX */ return (0); +fail: + iflib_irq_free(ctx, &vsi->irq); + que = vsi->rx_queues; + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + iflib_irq_free(ctx, &que->que_irq); + return (err); +} + +/* Enable all interrupts */ +static void +ixlv_if_enable_intr(if_ctx_t ctx) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + + ixlv_enable_intr(vsi); +} + +/* Disable all interrupts */ +static void +ixlv_if_disable_intr(if_ctx_t ctx) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + + ixlv_disable_intr(vsi); +} + +/* Enable queue interrupt */ +static int +ixlv_if_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct i40e_hw *hw = vsi->hw; + struct ixl_rx_queue *que = &vsi->rx_queues[rxqid]; + + ixlv_enable_queue_irq(hw, que->rxr.me); + + return (0); +} + +static int +ixlv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixl_tx_queue *que; + int i; + + MPASS(vsi->num_tx_queues > 0); + MPASS(ntxqs == 1); + MPASS(vsi->num_tx_queues == ntxqsets); + + /* Allocate queue structure memory */ + if (!(vsi->tx_queues = + (struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXLV, M_NOWAIT | M_ZERO))) { + device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n"); + return (ENOMEM); + } + + for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) { + struct tx_ring *txr = &que->txr; + txr->me = i; + que->vsi = vsi; + + /* get the virtual and physical address of the hardware queues */ + txr->tail = I40E_QTX_TAIL1(txr->me); + txr->tx_base = (struct i40e_tx_desc *)vaddrs[i]; + txr->tx_paddr = paddrs[i]; + txr->que = que; + } + + // TODO: Do a config_gtask_init for admin queue here? + // iflib_config_gtask_init(ctx, &adapter->mod_task, ixgbe_handle_mod, "mod_task"); + + device_printf(iflib_get_dev(ctx), "%s: allocated for %d txqs\n", __func__, vsi->num_tx_queues); + return (0); +} + +static int +ixlv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixl_rx_queue *que; + int i; + + MPASS(vsi->num_rx_queues > 0); + MPASS(nrxqs == 1); + MPASS(vsi->num_rx_queues == nrxqsets); + + /* Allocate queue structure memory */ + if (!(vsi->rx_queues = + (struct ixl_rx_queue *) malloc(sizeof(struct ixl_rx_queue) * + nrxqsets, M_IXLV, M_NOWAIT | M_ZERO))) { + device_printf(iflib_get_dev(ctx), "Unable to allocate RX ring memory\n"); + return (ENOMEM); + } + + for (i = 0, que = vsi->rx_queues; i < nrxqsets; i++, que++) { + struct rx_ring *rxr = &que->rxr; + + rxr->me = i; + que->vsi = vsi; + + /* get the virtual and physical address of the hardware queues */ + rxr->tail = I40E_QRX_TAIL1(rxr->me); + rxr->rx_base = (union i40e_rx_desc *)vaddrs[i]; + rxr->rx_paddr = paddrs[i]; + rxr->que = que; + } + + device_printf(iflib_get_dev(ctx), "%s: allocated for %d rxqs\n", __func__, vsi->num_rx_queues); + return (0); +} + +static void +ixlv_if_queues_free(if_ctx_t ctx) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + + if (vsi->tx_queues != NULL) { + free(vsi->tx_queues, M_IXLV); + vsi->tx_queues = NULL; + } + if (vsi->rx_queues != NULL) { + free(vsi->rx_queues, M_IXLV); + vsi->rx_queues = NULL; + } +} + +// TODO: Implement +static void +ixlv_if_update_admin_status(if_ctx_t ctx) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + //struct ixlv_sc *sc = vsi->back; + //struct i40e_hw *hw = &sc->hw; + //struct i40e_arq_event_info event; + //i40e_status ret; + //u32 loop = 0; + //u16 opcode + u16 result = 0; + //u64 baudrate; + + /* TODO: Split up + * - Update admin queue stuff + * - Update link status + * - Enqueue aq task + * - Re-enable admin intr + */ + +/* TODO: Does VF reset need to be handled here? */ +#if 0 + if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { + /* Flag cleared at end of this function */ + ixl_handle_empr_reset(pf); + return; + } +#endif + +#if 0 + event.buf_len = IXL_AQ_BUF_SZ; + event.msg_buf = malloc(event.buf_len, + M_IXLV, M_NOWAIT | M_ZERO); + if (!event.msg_buf) { + device_printf(pf->dev, "%s: Unable to allocate memory for Admin" + " Queue event!\n", __func__); + return; + } + + /* clean and process any events */ + do { + ret = i40e_clean_arq_element(hw, &event, &result); + if (ret) + break; + opcode = LE16_TO_CPU(event.desc.opcode); + ixl_dbg(pf, IXL_DBG_AQ, + "Admin Queue event: %#06x\n", opcode); + switch (opcode) { + case i40e_aqc_opc_get_link_status: + ixl_link_event(pf, &event); + break; + case i40e_aqc_opc_send_msg_to_pf: +#ifdef PCI_IOV + ixl_handle_vf_msg(pf, &event); +#endif + break; + case i40e_aqc_opc_event_lan_overflow: + break; + default: +#ifdef IXL_DEBUG + printf("AdminQ unknown event %x\n", opcode); +#endif + break; + } + + } while (result && (loop++ < IXL_ADM_LIMIT)); + + free(event.msg_buf, M_IXLV); +#endif + +#if 0 + /* XXX: This updates the link status */ + if (pf->link_up) { + if (vsi->link_active == FALSE) { + vsi->link_active = TRUE; + baudrate = ixl_max_aq_speed_to_value(pf->link_speed); + iflib_link_state_change(ctx, LINK_STATE_UP, baudrate); + ixl_link_up_msg(pf); + // ixl_ping_all_vfs(adapter); + } + } else { /* Link down */ + if (vsi->link_active == TRUE) { + vsi->link_active = FALSE; + iflib_link_state_change(ctx, LINK_STATE_DOWN, 0); + // ixl_ping_all_vfs(adapter); + } + } +#endif + + /* + * If there are still messages to process, reschedule ourselves. + * Otherwise, re-enable our interrupt and go to sleep. + */ + if (result > 0) + iflib_admin_intr_deferred(ctx); + else + /* TODO: Link/adminq interrupt should be re-enabled in IFDI_LINK_INTR_ENABLE */ + ixlv_enable_intr(vsi); +} + +static void +ixlv_if_multi_set(if_ctx_t ctx) +{ + // struct ixl_vsi *vsi = iflib_get_softc(ctx); + // struct i40e_hw *hw = vsi->hw; + // struct ixlv_sc *sc = vsi->back; + // int mcnt = 0, flags; + + IOCTL_DEBUGOUT("ixl_if_multi_set: begin"); + + // TODO: Implement +#if 0 + mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR); + /* delete existing MC filters */ + ixlv_del_multi(vsi); + + if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { + // Set promiscuous mode (multicast) + // TODO: This needs to get handled somehow +#if 0 + ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd, + IXLV_FLAG_AQ_CONFIGURE_PROMISC, ixl_init_cmd_complete, sc); +#endif + return; + } + /* (re-)install filters for all mcast addresses */ + mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi); + + if (mcnt > 0) { + flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); + ixlv_add_hw_filters(vsi, flags, mcnt); + } +#endif + + IOCTL_DEBUGOUT("ixl_if_multi_set: end"); +} + +static void +ixlv_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixlv_sc *sc = (struct ixlv_sc *)vsi->back; + struct i40e_hw *hw = &sc->hw; + + INIT_DEBUGOUT("ixl_media_status: begin"); + + hw->phy.get_link_info = TRUE; + i40e_get_link_status(hw, &sc->link_up); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!sc->link_up) { + return; + } + + ifmr->ifm_status |= IFM_ACTIVE; + /* Hardware is always full-duplex */ + ifmr->ifm_active |= IFM_FDX; + + // TODO: Check another variable to get link speed +#if 0 + switch (hw->phy.link_info.phy_type) { + /* 100 M */ + case I40E_PHY_TYPE_100BASE_TX: + ifmr->ifm_active |= IFM_100_TX; + break; + /* 1 G */ + case I40E_PHY_TYPE_1000BASE_T: + ifmr->ifm_active |= IFM_1000_T; + break; + case I40E_PHY_TYPE_1000BASE_SX: + ifmr->ifm_active |= IFM_1000_SX; + break; + case I40E_PHY_TYPE_1000BASE_LX: + ifmr->ifm_active |= IFM_1000_LX; + break; + case I40E_PHY_TYPE_1000BASE_T_OPTICAL: + ifmr->ifm_active |= IFM_OTHER; + break; + /* 10 G */ + case I40E_PHY_TYPE_10GBASE_SFPP_CU: + ifmr->ifm_active |= IFM_10G_TWINAX; + break; + case I40E_PHY_TYPE_10GBASE_SR: + ifmr->ifm_active |= IFM_10G_SR; + break; + case I40E_PHY_TYPE_10GBASE_LR: + ifmr->ifm_active |= IFM_10G_LR; + break; + case I40E_PHY_TYPE_10GBASE_T: + ifmr->ifm_active |= IFM_10G_T; + break; + case I40E_PHY_TYPE_XAUI: + case I40E_PHY_TYPE_XFI: + case I40E_PHY_TYPE_10GBASE_AOC: + ifmr->ifm_active |= IFM_OTHER; + break; + /* 25 G */ + case I40E_PHY_TYPE_25GBASE_KR: + ifmr->ifm_active |= IFM_25G_KR; + break; + case I40E_PHY_TYPE_25GBASE_CR: + ifmr->ifm_active |= IFM_25G_CR; + break; + case I40E_PHY_TYPE_25GBASE_SR: + ifmr->ifm_active |= IFM_25G_SR; + break; + case I40E_PHY_TYPE_25GBASE_LR: + ifmr->ifm_active |= IFM_UNKNOWN; + break; + /* 40 G */ + case I40E_PHY_TYPE_40GBASE_CR4: + case I40E_PHY_TYPE_40GBASE_CR4_CU: + ifmr->ifm_active |= IFM_40G_CR4; + break; + case I40E_PHY_TYPE_40GBASE_SR4: + ifmr->ifm_active |= IFM_40G_SR4; + break; + case I40E_PHY_TYPE_40GBASE_LR4: + ifmr->ifm_active |= IFM_40G_LR4; + break; + case I40E_PHY_TYPE_XLAUI: + ifmr->ifm_active |= IFM_OTHER; + break; + case I40E_PHY_TYPE_1000BASE_KX: + ifmr->ifm_active |= IFM_1000_KX; + break; + case I40E_PHY_TYPE_SGMII: + ifmr->ifm_active |= IFM_1000_SGMII; + break; + /* ERJ: What's the difference between these? */ + case I40E_PHY_TYPE_10GBASE_CR1_CU: + case I40E_PHY_TYPE_10GBASE_CR1: + ifmr->ifm_active |= IFM_10G_CR1; + break; + case I40E_PHY_TYPE_10GBASE_KX4: + ifmr->ifm_active |= IFM_10G_KX4; + break; + case I40E_PHY_TYPE_10GBASE_KR: + ifmr->ifm_active |= IFM_10G_KR; + break; + case I40E_PHY_TYPE_SFI: + ifmr->ifm_active |= IFM_10G_SFI; + break; + /* Our single 20G media type */ + case I40E_PHY_TYPE_20GBASE_KR2: + ifmr->ifm_active |= IFM_20G_KR2; + break; + case I40E_PHY_TYPE_40GBASE_KR4: + ifmr->ifm_active |= IFM_40G_KR4; + break; + case I40E_PHY_TYPE_XLPPI: + case I40E_PHY_TYPE_40GBASE_AOC: + ifmr->ifm_active |= IFM_40G_XLPPI; + break; + /* Unknown to driver */ + default: + ifmr->ifm_active |= IFM_UNKNOWN; + break; + } + /* Report flow control status as well */ + if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) + ifmr->ifm_active |= IFM_ETH_TXPAUSE; + if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) + ifmr->ifm_active |= IFM_ETH_RXPAUSE; + #endif +} + +static int +ixlv_if_media_change(if_ctx_t ctx) +{ + struct ifmedia *ifm = iflib_get_media(ctx); + + INIT_DEBUGOUT("ixl_media_change: begin"); + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + if_printf(iflib_get_ifp(ctx), "Media change is not supported.\n"); + return (ENODEV); +} + +// TODO: Rework +static int +ixlv_if_promisc_set(if_ctx_t ctx, int flags) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ifnet *ifp = iflib_get_ifp(ctx); + struct i40e_hw *hw = vsi->hw; + int err; + bool uni = FALSE, multi = FALSE; + + if (flags & IFF_ALLMULTI || + if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR) + multi = TRUE; + if (flags & IFF_PROMISC) + uni = TRUE; + + err = i40e_aq_set_vsi_unicast_promiscuous(hw, + vsi->seid, uni, NULL, false); + if (err) + return (err); + err = i40e_aq_set_vsi_multicast_promiscuous(hw, + vsi->seid, multi, NULL); + return (err); +} + +static void +ixlv_if_timer(if_ctx_t ctx, uint16_t qid) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + struct ixlv_sc *sc = vsi->back; + //struct i40e_hw *hw = &sc->hw; + //struct ixl_tx_queue *que = &vsi->tx_queues[qid]; + //u32 mask; + +#if 0 + /* + ** Check status of the queues + */ + mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); + + /* If queue param has outstanding work, trigger sw irq */ + // TODO: TX queues in iflib don't use HW interrupts; does this do anything? + if (que->busy) + wr32(hw, I40E_PFINT_DYN_CTLN(que->txr.me), mask); + #endif + + // XXX: Is this timer per-queue? + if (qid != 0) + return; + + /* Fire off the adminq task */ + iflib_admin_intr_deferred(ctx); + + /* Update stats */ + ixlv_request_stats(sc); +} + +static void +ixlv_if_vlan_register(if_ctx_t ctx, u16 vtag) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + //struct i40e_hw *hw = vsi->hw; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + ++vsi->num_vlans; + // TODO: Redo + // ixlv_add_filter(vsi, hw->mac.addr, vtag); +} + +static void +ixlv_if_vlan_unregister(if_ctx_t ctx, u16 vtag) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + //struct i40e_hw *hw = vsi->hw; + + if ((vtag == 0) || (vtag > 4095)) /* Invalid */ + return; + + --vsi->num_vlans; + // TODO: Redo + // ixlv_del_filter(vsi, hw->mac.addr, vtag); +} + +static uint64_t +ixlv_if_get_counter(if_ctx_t ctx, ift_counter cnt) +{ + struct ixl_vsi *vsi = iflib_get_softc(ctx); + if_t ifp = iflib_get_ifp(ctx); + + switch (cnt) { + case IFCOUNTER_IPACKETS: + return (vsi->ipackets); + case IFCOUNTER_IERRORS: + return (vsi->ierrors); + case IFCOUNTER_OPACKETS: + return (vsi->opackets); + case IFCOUNTER_OERRORS: + return (vsi->oerrors); + case IFCOUNTER_COLLISIONS: + /* Collisions are by standard impossible in 40G/10G Ethernet */ + return (0); + case IFCOUNTER_IBYTES: + return (vsi->ibytes); + case IFCOUNTER_OBYTES: + return (vsi->obytes); + case IFCOUNTER_IMCASTS: + return (vsi->imcasts); + case IFCOUNTER_OMCASTS: + return (vsi->omcasts); + case IFCOUNTER_IQDROPS: + return (vsi->iqdrops); + case IFCOUNTER_OQDROPS: + return (vsi->oqdrops); + case IFCOUNTER_NOPROTO: + return (vsi->noproto); + default: + return (if_get_counter_default(ifp, cnt)); + } } static int ixlv_allocate_pci_resources(struct ixlv_sc *sc) { + struct i40e_hw *hw = &sc->hw; + device_t dev = iflib_get_dev(sc->vsi.ctx); int rid; - device_t dev = sc->dev; + /* Map BAR0 */ rid = PCIR_BAR(0); sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!(sc->pci_mem)) { - device_printf(dev, "Unable to allocate bus resource: memory\n"); + device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); return (ENXIO); - } + } + + /* Save off the PCI information */ + hw->vendor_id = pci_get_vendor(dev); + hw->device_id = pci_get_device(dev); + hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); + hw->subsystem_vendor_id = + pci_read_config(dev, PCIR_SUBVEND_0, 2); + hw->subsystem_device_id = + pci_read_config(dev, PCIR_SUBDEV_0, 2); + hw->bus.device = pci_get_slot(dev); + hw->bus.func = pci_get_function(dev); + + /* Save off register access information */ sc->osdep.mem_bus_space_tag = rman_get_bustag(sc->pci_mem); sc->osdep.mem_bus_space_handle = rman_get_bushandle(sc->pci_mem); sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem); sc->osdep.flush_reg = I40E_VFGEN_RSTAT; + sc->osdep.dev = dev; + sc->hw.hw_addr = (u8 *) &sc->osdep.mem_bus_space_handle; sc->hw.back = &sc->osdep; - ixl_set_busmaster(dev); - ixl_set_msix_enable(dev); - /* Disable adminq interrupts (just in case) */ - ixlv_disable_adminq_irq(&sc->hw); - - return (0); -} - -/* - * Free MSI-X related resources for a single queue - */ -static void -ixlv_free_msix_resources(struct ixlv_sc *sc, struct ixl_queue *que) -{ - device_t dev = sc->dev; - - /* - ** Release all msix queue resources: - */ - if (que->tag != NULL) { - bus_teardown_intr(dev, que->res, que->tag); - que->tag = NULL; - } - if (que->res != NULL) { - int rid = que->msix + 1; - bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); - que->res = NULL; - } - if (que->tq != NULL) { - taskqueue_free(que->tq); - que->tq = NULL; - } -} + /* TODO: Probably not necessary */ + // ixlv_disable_adminq_irq(&sc->hw); + return (0); + } + static void ixlv_free_pci_resources(struct ixlv_sc *sc) { + struct ixl_vsi *vsi = &sc->vsi; + struct ixl_rx_queue *rx_que = vsi->rx_queues; device_t dev = sc->dev; - pci_release_msi(dev); + /* We may get here before stations are setup */ + // TODO: Check if we can still check against sc->msix + if ((sc->msix > 0) || (rx_que == NULL)) + goto early; - if (sc->msix_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - PCIR_BAR(IXL_MSIX_BAR), sc->msix_mem); + /* + ** Release all msix VSI resources: + */ + iflib_irq_free(vsi->ctx, &vsi->irq); + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) + iflib_irq_free(vsi->ctx, &rx_que->que_irq); + +early: if (sc->pci_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->pci_mem); } -/* - * Create taskqueue and tasklet for Admin Queue interrupts. - */ -static int -ixlv_init_taskqueue(struct ixlv_sc *sc) -{ - int error = 0; - - TASK_INIT(&sc->aq_irq, 0, ixlv_do_adminq, sc); - - sc->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, - taskqueue_thread_enqueue, &sc->tq); - taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s sc->tq", - device_get_nameunit(sc->dev)); - - return (error); -} - -/********************************************************************* - * - * Setup MSIX Interrupt resources and handlers for the VSI queues - * - **********************************************************************/ -static int -ixlv_assign_msix(struct ixlv_sc *sc) -{ - device_t dev = sc->dev; - struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; - struct tx_ring *txr; - int error, rid, vector = 1; -#ifdef RSS - cpuset_t cpu_mask; -#endif - - for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { - int cpu_id = i; - rid = vector + 1; - txr = &que->txr; - que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (que->res == NULL) { - device_printf(dev,"Unable to allocate" - " bus resource: que interrupt [%d]\n", vector); - return (ENXIO); - } - /* Set the handler function */ - error = bus_setup_intr(dev, que->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixlv_msix_que, que, &que->tag); - if (error) { - que->tag = NULL; - device_printf(dev, "Failed to register que handler"); - return (error); - } - bus_describe_intr(dev, que->res, que->tag, "que %d", i); - /* Bind the vector to a CPU */ -#ifdef RSS - cpu_id = rss_getcpu(i % rss_getnumbuckets()); -#endif - bus_bind_intr(dev, que->res, cpu_id); - que->msix = vector; - TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); - TASK_INIT(&que->task, 0, ixlv_handle_que, que); - que->tq = taskqueue_create_fast("ixlv_que", M_NOWAIT, - taskqueue_thread_enqueue, &que->tq); -#ifdef RSS - CPU_SETOF(cpu_id, &cpu_mask); - taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, - &cpu_mask, "%s (bucket %d)", - device_get_nameunit(dev), cpu_id); -#else - taskqueue_start_threads(&que->tq, 1, PI_NET, - "%s que", device_get_nameunit(dev)); -#endif - - } - - return (0); -} /* ** Requests a VF reset from the PF. @@ -1552,76 +1830,31 @@ return (EBUSY); } - -/********************************************************************* - * - * Setup networking device structure and register an interface. - * - **********************************************************************/ -static int -ixlv_setup_interface(device_t dev, struct ixlv_sc *sc) +static void +ixlv_setup_interface(device_t dev, struct ixl_vsi *vsi) { - struct ifnet *ifp; - struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; + if_ctx_t ctx = vsi->ctx; + struct ixlv_sc *sc = vsi->back; + struct ifnet *ifp = iflib_get_ifp(ctx); + uint64_t cap; + //struct ixl_queue *que = vsi->queues; INIT_DBG_DEV(dev, "begin"); - ifp = vsi->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - device_printf(dev, "%s: could not allocate ifnet" - " structure!\n", __func__); - return (-1); - } - - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - - ifp->if_mtu = ETHERMTU; + /* initialize fast path functions */ + cap = IXL_CAPS; + if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); + if_setcapabilitiesbit(ifp, cap, 0); + if_setcapenable(ifp, if_getcapabilities(ifp)); + /* TODO: Remove VLAN_ENCAP_LEN? */ + vsi->shared->isc_max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + + ETHER_VLAN_ENCAP_LEN; #if __FreeBSD_version >= 1100000 - ifp->if_baudrate = IF_Gbps(40); + if_setbaudrate(ifp, IF_Gbps(40)); #else if_initbaudrate(ifp, IF_Gbps(40)); #endif - ifp->if_init = ixlv_init; - ifp->if_softc = vsi; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ixlv_ioctl; - -#if __FreeBSD_version >= 1100000 - if_setgetcounterfn(ifp, ixl_get_counter); -#endif - - ifp->if_transmit = ixl_mq_start; - - ifp->if_qflush = ixl_qflush; - ifp->if_snd.ifq_maxlen = que->num_tx_desc - 2; - - ether_ifattach(ifp, sc->hw.mac.addr); - - vsi->max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN - + ETHER_VLAN_ENCAP_LEN; - - ifp->if_hw_tsomax = IP_MAXPACKET - (ETHER_HDR_LEN + ETHER_CRC_LEN); - ifp->if_hw_tsomaxsegcount = IXL_MAX_TSO_SEGS; - ifp->if_hw_tsomaxsegsize = IXL_MAX_DMA_SEG_SIZE; - - /* - * Tell the upper layer(s) we support long frames. - */ - ifp->if_hdrlen = sizeof(struct ether_vlan_header); - - ifp->if_capabilities |= IFCAP_HWCSUM; - ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; - ifp->if_capabilities |= IFCAP_TSO; - ifp->if_capabilities |= IFCAP_JUMBO_MTU; - - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING - | IFCAP_VLAN_HWTSO - | IFCAP_VLAN_MTU - | IFCAP_VLAN_HWCSUM - | IFCAP_LRO; - ifp->if_capenable = ifp->if_capabilities; /* ** Don't turn this on by default, if vlans are @@ -1631,14 +1864,7 @@ ** using vlans directly on the ixl driver you can ** enable this and get full hardware tag filtering. */ - ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; - - /* - * Specify the media types supported by this adapter and register - * callbacks to update media and link information - */ - ifmedia_init(&sc->media, IFM_IMASK, ixlv_media_change, - ixlv_media_status); + if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWFILTER, 0); /* Media types based on reported link speed over AdminQ */ ifmedia_add(&sc->media, IFM_ETHER | IFM_100_TX, 0, NULL); @@ -1653,6 +1879,7 @@ INIT_DBG_DEV(dev, "end"); return (0); } +#if 0 /* ** Allocate and setup a single queue @@ -1763,6 +1990,7 @@ return (error); } +#endif /* ** Allocate and setup the interface queues @@ -1813,6 +2041,7 @@ return (error); } +#if 0 /* ** This routine is run via an vlan config EVENT, ** it enables us to use the HW Filter table since @@ -1885,6 +2114,7 @@ mtx_unlock(&sc->mtx); return; } +#endif /* ** Get a new filter and add it to the mac filter list. @@ -1923,44 +2153,19 @@ return (f); } -static int -ixlv_teardown_adminq_msix(struct ixlv_sc *sc) -{ - device_t dev = sc->dev; - int error = 0; - - if (sc->tag != NULL) { - bus_teardown_intr(dev, sc->res, sc->tag); - if (error) { - device_printf(dev, "bus_teardown_intr() for" - " interrupt 0 failed\n"); - // return (ENXIO); - } - sc->tag = NULL; - } - if (sc->res != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, 1, sc->res); - if (error) { - device_printf(dev, "bus_release_resource() for" - " interrupt 0 failed\n"); - // return (ENXIO); - } - sc->res = NULL; - } - - return (0); - -} - /* ** Admin Queue interrupt handler */ -static void +static int ixlv_msix_adminq(void *arg) { struct ixlv_sc *sc = arg; struct i40e_hw *hw = &sc->hw; - u32 reg, mask; + // device_t dev = sc->dev; + u32 reg; + bool do_task = FALSE; + + ++sc->admin_irq; reg = rd32(hw, I40E_VFINT_ICR01); mask = rd32(hw, I40E_VFINT_ICR0_ENA1); @@ -1969,34 +2174,40 @@ reg |= I40E_VFINT_DYN_CTL01_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, reg); - /* schedule task */ - taskqueue_enqueue(sc->tq, &sc->aq_irq); - return; + /* Check on the cause */ + if (reg & I40E_VFINT_ICR0_ADMINQ_MASK) + do_task = TRUE; + + if (do_task) + iflib_admin_intr_deferred(sc->vsi.ctx); + else + ixlv_enable_adminq_irq(hw); + + return (FILTER_HANDLED); } void ixlv_enable_intr(struct ixl_vsi *vsi) { struct i40e_hw *hw = vsi->hw; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *que = vsi->rx_queues; ixlv_enable_adminq_irq(hw); - for (int i = 0; i < vsi->num_queues; i++, que++) - ixlv_enable_queue_irq(hw, que->me); + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + ixlv_enable_queue_irq(hw, que->rxr.me); } void ixlv_disable_intr(struct ixl_vsi *vsi) { struct i40e_hw *hw = vsi->hw; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *que = vsi->rx_queues; ixlv_disable_adminq_irq(hw); - for (int i = 0; i < vsi->num_queues; i++, que++) - ixlv_disable_queue_irq(hw, que->me); + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + ixlv_disable_queue_irq(hw, que->rxr.me); } - static void ixlv_disable_adminq_irq(struct i40e_hw *hw) { @@ -2004,7 +2215,6 @@ wr32(hw, I40E_VFINT_ICR0_ENA1, 0); /* flush */ rd32(hw, I40E_VFGEN_RSTAT); - return; } static void @@ -2016,7 +2226,6 @@ wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK); /* flush */ rd32(hw, I40E_VFGEN_RSTAT); - return; } static void @@ -2047,24 +2256,26 @@ { struct i40e_hw *hw = &sc->hw; struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *rx_que = vsi->rx_queues; vsi->rx_itr_setting = ixlv_rx_itr; - vsi->tx_itr_setting = ixlv_tx_itr; + //vsi->tx_itr_setting = ixlv_tx_itr; - for (int i = 0; i < vsi->num_queues; i++, que++) { - struct tx_ring *txr = &que->txr; - struct rx_ring *rxr = &que->rxr; + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) { + struct rx_ring *rxr = &rx_que->rxr; wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, i), vsi->rx_itr_setting); rxr->itr = vsi->rx_itr_setting; rxr->latency = IXL_AVE_LATENCY; +#if 0 + struct tx_ring *txr = &que->txr; wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, i), vsi->tx_itr_setting); txr->itr = vsi->tx_itr_setting; txr->latency = IXL_AVE_LATENCY; +#endif } } @@ -2073,7 +2284,7 @@ ** interrupt moderation value. */ static void -ixlv_set_queue_rx_itr(struct ixl_queue *que) +ixlv_set_queue_rx_itr(struct ixl_rx_queue *que) { struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; @@ -2124,7 +2335,7 @@ ((9 * rx_itr) + rxr->itr); rxr->itr = min(rx_itr, IXL_MAX_ITR); wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, - que->me), rxr->itr); + que->rxr.me), rxr->itr); } } else { /* We may have have toggled to non-dynamic */ if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) @@ -2133,7 +2344,7 @@ if (rxr->itr != vsi->rx_itr_setting) { rxr->itr = vsi->rx_itr_setting; wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, - que->me), rxr->itr); + que->rxr.me), rxr->itr); } } rxr->bytes = 0; @@ -2147,7 +2358,7 @@ ** interrupt moderation value. */ static void -ixlv_set_queue_tx_itr(struct ixl_queue *que) +ixlv_set_queue_tx_itr(struct ixl_tx_queue *que) { struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; @@ -2197,7 +2408,7 @@ ((9 * tx_itr) + txr->itr); txr->itr = min(tx_itr, IXL_MAX_ITR); wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, - que->me), txr->itr); + que->txr.me), txr->itr); } } else { /* We may have have toggled to non-dynamic */ @@ -2207,7 +2418,7 @@ if (txr->itr != vsi->tx_itr_setting) { txr->itr = vsi->tx_itr_setting; wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, - que->me), txr->itr); + que->txr.me), txr->itr); } } txr->bytes = 0; @@ -2215,7 +2426,7 @@ return; } - +#if 0 /* ** ** MSIX Interrupt Handlers and Tasklets @@ -2248,50 +2459,20 @@ ixlv_enable_queue_irq(hw, que->me); return; } +#endif -/********************************************************************* - * - * MSIX Queue Interrupt Service routine - * - **********************************************************************/ -static void +static int ixlv_msix_que(void *arg) { - struct ixl_queue *que = arg; - struct ixl_vsi *vsi = que->vsi; - struct i40e_hw *hw = vsi->hw; - struct tx_ring *txr = &que->txr; - bool more_tx, more_rx; - - /* Spurious interrupts are ignored */ - if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) - return; + struct ixl_rx_queue *que = arg; ++que->irqs; - more_rx = ixl_rxeof(que, IXL_RX_LIMIT); - - mtx_lock(&txr->mtx); - more_tx = ixl_txeof(que); - /* - ** Make certain that if the stack - ** has anything queued the task gets - ** scheduled to handle it. - */ - if (!drbr_empty(vsi->ifp, txr->br)) - more_tx = 1; - mtx_unlock(&txr->mtx); - ixlv_set_queue_rx_itr(que); ixlv_set_queue_tx_itr(que); - if (more_tx || more_rx) - taskqueue_enqueue(que->tq, &que->task); - else - ixlv_enable_queue_irq(hw, que->me); - - return; + return (FILTER_SCHEDULE_THREAD); } @@ -2386,6 +2567,7 @@ } +#if 0 /********************************************************************* * Multicast Initialization * @@ -2526,14 +2708,6 @@ IOCTL_DBG_IF(ifp, "end"); } -/********************************************************************* - * Timer routine - * - * This routine checks for link status,updates statistics, - * and runs the watchdog check. - * - **********************************************************************/ - static void ixlv_local_timer(void *arg) { @@ -2600,6 +2774,7 @@ return; } +#endif /********************************************************************* * @@ -2617,8 +2792,6 @@ ifp = sc->vsi.ifp; INIT_DBG_IF(ifp, "begin"); - IXLV_CORE_LOCK_ASSERT(sc); - ixl_vc_flush(&sc->vc_mgr); ixlv_disable_queues(sc); @@ -2633,53 +2806,12 @@ INIT_DBG_IF(ifp, "end"); } -/* Free a single queue struct */ static void -ixlv_free_queue(struct ixlv_sc *sc, struct ixl_queue *que) +ixlv_if_stop(if_ctx_t ctx) { - struct tx_ring *txr = &que->txr; - struct rx_ring *rxr = &que->rxr; + struct ixl_vsi *vsi = iflib_get_softc(ctx); - if (!mtx_initialized(&txr->mtx)) /* uninitialized */ - return; - IXL_TX_LOCK(txr); - if (txr->br) - buf_ring_free(txr->br, M_DEVBUF); - ixl_free_que_tx(que); - if (txr->base) - i40e_free_dma_mem(&sc->hw, &txr->dma); - IXL_TX_UNLOCK(txr); - IXL_TX_LOCK_DESTROY(txr); - - if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ - return; - IXL_RX_LOCK(rxr); - ixl_free_que_rx(que); - if (rxr->base) - i40e_free_dma_mem(&sc->hw, &rxr->dma); - IXL_RX_UNLOCK(rxr); - IXL_RX_LOCK_DESTROY(rxr); -} - -/********************************************************************* - * - * Free all station queue structs. - * - **********************************************************************/ -static void -ixlv_free_queues(struct ixl_vsi *vsi) -{ - struct ixlv_sc *sc = (struct ixlv_sc *)vsi->back; - struct ixl_queue *que = vsi->queues; - - for (int i = 0; i < vsi->num_queues; i++, que++) { - /* First, free the MSI-X resources */ - ixlv_free_msix_resources(sc, que); - /* Then free other queue data */ - ixlv_free_queue(sc, que); - } - - free(vsi->queues, M_DEVBUF); + ixlv_stop(sc); } static void @@ -2696,7 +2828,7 @@ #endif /* Don't set up RSS if using a single queue */ - if (vsi->num_queues == 1) { + if (vsi->num_rx_queues == 1) { wr32(hw, I40E_VFQF_HENA(0), 0); wr32(hw, I40E_VFQF_HENA(1), 0); ixl_flush(hw); @@ -2742,7 +2874,7 @@ /* Populate the LUT with max no. of queues in round robin fashion */ for (i = 0, j = 0; i < IXL_RSS_VSI_LUT_SIZE; i++, j++) { - if (j == vsi->num_queues) + if (j == vsi->num_rx_queues) j = 0; #ifdef RSS /* @@ -2874,21 +3006,6 @@ return (0); } -/* -** Tasklet handler for MSIX Adminq interrupts -** - done outside interrupt context since it might sleep -*/ -static void -ixlv_do_adminq(void *context, int pending) -{ - struct ixlv_sc *sc = context; - - mtx_lock(&sc->mtx); - ixlv_do_adminq_locked(sc); - mtx_unlock(&sc->mtx); - return; -} - static void ixlv_do_adminq_locked(struct ixlv_sc *sc) { @@ -2901,8 +3018,6 @@ i40e_status ret; bool aq_error = false; - IXLV_CORE_LOCK_ASSERT(sc); - event.buf_len = IXL_AQ_BUF_SZ; event.msg_buf = sc->aq_buffer; v_msg = (struct virtchnl_msg *)&event.desc; @@ -2961,7 +3076,8 @@ device_printf(dev, "WARNING: Resetting!\n"); sc->init_state = IXLV_RESET_REQUIRED; ixlv_stop(sc); - ixlv_init_locked(sc); + // TODO: Make stop/init calls match + ixlv_if_init(sc->vsi.ctx); } ixlv_enable_adminq_irq(hw); } @@ -2977,15 +3093,17 @@ struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); - struct sysctl_oid *vsi_node, *queue_node; - struct sysctl_oid_list *vsi_list, *queue_list; + struct sysctl_oid *vsi_node; // *queue_node; + struct sysctl_oid_list *vsi_list; // *queue_list; #define QUEUE_NAME_LEN 32 - char queue_namebuf[QUEUE_NAME_LEN]; + //char queue_namebuf[QUEUE_NAME_LEN]; +#if 0 struct ixl_queue *queues = vsi->queues; - struct tx_ring *txr; + struct tX_ring *txr; struct rx_ring *rxr; +#endif /* Driver statistics sysctls */ SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events", @@ -3042,6 +3160,7 @@ entry++; } +#if 0 /* Queue sysctls */ for (int q = 0; q < vsi->num_queues; q++) { snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); @@ -3106,6 +3225,7 @@ "Ticks before watchdog event is triggered"); #endif } +#endif } static void @@ -3117,7 +3237,6 @@ sc->vlan_filters = malloc(sizeof(struct ixlv_vlan_filter), M_DEVBUF, M_NOWAIT | M_ZERO); SLIST_INIT(sc->vlan_filters); - return; } static void @@ -3138,7 +3257,6 @@ free(v, M_DEVBUF); } free(sc->vlan_filters, M_DEVBUF); - return; } static char * Index: sys/dev/ixl/ixl.h =================================================================== --- sys/dev/ixl/ixl.h +++ sys/dev/ixl/ixl.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -102,80 +103,13 @@ #include #endif +#include "ifdi_if.h" #include "i40e_type.h" #include "i40e_prototype.h" +#include "ixl_debug.h" -#define MAC_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_FORMAT_ARGS(mac_addr) \ - (mac_addr)[0], (mac_addr)[1], (mac_addr)[2], (mac_addr)[3], \ - (mac_addr)[4], (mac_addr)[5] -#define ON_OFF_STR(is_set) ((is_set) ? "On" : "Off") - -#ifdef IXL_DEBUG - -#define _DBG_PRINTF(S, ...) printf("%s: " S "\n", __func__, ##__VA_ARGS__) -#define _DEV_DBG_PRINTF(dev, S, ...) device_printf(dev, "%s: " S "\n", __func__, ##__VA_ARGS__) -#define _IF_DBG_PRINTF(ifp, S, ...) if_printf(ifp, "%s: " S "\n", __func__, ##__VA_ARGS__) - -/* Defines for printing generic debug information */ -#define DPRINTF(...) _DBG_PRINTF(__VA_ARGS__) -#define DDPRINTF(...) _DEV_DBG_PRINTF(__VA_ARGS__) -#define IDPRINTF(...) _IF_DBG_PRINTF(__VA_ARGS__) - -/* Defines for printing specific debug information */ -#define DEBUG_INIT 1 -#define DEBUG_IOCTL 1 -#define DEBUG_HW 1 - -#define INIT_DEBUGOUT(...) if (DEBUG_INIT) _DBG_PRINTF(__VA_ARGS__) -#define INIT_DBG_DEV(...) if (DEBUG_INIT) _DEV_DBG_PRINTF(__VA_ARGS__) -#define INIT_DBG_IF(...) if (DEBUG_INIT) _IF_DBG_PRINTF(__VA_ARGS__) - -#define IOCTL_DEBUGOUT(...) if (DEBUG_IOCTL) _DBG_PRINTF(__VA_ARGS__) -#define IOCTL_DBG_IF2(ifp, S, ...) if (DEBUG_IOCTL) \ - if_printf(ifp, S "\n", ##__VA_ARGS__) -#define IOCTL_DBG_IF(...) if (DEBUG_IOCTL) _IF_DBG_PRINTF(__VA_ARGS__) - -#define HW_DEBUGOUT(...) if (DEBUG_HW) _DBG_PRINTF(__VA_ARGS__) - -#else /* no IXL_DEBUG */ -#define DEBUG_INIT 0 -#define DEBUG_IOCTL 0 -#define DEBUG_HW 0 - -#define DPRINTF(...) -#define DDPRINTF(...) -#define IDPRINTF(...) - -#define INIT_DEBUGOUT(...) -#define INIT_DBG_DEV(...) -#define INIT_DBG_IF(...) -#define IOCTL_DEBUGOUT(...) -#define IOCTL_DBG_IF2(...) -#define IOCTL_DBG_IF(...) -#define HW_DEBUGOUT(...) -#endif /* IXL_DEBUG */ - -enum ixl_dbg_mask { - IXL_DBG_INFO = 0x00000001, - IXL_DBG_EN_DIS = 0x00000002, - IXL_DBG_AQ = 0x00000004, - IXL_DBG_NVMUPD = 0x00000008, - - IXL_DBG_IOCTL_KNOWN = 0x00000010, - IXL_DBG_IOCTL_UNKNOWN = 0x00000020, - IXL_DBG_IOCTL_ALL = 0x00000030, - - I40E_DEBUG_RSS = 0x00000100, - - IXL_DBG_IOV = 0x00001000, - IXL_DBG_IOV_VC = 0x00002000, - - IXL_DBG_SWITCH_INFO = 0x00010000, - IXL_DBG_I2C = 0x00020000, - - IXL_DBG_ALL = 0xFFFFFFFF -}; +#define PVIDV(vendor, devid, name) \ + PVID(vendor, devid, name " - " IXL_DRIVER_VERSION_STRING) /* Tunables */ @@ -195,48 +129,27 @@ #define IXL_AQ_LEN 256 #define IXL_AQ_LEN_MAX 1024 -/* -** Default number of entries in Tx queue buf_ring. -*/ -#define DEFAULT_TXBRSZ 4096 - /* Alignment for rings */ #define DBA_ALIGN 128 -/* - * This is the max watchdog interval, ie. the time that can - * pass between any two TX clean operations, such only happening - * when the TX hardware is functioning. - * - * XXX: Watchdog currently counts down in units of (hz) - * Set this to just (hz) if you want queues to hang under a little bit of stress - */ -#define IXL_WATCHDOG (10 * hz) - -/* - * This parameters control when the driver calls the routine to reclaim - * transmit descriptors. - */ -#define IXL_TX_CLEANUP_THRESHOLD (que->num_tx_desc / 8) -#define IXL_TX_OP_THRESHOLD (que->num_tx_desc / 32) - #define MAX_MULTICAST_ADDR 128 #define IXL_MSIX_BAR 3 #define IXL_ADM_LIMIT 2 -#define IXL_TSO_SIZE 65535 +// TODO: Find out which TSO_SIZE to use +//#define IXL_TSO_SIZE 65535 +#define IXL_TSO_SIZE ((255*1024)-1) +#define IXL_TX_BUF_SZ ((u32) 1514) #define IXL_AQ_BUF_SZ ((u32) 4096) -#define IXL_RX_HDR 128 -#define IXL_RX_LIMIT 512 #define IXL_RX_ITR 0 #define IXL_TX_ITR 1 #define IXL_ITR_NONE 3 #define IXL_QUEUE_EOL 0x7FF #define IXL_MAX_FRAME 9728 #define IXL_MAX_TX_SEGS 8 +#define IXL_MAX_RX_SEGS 5 #define IXL_MAX_TSO_SEGS 128 #define IXL_SPARSE_CHAIN 7 -#define IXL_QUEUE_HUNG 0x80000000 #define IXL_MIN_TSO_MSS 64 #define IXL_MAX_DMA_SEG_SIZE ((16 * 1024) - 1) @@ -252,7 +165,6 @@ /* ERJ: hardware can support ~2k (SW5+) filters between all functions */ #define IXL_MAX_FILTERS 256 -#define IXL_MAX_TX_BUSY 10 #define IXL_NVM_VERSION_LO_SHIFT 0 #define IXL_NVM_VERSION_LO_MASK (0xff << IXL_NVM_VERSION_LO_SHIFT) @@ -288,12 +200,6 @@ #define CSUM_OFFLOAD_IPV6 (CSUM_TCP_IPV6|CSUM_UDP_IPV6|CSUM_SCTP_IPV6) #define CSUM_OFFLOAD (CSUM_OFFLOAD_IPV4|CSUM_OFFLOAD_IPV6|CSUM_TSO) -/* Misc flags for ixl_vsi.flags */ -#define IXL_FLAGS_KEEP_TSO4 (1 << 0) -#define IXL_FLAGS_KEEP_TSO6 (1 << 1) -#define IXL_FLAGS_USES_MSIX (1 << 2) -#define IXL_FLAGS_IS_VF (1 << 3) - #define IXL_VF_RESET_TIMEOUT 100 #define IXL_VSI_DATA_PORT 0x01 @@ -304,6 +210,7 @@ #define IXL_RX_CTX_BASE_UNITS 128 #define IXL_TX_CTX_BASE_UNITS 128 +#if 0 #define IXL_VPINT_LNKLSTN_REG(hw, vector, vf_num) \ I40E_VPINT_LNKLSTN(((vector) - 1) + \ (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num))) @@ -311,6 +218,7 @@ #define IXL_VFINT_DYN_CTLN_REG(hw, vector, vf_num) \ I40E_VFINT_DYN_CTLN(((vector) - 1) + \ (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num))) +#endif #define IXL_PF_PCI_CIAA_VF_DEVICE_STATUS 0xAA @@ -347,15 +255,20 @@ BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK)) -#define IXL_TX_LOCK(_sc) mtx_lock(&(_sc)->mtx) -#define IXL_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) -#define IXL_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) -#define IXL_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->mtx) -#define IXL_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) +#define IXL_CAPS \ + (IFCAP_TSO4 | IFCAP_TSO6 | \ + IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6 | \ + IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | \ + IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO | \ + IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO | \ + IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU | IFCAP_LRO) -#define IXL_RX_LOCK(_sc) mtx_lock(&(_sc)->mtx) -#define IXL_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) -#define IXL_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) +#define IXL_CSUM_TCP \ + (CSUM_IP_TCP|CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP6_TCP) +#define IXL_CSUM_UDP \ + (CSUM_IP_UDP|CSUM_IP6_UDP) +#define IXL_CSUM_SCTP \ + (CSUM_IP_SCTP|CSUM_IP6_SCTP) /* Pre-11 counter(9) compatibility */ #if __FreeBSD_version >= 1100036 @@ -386,6 +299,9 @@ #define IXL_SET_NOPROTO(vsi, count) (vsi)->noproto = (count) #endif +#define IXL_DEV_ERR(_dev, _format, ...) \ + device_printf(_dev, "%s: " _format " (%s:%d)\n", __func__, ##__VA_ARGS__, __FILE__, __LINE__) + /* ***************************************************************************** * vendor_info_array @@ -403,22 +319,6 @@ unsigned int index; } ixl_vendor_info_t; - -struct ixl_tx_buf { - u32 eop_index; - struct mbuf *m_head; - bus_dmamap_t map; - bus_dma_tag_t tag; -}; - -struct ixl_rx_buf { - struct mbuf *m_head; - struct mbuf *m_pack; - struct mbuf *fmp; - bus_dmamap_t hmap; - bus_dmamap_t pmap; -}; - /* ** This struct has multiple uses, multicast ** addresses, vlans, and mac filters all use it. @@ -434,34 +334,30 @@ * The Transmit ring control struct */ struct tx_ring { - struct ixl_queue *que; - struct mtx mtx; + struct ixl_tx_queue *que; u32 tail; - struct i40e_tx_desc *base; - struct i40e_dma_mem dma; - u16 next_avail; - u16 next_to_clean; - u16 atr_rate; - u16 atr_count; - u32 itr; + struct i40e_tx_desc *tx_base; + u64 tx_paddr; u32 latency; - struct ixl_tx_buf *buffers; - volatile u16 avail; - u32 cmd; - bus_dma_tag_t tx_tag; - bus_dma_tag_t tso_tag; - char mtx_name[16]; - struct buf_ring *br; - s32 watchdog_timer; + u32 packets; + u32 me; + /* + * For reporting completed packet status + * in descriptor writeback mode + */ + qidx_t *tx_rsq; + qidx_t tx_rs_cidx; + qidx_t tx_rs_pidx; + qidx_t tx_cidx_processed; /* Used for Dynamic ITR calculation */ - u32 packets; + u32 itr; u32 bytes; /* Soft Stats */ u64 tx_bytes; - u64 no_desc; - u64 total_packets; + u64 tx_packets; + u64 mss_too_small; }; @@ -469,68 +365,46 @@ * The Receive ring control struct */ struct rx_ring { - struct ixl_queue *que; - struct mtx mtx; - union i40e_rx_desc *base; - struct i40e_dma_mem dma; - struct lro_ctrl lro; - bool lro_enabled; - bool hdr_split; + struct ixl_rx_queue *que; + union i40e_rx_desc *rx_base; + uint64_t rx_paddr; bool discard; - u32 next_refresh; - u32 next_check; u32 itr; u32 latency; - char mtx_name[16]; - struct ixl_rx_buf *buffers; u32 mbuf_sz; u32 tail; - bus_dma_tag_t htag; - bus_dma_tag_t ptag; + u32 me; /* Used for Dynamic ITR calculation */ u32 packets; u32 bytes; /* Soft stats */ - u64 split; u64 rx_packets; u64 rx_bytes; u64 desc_errs; - u64 not_done; }; /* -** Driver queue struct: this is the interrupt container -** for the associated tx and rx ring pair. +** Driver queue structs */ -struct ixl_queue { +struct ixl_tx_queue { struct ixl_vsi *vsi; - u32 me; - u32 msix; /* This queue's MSIX vector */ - u32 eims; /* This queue's EIMS bit */ - struct resource *res; - void *tag; - int num_tx_desc; /* both tx and rx */ - int num_rx_desc; /* both tx and rx */ -#ifdef DEV_NETMAP - int num_desc; /* for compatibility with current netmap code in kernel */ -#endif struct tx_ring txr; - struct rx_ring rxr; - struct task task; - struct task tx_task; - struct taskqueue *tq; - - /* Queue stats */ + struct if_irq que_irq; + u32 msix; + /* Stats */ u64 irqs; u64 tso; - u64 mbuf_defrag_failed; - u64 mbuf_hdr_failed; - u64 mbuf_pkt_failed; - u64 tx_dmamap_failed; - u64 dropped_pkts; - u64 mss_too_small; +}; + +struct ixl_rx_queue { + struct ixl_vsi *vsi; + struct rx_ring rxr; + struct if_irq que_irq; + u32 msix; /* This queue's MSIX vector */ + /* Stats */ + u64 irqs; }; /* @@ -538,29 +412,35 @@ */ SLIST_HEAD(ixl_ftl_head, ixl_mac_filter); struct ixl_vsi { - void *back; + if_ctx_t ctx; + if_softc_ctx_t shared; struct ifnet *ifp; - device_t dev; + //device_t dev; struct i40e_hw *hw; - struct ifmedia media; + struct ifmedia *media; +#define num_rx_queues shared->isc_nrxqsets +#define num_tx_queues shared->isc_ntxqsets + + void *back; enum i40e_vsi_type type; + // TODO: Remove? + u64 que_mask; int id; - u16 num_queues; - int num_tx_desc; - int num_rx_desc; u32 rx_itr_setting; u32 tx_itr_setting; - u16 max_frame_size; bool enable_head_writeback; - struct ixl_queue *queues; /* head of queues */ - u16 vsi_num; bool link_active; u16 seid; u16 uplink_seid; u16 downlink_seid; + struct ixl_tx_queue *tx_queues; /* TX queue array */ + struct ixl_rx_queue *rx_queues; /* RX queue array */ + struct if_irq irq; + u32 link_speed; + /* MAC/VLAN Filter list */ struct ixl_ftl_head ftl; u16 num_macs; @@ -568,8 +448,6 @@ /* Contains readylist & stat counter id */ struct i40e_aqc_vsi_properties_data info; - eventhandler_tag vlan_attach; - eventhandler_tag vlan_detach; u16 num_vlans; /* Per-VSI stats from hardware */ @@ -595,37 +473,27 @@ /* Misc. */ u64 flags; + /* Stats sysctls for this VSI */ struct sysctl_oid *vsi_node; }; /* -** Find the number of unrefreshed RX descriptors -*/ -static inline u16 -ixl_rx_unrefreshed(struct ixl_queue *que) -{ - struct rx_ring *rxr = &que->rxr; - - if (rxr->next_check > rxr->next_refresh) - return (rxr->next_check - rxr->next_refresh - 1); - else - return ((que->num_rx_desc + rxr->next_check) - - rxr->next_refresh - 1); -} - -/* -** Find the next available unused filter +** Creates new filter with given MAC address and VLAN ID */ static inline struct ixl_mac_filter * -ixl_get_filter(struct ixl_vsi *vsi) +ixl_new_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan) { struct ixl_mac_filter *f; /* create a new empty filter */ f = malloc(sizeof(struct ixl_mac_filter), M_DEVBUF, M_NOWAIT | M_ZERO); - if (f) + if (f) { SLIST_INSERT_HEAD(&vsi->ftl, f, next); + bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); + f->vlan = vlan; + f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); + } return (f); } @@ -636,14 +504,7 @@ static inline bool cmp_etheraddr(const u8 *ea1, const u8 *ea2) { - bool cmp = FALSE; - - if ((ea1[0] == ea2[0]) && (ea1[1] == ea2[1]) && - (ea1[2] == ea2[2]) && (ea1[3] == ea2[3]) && - (ea1[4] == ea2[4]) && (ea1[5] == ea2[5])) - cmp = TRUE; - - return (cmp); + return (bcmp(ea1, ea2, 6) == 0); } /* @@ -679,34 +540,11 @@ extern const uint8_t ixl_bcast_addr[ETHER_ADDR_LEN]; -/********************************************************************* - * TXRX Function prototypes - *********************************************************************/ -int ixl_allocate_tx_data(struct ixl_queue *); -int ixl_allocate_rx_data(struct ixl_queue *); -void ixl_init_tx_ring(struct ixl_queue *); -int ixl_init_rx_ring(struct ixl_queue *); -bool ixl_rxeof(struct ixl_queue *, int); -bool ixl_txeof(struct ixl_queue *); -void ixl_free_que_tx(struct ixl_queue *); -void ixl_free_que_rx(struct ixl_queue *); - -int ixl_mq_start(struct ifnet *, struct mbuf *); -int ixl_mq_start_locked(struct ifnet *, struct tx_ring *); -void ixl_deferred_mq_start(void *, int); - -void ixl_vsi_setup_rings_size(struct ixl_vsi *, int, int); -int ixl_queue_hang_check(struct ixl_vsi *); -void ixl_free_vsi(struct ixl_vsi *); -void ixl_qflush(struct ifnet *); - /* Common function prototypes between PF/VF driver */ -#if __FreeBSD_version >= 1100000 -uint64_t ixl_get_counter(if_t ifp, ift_counter cnt); -#endif -void ixl_get_default_rss_key(u32 *); +void ixl_init_tx_ring(struct ixl_vsi *vsi, struct ixl_tx_queue *que); +void ixl_set_queue_rx_itr(struct ixl_rx_queue *que); +void ixl_get_default_rss_key(u32 *); const char * i40e_vc_stat_str(struct i40e_hw *hw, enum virtchnl_status_code stat_err); -void ixl_set_busmaster(device_t); -void ixl_set_msix_enable(device_t); +u64 ixl_max_aq_speed_to_value(u8); #endif /* _IXL_H_ */ Index: sys/dev/ixl/ixl_debug.h =================================================================== --- /dev/null +++ sys/dev/ixl/ixl_debug.h @@ -0,0 +1,110 @@ +/****************************************************************************** + + Copyright (c) 2013-2018, Intel Corporation + All rights reserved. + + 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. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. + +******************************************************************************/ +/*$FreeBSD$*/ + +#ifndef _IXL_DEBUG_H_ +#define _IXL_DEBUG_H_ + +#define MAC_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_FORMAT_ARGS(mac_addr) \ + (mac_addr)[0], (mac_addr)[1], (mac_addr)[2], (mac_addr)[3], \ + (mac_addr)[4], (mac_addr)[5] +#define ON_OFF_STR(is_set) ((is_set) ? "On" : "Off") + +#ifdef IXL_DEBUG + +#define _DBG_PRINTF(S, ...) printf("%s: " S "\n", __func__, ##__VA_ARGS__) +#define _DEV_DBG_PRINTF(dev, S, ...) device_printf(dev, "%s: " S "\n", __func__, ##__VA_ARGS__) +#define _IF_DBG_PRINTF(ifp, S, ...) if_printf(ifp, "%s: " S "\n", __func__, ##__VA_ARGS__) + +/* Defines for printing generic debug information */ +#define DPRINTF(...) _DBG_PRINTF(__VA_ARGS__) +#define DDPRINTF(...) _DEV_DBG_PRINTF(__VA_ARGS__) +#define IDPRINTF(...) _IF_DBG_PRINTF(__VA_ARGS__) + +/* Defines for printing specific debug information */ +#define DEBUG_INIT 1 +#define DEBUG_IOCTL 1 +#define DEBUG_HW 1 + +#define INIT_DEBUGOUT(...) if (DEBUG_INIT) _DBG_PRINTF(__VA_ARGS__) +#define INIT_DBG_DEV(...) if (DEBUG_INIT) _DEV_DBG_PRINTF(__VA_ARGS__) +#define INIT_DBG_IF(...) if (DEBUG_INIT) _IF_DBG_PRINTF(__VA_ARGS__) + +#define IOCTL_DEBUGOUT(...) if (DEBUG_IOCTL) _DBG_PRINTF(__VA_ARGS__) +#define IOCTL_DBG_IF2(ifp, S, ...) if (DEBUG_IOCTL) \ + if_printf(ifp, S "\n", ##__VA_ARGS__) +#define IOCTL_DBG_IF(...) if (DEBUG_IOCTL) _IF_DBG_PRINTF(__VA_ARGS__) + +#define HW_DEBUGOUT(...) if (DEBUG_HW) _DBG_PRINTF(__VA_ARGS__) + +#else /* no IXL_DEBUG */ +#define DEBUG_INIT 0 +#define DEBUG_IOCTL 0 +#define DEBUG_HW 0 + +#define DPRINTF(...) +#define DDPRINTF(...) +#define IDPRINTF(...) + +#define INIT_DEBUGOUT(...) +#define INIT_DBG_DEV(...) +#define INIT_DBG_IF(...) +#define IOCTL_DEBUGOUT(...) +#define IOCTL_DBG_IF2(...) +#define IOCTL_DBG_IF(...) +#define HW_DEBUGOUT(...) +#endif /* IXL_DEBUG */ + +enum ixl_dbg_mask { + IXL_DBG_INFO = 0x00000001, + IXL_DBG_EN_DIS = 0x00000002, + IXL_DBG_AQ = 0x00000004, + IXL_DBG_NVMUPD = 0x00000008, + + IXL_DBG_IOCTL_KNOWN = 0x00000010, + IXL_DBG_IOCTL_UNKNOWN = 0x00000020, + IXL_DBG_IOCTL_ALL = 0x00000030, + + I40E_DEBUG_RSS = 0x00000100, + + IXL_DBG_IOV = 0x00001000, + IXL_DBG_IOV_VC = 0x00002000, + + IXL_DBG_SWITCH_INFO = 0x00010000, + IXL_DBG_I2C = 0x00020000, + + IXL_DBG_ALL = 0xFFFFFFFF +}; + +#endif /* _IXL_DEBUG_H_ */ Index: sys/dev/ixl/ixl_iw.h =================================================================== --- sys/dev/ixl/ixl_iw.h +++ sys/dev/ixl/ixl_iw.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixl_iw.c =================================================================== --- sys/dev/ixl/ixl_iw.c +++ sys/dev/ixl/ixl_iw.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixl_iw_int.h =================================================================== --- sys/dev/ixl/ixl_iw_int.h +++ sys/dev/ixl/ixl_iw_int.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixl_pf.h =================================================================== --- sys/dev/ixl/ixl_pf.h +++ sys/dev/ixl/ixl_pf.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -45,16 +45,41 @@ #define VF_FLAG_PROMISC_CAP 0x08 #define VF_FLAG_MAC_ANTI_SPOOF 0x10 -#define IXL_PF_STATE_EMPR_RESETTING (1 << 0) -#define IXL_PF_STATE_FW_LLDP_DISABLED (1 << 1) +#define IXL_ICR0_CRIT_ERR_MASK \ + (I40E_PFINT_ICR0_PCI_EXCEPTION_MASK | \ + I40E_PFINT_ICR0_ECC_ERR_MASK | \ + I40E_PFINT_ICR0_PE_CRITERR_MASK) + +/* VF Interrupts */ +#define IXL_VPINT_LNKLSTN_REG(hw, vector, vf_num) \ + I40E_VPINT_LNKLSTN(((vector) - 1) + \ + (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num))) + +#define IXL_VFINT_DYN_CTLN_REG(hw, vector, vf_num) \ + I40E_VFINT_DYN_CTLN(((vector) - 1) + \ + (((hw)->func_caps.num_msix_vectors_vf - 1) * (vf_num))) + +/* Used in struct ixl_pf's state field */ +enum ixl_pf_state { + IXL_PF_STATE_ADAPTER_RESETTING = (1 << 0), + IXL_PF_STATE_MDD_PENDING = (1 << 1), + IXL_PF_STATE_PF_RESET_REQ = (1 << 2), + IXL_PF_STATE_VF_RESET_REQ = (1 << 3), + IXL_PF_STATE_PF_CRIT_ERR = (1 << 4), + IXL_PF_STATE_CORE_RESET_REQ = (1 << 5), + IXL_PF_STATE_GLOB_RESET_REQ = (1 << 6), + IXL_PF_STATE_EMP_RESET_REQ = (1 << 7), + IXL_PF_STATE_FW_LLDP_DISABLED = (1 << 8), +}; struct ixl_vf { struct ixl_vsi vsi; - uint32_t vf_flags; + u32 vf_flags; + u32 num_mdd_events; - uint8_t mac[ETHER_ADDR_LEN]; - uint16_t vf_num; - uint32_t version; + u8 mac[ETHER_ADDR_LEN]; + u16 vf_num; + u32 version; struct ixl_pf_qtag qtag; struct sysctl_ctx_list ctx; @@ -62,31 +87,24 @@ /* Physical controller structure */ struct ixl_pf { + /* + * This is first so that iflib_get_softc can return + * either the VSI or the PF structures. + */ + struct ixl_vsi vsi; + struct i40e_hw hw; struct i40e_osdep osdep; device_t dev; - struct ixl_vsi vsi; struct resource *pci_mem; - struct resource *msix_mem; - /* - * Interrupt resources: this set is - * either used for legacy, or for Link - * when doing MSIX - */ - void *tag; - struct resource *res; - - struct callout timer; - int msix; #ifdef IXL_IW int iw_msix; bool iw_enabled; #endif int if_flags; - int state; - bool init_in_progress; + u32 state; u8 supported_speeds; struct ixl_pf_qmgr qmgr; @@ -101,13 +119,6 @@ int tx_itr; int rx_itr; - struct mtx pf_mtx; - - u32 qbase; - u32 admvec; - struct task adminq; - struct taskqueue *tq; - bool link_up; u32 link_speed; int advertised_speed; @@ -124,6 +135,13 @@ struct i40e_hw_port_stats stats_offsets; bool stat_offsets_loaded; + /* I2C access methods */ + u8 i2c_access_method; + s32 (*read_i2c_byte)(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 *data); + s32 (*write_i2c_byte)(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 data); + /* SR-IOV */ struct ixl_vf *vfs; int num_vfs; @@ -177,13 +195,38 @@ #define IXL_SYSCTL_HELP_LINK_STATUS \ "\nExecutes a \"Get Link Status\" command on the Admin Queue, and displays" \ -" the response." \ +" the response." #define IXL_SYSCTL_HELP_FW_LLDP \ "\nFW LLDP engine:\n" \ "\t0 - disable\n" \ "\t1 - enable\n" +#define IXL_SYSCTL_HELP_READ_I2C \ +"\nRead a byte from I2C bus\n" \ +"Input: 32-bit value\n" \ +"\tbits 0-7: device address (0xA0 or 0xA2)\n" \ +"\tbits 8-15: offset (0-255)\n" \ +"\tbits 16-31: unused\n" \ +"Output: 8-bit value read" + +#define IXL_SYSCTL_HELP_WRITE_I2C \ +"\nWrite a byte to the I2C bus\n" \ +"Input: 32-bit value\n" \ +"\tbits 0-7: device address (0xA0 or 0xA2)\n" \ +"\tbits 8-15: offset (0-255)\n" \ +"\tbits 16-23: value to write\n" \ +"\tbits 24-31: unused\n" \ +"Output: 8-bit value written" + +#define IXL_SYSCTL_HELP_I2C_METHOD \ +"\nI2C access method that driver will use:\n" \ +"\t0 - best available method\n" \ +"\t1 - bit bang via I2CPARAMS register\n" \ +"\t2 - register read/write via I2CCMD register\n" \ +"\t3 - Use Admin Queue command (best)\n" \ +"Using the Admin Queue is only supported on 710 devices with FW version 1.7 or higher" + extern const char * const ixl_fc_string[6]; MALLOC_DECLARE(M_IXL); @@ -199,13 +242,6 @@ #define i40e_send_vf_nack(pf, vf, op, st) \ ixl_send_vf_nack_msg((pf), (vf), (op), (st), __FILE__, __LINE__) -#define IXL_PF_LOCK_INIT(_sc, _name) \ - mtx_init(&(_sc)->pf_mtx, _name, "IXL PF Lock", MTX_DEF) -#define IXL_PF_LOCK(_sc) mtx_lock(&(_sc)->pf_mtx) -#define IXL_PF_UNLOCK(_sc) mtx_unlock(&(_sc)->pf_mtx) -#define IXL_PF_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->pf_mtx) -#define IXL_PF_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->pf_mtx, MA_OWNED) - /* Debug printing */ #define ixl_dbg(p, m, s, ...) ixl_debug_core(p, m, s, ##__VA_ARGS__) void ixl_debug_core(struct ixl_pf *, enum ixl_dbg_mask, char *, ...); @@ -216,11 +252,8 @@ /* For netmap(4) compatibility */ #define ixl_disable_intr(vsi) ixl_disable_rings_intr(vsi) -/* - * PF-only function declarations - */ - -int ixl_setup_interface(device_t, struct ixl_vsi *); +/* PF-only function declarations */ +int ixl_setup_interface(device_t, struct ixl_pf *); void ixl_print_nvm_cmd(device_t, struct i40e_nvm_access *); char * ixl_aq_speed_to_str(enum i40e_aq_link_speed); @@ -230,9 +263,9 @@ void ixl_local_timer(void *); void ixl_register_vlan(void *, struct ifnet *, u16); void ixl_unregister_vlan(void *, struct ifnet *, u16); -void ixl_intr(void *); -void ixl_msix_que(void *); -void ixl_msix_adminq(void *); +int ixl_intr(void *); +int ixl_msix_que(void *); +int ixl_msix_adminq(void *); void ixl_do_adminq(void *, int); int ixl_res_alloc_cmp(const void *, const void *); @@ -264,7 +297,6 @@ int ixl_get_hw_capabilities(struct ixl_pf *); void ixl_link_up_msg(struct ixl_pf *); void ixl_update_link_status(struct ixl_pf *); -int ixl_allocate_pci_resources(struct ixl_pf *); int ixl_setup_stations(struct ixl_pf *); int ixl_switch_config(struct ixl_pf *); void ixl_stop_locked(struct ixl_pf *); @@ -304,8 +336,8 @@ int ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up); int ixl_rebuild_hw_structs_after_reset(struct ixl_pf *, bool is_up); -void ixl_set_queue_rx_itr(struct ixl_queue *); -void ixl_set_queue_tx_itr(struct ixl_queue *); +void ixl_set_queue_rx_itr(struct ixl_rx_queue *); +void ixl_set_queue_tx_itr(struct ixl_tx_queue *); void ixl_add_filter(struct ixl_vsi *, const u8 *, s16 vlan); void ixl_del_filter(struct ixl_vsi *, const u8 *, s16 vlan); @@ -345,19 +377,31 @@ void ixl_update_vsi_stats(struct ixl_vsi *); void ixl_vsi_reset_stats(struct ixl_vsi *); -int ixl_vsi_setup_queues(struct ixl_vsi *vsi); void ixl_vsi_free_queues(struct ixl_vsi *vsi); +void ixl_if_init(if_ctx_t ctx); +void ixl_if_stop(if_ctx_t ctx); + /* * I2C Function prototypes */ int ixl_find_i2c_interface(struct ixl_pf *); -s32 ixl_read_i2c_byte(struct ixl_pf *pf, u8 byte_offset, +s32 ixl_read_i2c_byte_bb(struct ixl_pf *pf, u8 byte_offset, u8 dev_addr, u8 *data); -s32 ixl_write_i2c_byte(struct ixl_pf *pf, u8 byte_offset, +s32 ixl_write_i2c_byte_bb(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 data); +s32 ixl_read_i2c_byte_reg(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 *data); +s32 ixl_write_i2c_byte_reg(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 data); +s32 ixl_read_i2c_byte_aq(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 *data); +s32 ixl_write_i2c_byte_aq(struct ixl_pf *pf, u8 byte_offset, u8 dev_addr, u8 data); int ixl_get_fw_lldp_status(struct ixl_pf *pf); int ixl_attach_get_link_status(struct ixl_pf *); +u64 ixl_max_aq_speed_to_value(u8); +void ixl_handle_vflr(void *, int); #endif /* _IXL_PF_H_ */ Index: sys/dev/ixl/ixl_pf_i2c.c =================================================================== --- sys/dev/ixl/ixl_pf_i2c.c +++ sys/dev/ixl/ixl_pf_i2c.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -46,9 +46,9 @@ #define IXL_I2C_CLOCK_STRETCHING_TIMEOUT 500 #define IXL_I2C_REG(_hw) \ - I40E_GLGEN_I2CPARAMS(((struct i40e_osdep *)(_hw)->back)->i2c_intfc_num) - + I40E_GLGEN_I2CPARAMS(_hw->func_caps.mdio_port_num) +/* I2C bit-banging functions */ static s32 ixl_set_i2c_data(struct ixl_pf *pf, u32 *i2cctl, bool data); static bool ixl_get_i2c_data(struct ixl_pf *pf, u32 *i2cctl); static void ixl_raise_i2c_clk(struct ixl_pf *pf, u32 *i2cctl); @@ -62,6 +62,8 @@ static void ixl_i2c_start(struct ixl_pf *pf); static void ixl_i2c_stop(struct ixl_pf *pf); +static s32 ixl_wait_for_i2c_completion(struct i40e_hw *hw, u8 portnum); + /** * ixl_i2c_bus_clear - Clears the I2C bus * @hw: pointer to hardware structure @@ -449,10 +451,10 @@ } /** - * ixl_read_i2c_byte - Reads 8 bit word over I2C + * ixl_read_i2c_byte_bb - Reads 8 bit word over I2C **/ s32 -ixl_read_i2c_byte(struct ixl_pf *pf, u8 byte_offset, +ixl_read_i2c_byte_bb(struct ixl_pf *pf, u8 byte_offset, u8 dev_addr, u8 *data) { struct i40e_hw *hw = &pf->hw; @@ -523,9 +525,9 @@ i40e_msec_delay(100); retry++; if (retry < max_retry) - ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read error - Retrying.\n"); + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read error - Retrying\n"); else - ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read error.\n"); + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read error\n"); } while (retry < max_retry); done: @@ -538,10 +540,10 @@ } /** - * ixl_write_i2c_byte - Writes 8 bit word over I2C + * ixl_write_i2c_byte_bb - Writes 8 bit word over I2C **/ s32 -ixl_write_i2c_byte(struct ixl_pf *pf, u8 byte_offset, +ixl_write_i2c_byte_bb(struct ixl_pf *pf, u8 byte_offset, u8 dev_addr, u8 data) { struct i40e_hw *hw = &pf->hw; @@ -589,9 +591,9 @@ i40e_msec_delay(100); retry++; if (retry < max_retry) - ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write error - Retrying.\n"); + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write error - Retrying\n"); else - ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write error.\n"); + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write error\n"); } while (retry < max_retry); write_byte_out: @@ -603,3 +605,139 @@ return status; } +/** + * ixl_read_i2c_byte - Reads 8 bit word over I2C using a hardware register + **/ +s32 +ixl_read_i2c_byte_reg(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 *data) +{ + struct i40e_hw *hw = &pf->hw; + u32 reg = 0; + s32 status; + *data = 0; + + reg |= (byte_offset << I40E_GLGEN_I2CCMD_REGADD_SHIFT); + reg |= (((dev_addr >> 1) & 0x7) << I40E_GLGEN_I2CCMD_PHYADD_SHIFT); + reg |= I40E_GLGEN_I2CCMD_OP_MASK; + wr32(hw, I40E_GLGEN_I2CCMD(hw->func_caps.mdio_port_num), reg); + + status = ixl_wait_for_i2c_completion(hw, hw->func_caps.mdio_port_num); + + /* Get data from I2C register */ + reg = rd32(hw, I40E_GLGEN_I2CCMD(hw->func_caps.mdio_port_num)); + + /* Retrieve data readed from EEPROM */ + *data = (u8)(reg & 0xff); + + if (status) + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read error\n"); + return status; +} + +/** + * ixl_write_i2c_byte - Writes 8 bit word over I2C using a hardware register + **/ +s32 +ixl_write_i2c_byte_reg(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 data) +{ + struct i40e_hw *hw = &pf->hw; + s32 status = I40E_SUCCESS; + u32 reg = 0; + u8 upperbyte = 0; + u16 datai2c = 0; + + status = ixl_read_i2c_byte_reg(pf, byte_offset + 1, dev_addr, &upperbyte); + datai2c = ((u16)upperbyte << 8) | (u16)data; + reg = rd32(hw, I40E_GLGEN_I2CCMD(hw->func_caps.mdio_port_num)); + + /* Form write command */ + reg &= ~I40E_GLGEN_I2CCMD_PHYADD_MASK; + reg |= (((dev_addr >> 1) & 0x7) << I40E_GLGEN_I2CCMD_PHYADD_SHIFT); + reg &= ~I40E_GLGEN_I2CCMD_REGADD_MASK; + reg |= (byte_offset << I40E_GLGEN_I2CCMD_REGADD_SHIFT); + reg &= ~I40E_GLGEN_I2CCMD_DATA_MASK; + reg |= (datai2c << I40E_GLGEN_I2CCMD_DATA_SHIFT); + reg &= ~I40E_GLGEN_I2CCMD_OP_MASK; + + /* Write command to registers controling I2C - data and address. */ + wr32(hw, I40E_GLGEN_I2CCMD(hw->func_caps.mdio_port_num), reg); + + status = ixl_wait_for_i2c_completion(hw, hw->func_caps.mdio_port_num); + + if (status) + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write error\n"); + return status; +} + +/** + * ixl_wait_for_i2c_completion + **/ +static s32 +ixl_wait_for_i2c_completion(struct i40e_hw *hw, u8 portnum) +{ + s32 status = 0; + u32 timeout = 100; + u32 reg; + do { + reg = rd32(hw, I40E_GLGEN_I2CCMD(portnum)); + if ((reg & I40E_GLGEN_I2CCMD_R_MASK) != 0) + break; + i40e_usec_delay(10); + } while (timeout-- > 0); + + if (timeout == 0) + return I40E_ERR_TIMEOUT; + else + return status; +} + +/** + * ixl_read_i2c_byte - Reads 8 bit word over I2C using a hardware register + **/ +s32 +ixl_read_i2c_byte_aq(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 *data) +{ + struct i40e_hw *hw = &pf->hw; + s32 status = I40E_SUCCESS; + u32 reg; + + status = i40e_aq_get_phy_register(hw, + I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, + dev_addr, + byte_offset, + ®, NULL); + + if (status) + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte read status %s, error %s\n", + i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status)); + else + *data = (u8)reg; + + return status; +} + +/** + * ixl_write_i2c_byte - Writes 8 bit word over I2C using a hardware register + **/ +s32 +ixl_write_i2c_byte_aq(struct ixl_pf *pf, u8 byte_offset, + u8 dev_addr, u8 data) +{ + struct i40e_hw *hw = &pf->hw; + s32 status = I40E_SUCCESS; + + status = i40e_aq_set_phy_register(hw, + I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, + dev_addr, + byte_offset, + data, NULL); + + if (status) + ixl_dbg(pf, IXL_DBG_I2C, "I2C byte write status %s, error %s\n", + i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status)); + + return status; +} Index: sys/dev/ixl/ixl_pf_iov.h =================================================================== --- sys/dev/ixl/ixl_pf_iov.h +++ sys/dev/ixl/ixl_pf_iov.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixl_pf_iov.c =================================================================== --- sys/dev/ixl/ixl_pf_iov.c +++ sys/dev/ixl/ixl_pf_iov.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -83,15 +83,13 @@ void ixl_initialize_sriov(struct ixl_pf *pf) { + return; +#if 0 device_t dev = pf->dev; struct i40e_hw *hw = &pf->hw; nvlist_t *pf_schema, *vf_schema; int iov_error; - /* SR-IOV is only supported when MSI-X is in use. */ - if (pf->msix <= 1) - return; - pf_schema = pci_iov_schema_alloc_node(); vf_schema = pci_iov_schema_alloc_node(); pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL); @@ -114,8 +112,10 @@ device_printf(dev, "SR-IOV ready\n"); pf->vc_debug_lvl = 1; +#endif } + /* * Allocate the VSI for a VF. */ @@ -165,15 +165,17 @@ vsi_ctx.info.tc_mapping[0] = htole16( (0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) | - (bsrl(vf->qtag.num_allocated) << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); + ((fls(vf->qtag.num_allocated) - 1) << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)); code = i40e_aq_add_vsi(hw, &vsi_ctx, NULL); if (code != I40E_SUCCESS) return (ixl_adminq_err_to_errno(hw->aq.asq_last_status)); vf->vsi.seid = vsi_ctx.seid; vf->vsi.vsi_num = vsi_ctx.vsi_number; - // vf->vsi.first_queue = vf->qtag.qidx[0]; - vf->vsi.num_queues = vf->qtag.num_active; + // TODO: How to deal with num tx queues / num rx queues split? + // I don't think just assigning this variable is going to work + vf->vsi.num_rx_queues = vf->qtag.num_active; + vf->vsi.num_tx_queues = vf->qtag.num_active; code = i40e_aq_get_vsi_params(hw, &vsi_ctx, NULL); if (code != I40E_SUCCESS) @@ -204,7 +206,7 @@ vf->vsi.hw_filters_add = 0; vf->vsi.hw_filters_del = 0; - ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); + // ixl_add_filter(&vf->vsi, ixl_bcast_addr, IXL_VLAN_ANY); ixl_reconfigure_filters(&vf->vsi); return (0); @@ -253,7 +255,7 @@ /* Program index of each VF queue into PF queue space * (This is only needed if QTABLE is enabled) */ - for (i = 0; i < vf->vsi.num_queues; i++) { + for (i = 0; i < vf->vsi.num_tx_queues; i++) { qtable = ixl_pf_qidx_from_vsi_qidx(&vf->qtag, i) << I40E_VPLAN_QTABLE_QINDEX_SHIFT; @@ -266,7 +268,7 @@ /* Map queues allocated to VF to its VSI; * This mapping matches the VF-wide mapping since the VF * is only given a single VSI */ - for (i = 0; i < vf->vsi.num_queues; i++) + for (i = 0; i < vf->vsi.num_tx_queues; i++) ixl_vf_map_vsi_queue(hw, vf, i, ixl_pf_qidx_from_vsi_qidx(&vf->qtag, i)); @@ -335,7 +337,8 @@ ixl_vf_unregister_intr(hw, vpint_reg); } - vf->vsi.num_queues = 0; + vf->vsi.num_tx_queues = 0; + vf->vsi.num_rx_queues = 0; } static int @@ -533,13 +536,13 @@ VIRTCHNL_VF_OFFLOAD_VLAN); reply.num_vsis = 1; - reply.num_queue_pairs = vf->vsi.num_queues; + reply.num_queue_pairs = vf->vsi.num_tx_queues; reply.max_vectors = pf->hw.func_caps.num_msix_vectors_vf; reply.rss_key_size = 52; reply.rss_lut_size = 64; reply.vsi_res[0].vsi_id = vf->vsi.vsi_num; reply.vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV; - reply.vsi_res[0].num_queue_pairs = vf->vsi.num_queues; + reply.vsi_res[0].num_queue_pairs = vf->vsi.num_tx_queues; memcpy(reply.vsi_res[0].default_mac_addr, vf->mac, ETHER_ADDR_LEN); ixl_send_vf_msg(pf, vf, VIRTCHNL_OP_GET_VF_RESOURCES, @@ -674,9 +677,9 @@ } info = msg; - if (info->num_queue_pairs == 0 || info->num_queue_pairs > vf->vsi.num_queues) { + if (info->num_queue_pairs == 0 || info->num_queue_pairs > vf->vsi.num_tx_queues) { device_printf(pf->dev, "VF %d: invalid # of qpairs (msg has %d, VSI has %d)\n", - vf->vf_num, info->num_queue_pairs, vf->vsi.num_queues); + vf->vf_num, info->num_queue_pairs, vf->vsi.num_tx_queues); i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); return; @@ -705,7 +708,7 @@ if (pair->txq.vsi_id != vf->vsi.vsi_num || pair->rxq.vsi_id != vf->vsi.vsi_num || pair->txq.queue_id != pair->rxq.queue_id || - pair->txq.queue_id >= vf->vsi.num_queues) { + pair->txq.queue_id >= vf->vsi.num_tx_queues) { i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES, I40E_ERR_PARAM); @@ -854,7 +857,7 @@ if (vector->rxq_map != 0) { largest_rxq = fls(vector->rxq_map) - 1; - if (largest_rxq >= vf->vsi.num_queues) { + if (largest_rxq >= vf->vsi.num_rx_queues) { i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); @@ -864,7 +867,7 @@ if (vector->txq_map != 0) { largest_txq = fls(vector->txq_map) - 1; - if (largest_txq >= vf->vsi.num_queues) { + if (largest_txq >= vf->vsi.num_tx_queues) { i40e_send_vf_nack(pf, vf, VIRTCHNL_OP_CONFIG_IRQ_MAP, I40E_ERR_PARAM); @@ -911,7 +914,7 @@ for (int i = 0; i < 32; i++) { if ((1 << i) & select->tx_queues) { /* Warn if queue is out of VF allocation range */ - if (i >= vf->vsi.num_queues) { + if (i >= vf->vsi.num_tx_queues) { device_printf(pf->dev, "VF %d: TX ring %d is outside of VF VSI allocation!\n", vf->vf_num, i); break; @@ -936,7 +939,7 @@ for (int i = 0; i < 32; i++) { if ((1 << i) & select->rx_queues) { /* Warn if queue is out of VF allocation range */ - if (i >= vf->vsi.num_queues) { + if (i >= vf->vsi.num_rx_queues) { device_printf(pf->dev, "VF %d: RX ring %d is outside of VF VSI allocation!\n", vf->vf_num, i); break; @@ -990,7 +993,7 @@ for (int i = 0; i < 32; i++) { if ((1 << i) & select->tx_queues) { /* Warn if queue is out of VF allocation range */ - if (i >= vf->vsi.num_queues) { + if (i >= vf->vsi.num_tx_queues) { device_printf(pf->dev, "VF %d: TX ring %d is outside of VF VSI allocation!\n", vf->vf_num, i); break; @@ -1016,7 +1019,7 @@ for (int i = 0; i < 32; i++) { if ((1 << i) & select->rx_queues) { /* Warn if queue is out of VF allocation range */ - if (i >= vf->vsi.num_queues) { + if (i >= vf->vsi.num_rx_queues) { device_printf(pf->dev, "VF %d: RX ring %d is outside of VF VSI allocation!\n", vf->vf_num, i); break; @@ -1058,6 +1061,8 @@ static bool ixl_bcast_mac(const uint8_t *addr) { + static uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; return (cmp_etheraddr(addr, ixl_bcast_addr)); } @@ -1634,7 +1639,7 @@ pf = arg; hw = &pf->hw; - IXL_PF_LOCK(pf); + /* TODO: May need to lock this */ for (i = 0; i < pf->num_vfs; i++) { global_vf_num = hw->func_caps.vf_base_id + i; @@ -1653,12 +1658,13 @@ } } + atomic_clear_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ); icr0 = rd32(hw, I40E_PFINT_ICR0_ENA); icr0 |= I40E_PFINT_ICR0_ENA_VFLR_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, icr0); ixl_flush(hw); - IXL_PF_UNLOCK(pf); + // IXL_PF_UNLOCK() } static int @@ -1728,7 +1734,7 @@ hw = &pf->hw; pf_vsi = &pf->vsi; - IXL_PF_LOCK(pf); + //IXL_PF_LOCK(pf); pf->vfs = malloc(sizeof(struct ixl_vf) * num_vfs, M_IXL, M_NOWAIT | M_ZERO); @@ -1750,13 +1756,13 @@ } pf->num_vfs = num_vfs; - IXL_PF_UNLOCK(pf); + //IXL_PF_UNLOCK(pf); return (0); fail: free(pf->vfs, M_IXL); pf->vfs = NULL; - IXL_PF_UNLOCK(pf); + //IXL_PF_UNLOCK(pf); return (error); } @@ -1775,7 +1781,7 @@ vsi = &pf->vsi; ifp = vsi->ifp; - IXL_PF_LOCK(pf); + //IXL_PF_LOCK(pf); for (i = 0; i < pf->num_vfs; i++) { if (pf->vfs[i].vsi.seid != 0) i40e_aq_delete_element(hw, pf->vfs[i].vsi.seid, NULL); @@ -1796,7 +1802,7 @@ pf->vfs = NULL; pf->num_vfs = 0; - IXL_PF_UNLOCK(pf); + //IXL_PF_UNLOCK(pf); /* Do this after the unlock as sysctl_ctx_free might sleep. */ for (i = 0; i < num_vfs; i++) @@ -1849,7 +1855,7 @@ pf = device_get_softc(dev); vf = &pf->vfs[vfnum]; - IXL_PF_LOCK(pf); + //IXL_PF_LOCK(pf); vf->vf_num = vfnum; vf->vsi.back = pf; @@ -1889,7 +1895,7 @@ ixl_reset_vf(pf, vf); out: - IXL_PF_UNLOCK(pf); + //IXL_PF_UNLOCK(pf); if (error == 0) { snprintf(sysctl_name, sizeof(sysctl_name), "vf%d", vfnum); ixl_add_vsi_sysctls(pf, &vf->vsi, &vf->ctx, sysctl_name); Index: sys/dev/ixl/ixl_pf_main.c =================================================================== --- sys/dev/ixl/ixl_pf_main.c +++ sys/dev/ixl/ixl_pf_main.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -44,16 +44,9 @@ #include "ixl_iw_int.h" #endif -#ifdef DEV_NETMAP -#include -#include -#include -#endif /* DEV_NETMAP */ - -static int ixl_vsi_setup_queue(struct ixl_vsi *, struct ixl_queue *, int); -static u64 ixl_max_aq_speed_to_value(u8); static u8 ixl_convert_sysctl_aq_link_speed(u8, bool); static void ixl_sbuf_print_bytes(struct sbuf *, u8 *, int, int, bool); +static void ixl_del_default_hw_filters(struct ixl_vsi *); /* Sysctls */ static int ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS); @@ -84,6 +77,12 @@ static int ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS); static int ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS); static int ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_do_pf_reset(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_do_core_reset(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_do_global_reset(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_do_emp_reset(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS); +static int ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS); #ifdef IXL_DEBUG static int ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS); static int ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS); @@ -170,11 +169,11 @@ { struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; - struct ixl_queue *que = vsi->queues; + struct ixl_tx_queue *que = vsi->tx_queues; vsi->tx_itr_setting = pf->tx_itr; - for (int i = 0; i < vsi->num_queues; i++, que++) { + for (int i = 0; i < vsi->num_tx_queues; i++, que++) { struct tx_ring *txr = &que->txr; wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, i), @@ -189,11 +188,11 @@ { struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *que = vsi->rx_queues; vsi->rx_itr_setting = pf->rx_itr; - for (int i = 0; i < vsi->num_queues; i++, que++) { + for (int i = 0; i < vsi->num_rx_queues; i++, que++) { struct rx_ring *rxr = &que->rxr; wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, i), @@ -213,136 +212,6 @@ ixl_configure_rx_itr(pf); } - -/********************************************************************* - * Init entry point - * - * This routine is used in two ways. It is used by the stack as - * init entry point in network interface structure. It is also used - * by the driver as a hw/sw initialization routine to get to a - * consistent state. - * - * return 0 on success, positive on failure - **********************************************************************/ -void -ixl_init_locked(struct ixl_pf *pf) -{ - struct i40e_hw *hw = &pf->hw; - struct ixl_vsi *vsi = &pf->vsi; - struct ifnet *ifp = vsi->ifp; - device_t dev = pf->dev; - struct i40e_filter_control_settings filter; - u8 tmpaddr[ETHER_ADDR_LEN]; - int ret; - - INIT_DEBUGOUT("ixl_init_locked: begin"); - IXL_PF_LOCK_ASSERT(pf); - - ixl_stop_locked(pf); - - /* - * If the aq is dead here, it probably means something outside of the driver - * did something to the adapter, like a PF reset. - * So rebuild the driver's state here if that occurs. - */ - if (!i40e_check_asq_alive(&pf->hw)) { - device_printf(dev, "Admin Queue is down; resetting...\n"); - ixl_teardown_hw_structs(pf); - ixl_reset(pf); - } - - /* Get the latest mac address... User might use a LAA */ - bcopy(IF_LLADDR(vsi->ifp), tmpaddr, - ETH_ALEN); - if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && - (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { - device_printf(dev, "ixl_init_locked: reconfigure MAC addr\n"); - ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); - bcopy(tmpaddr, hw->mac.addr, - ETH_ALEN); - ret = i40e_aq_mac_address_write(hw, - I40E_AQC_WRITE_TYPE_LAA_ONLY, - hw->mac.addr, NULL); - if (ret) { - device_printf(dev, "LLA address" - "change failed!!\n"); - return; - } - } - - ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); - - /* Set the various hardware offload abilities */ - ifp->if_hwassist = 0; - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); - if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) - ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); - - /* Set up the device filtering */ - bzero(&filter, sizeof(filter)); - filter.enable_ethtype = TRUE; - filter.enable_macvlan = TRUE; - filter.enable_fdir = FALSE; - filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; - if (i40e_set_filter_control(hw, &filter)) - device_printf(dev, "i40e_set_filter_control() failed\n"); - - /* Prepare the VSI: rings, hmc contexts, etc... */ - if (ixl_initialize_vsi(vsi)) { - device_printf(dev, "initialize vsi failed!!\n"); - return; - } - - /* Set up RSS */ - ixl_config_rss(pf); - - /* Add protocol filters to list */ - ixl_init_filters(vsi); - - /* Setup vlan's if needed */ - ixl_setup_vlan_filters(vsi); - - /* Set up MSI/X routing and the ITR settings */ - if (pf->msix > 1) { - ixl_configure_queue_intr_msix(pf); - ixl_configure_itr(pf); - } else - ixl_configure_legacy(pf); - - ixl_enable_rings(vsi); - - i40e_aq_set_default_vsi(hw, vsi->seid, NULL); - - ixl_reconfigure_filters(vsi); - - /* And now turn on interrupts */ - ixl_enable_intr(vsi); - - /* Get link info */ - hw->phy.get_link_info = TRUE; - i40e_get_link_status(hw, &pf->link_up); - ixl_update_link_status(pf); - - /* Start the local timer */ - callout_reset(&pf->timer, hz, ixl_local_timer, pf); - - /* Now inform the stack we're ready */ - ifp->if_drv_flags |= IFF_DRV_RUNNING; - -#ifdef IXL_IW - if (ixl_enable_iwarp && pf->iw_enabled) { - ret = ixl_iw_pf_init(pf); - if (ret) - device_printf(dev, - "initialize iwarp failed, code %d\n", ret); - } -#endif -} - - /********************************************************************* * * Get the hardware capabilities @@ -355,9 +224,10 @@ struct i40e_aqc_list_capabilities_element_resp *buf; struct i40e_hw *hw = &pf->hw; device_t dev = pf->dev; - int error, len; - u16 needed; - bool again = TRUE; + enum i40e_status_code status; + int len, i2c_intfc_num; + bool again = TRUE; + u16 needed; len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); retry: @@ -368,7 +238,7 @@ } /* This populates the hw struct */ - error = i40e_aq_discover_capabilities(hw, buf, len, + status = i40e_aq_discover_capabilities(hw, buf, len, &needed, i40e_aqc_opc_list_func_capabilities, NULL); free(buf, M_DEVBUF); if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && @@ -377,32 +247,52 @@ again = FALSE; len = needed; goto retry; - } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { - device_printf(dev, "capability discovery failed: %d\n", - pf->hw.aq.asq_last_status); + } else if (status != I40E_SUCCESS) { + device_printf(dev, "capability discovery failed; status %s, error %s\n", + i40e_stat_str(hw, status), i40e_aq_str(hw, hw->aq.asq_last_status)); return (ENODEV); } - /* Capture this PF's starting queue pair */ - pf->qbase = hw->func_caps.base_queue; - -#ifdef IXL_DEBUG - device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " - "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", - hw->pf_id, hw->func_caps.num_vfs, - hw->func_caps.num_msix_vectors, - hw->func_caps.num_msix_vectors_vf, - hw->func_caps.fd_filters_guaranteed, - hw->func_caps.fd_filters_best_effort, - hw->func_caps.num_tx_qp, - hw->func_caps.num_rx_qp, - hw->func_caps.base_queue); -#endif - struct i40e_osdep *osdep = (struct i40e_osdep *)hw->back; - osdep->i2c_intfc_num = ixl_find_i2c_interface(pf); - if (osdep->i2c_intfc_num != -1) + /* + * Some devices have both MDIO and I2C; since this isn't reported + * by the FW, check registers to see if an I2C interface exists. + */ + i2c_intfc_num = ixl_find_i2c_interface(pf); + if (i2c_intfc_num != -1) pf->has_i2c = true; + /* Determine functions to use for driver I2C accesses */ + switch (pf->i2c_access_method) { + case 0: { + if (hw->mac.type == I40E_MAC_XL710 && + hw->aq.api_maj_ver == 1 && + hw->aq.api_min_ver >= 7) { + pf->read_i2c_byte = ixl_read_i2c_byte_aq; + pf->write_i2c_byte = ixl_write_i2c_byte_aq; + } else { + pf->read_i2c_byte = ixl_read_i2c_byte_reg; + pf->write_i2c_byte = ixl_write_i2c_byte_reg; + } + break; + } + case 3: + pf->read_i2c_byte = ixl_read_i2c_byte_aq; + pf->write_i2c_byte = ixl_write_i2c_byte_aq; + break; + case 2: + pf->read_i2c_byte = ixl_read_i2c_byte_reg; + pf->write_i2c_byte = ixl_write_i2c_byte_reg; + break; + case 1: + pf->read_i2c_byte = ixl_read_i2c_byte_bb; + pf->write_i2c_byte = ixl_write_i2c_byte_bb; + break; + default: + /* Should not happen */ + device_printf(dev, "Error setting I2C access functions\n"); + break; + } + /* Print a subset of the capability information. */ device_printf(dev, "PF-ID[%d]: VFs %d, MSIX %d, VF MSIX %d, QPs %d, %s\n", hw->pf_id, hw->func_caps.num_vfs, hw->func_caps.num_msix_vectors, @@ -412,79 +302,7 @@ (hw->func_caps.mdio_port_mode == 1) ? "MDIO dedicated" : "MDIO shared"); - return (error); -} - -void -ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) -{ - device_t dev = vsi->dev; - - /* Enable/disable TXCSUM/TSO4 */ - if (!(ifp->if_capenable & IFCAP_TXCSUM) - && !(ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) { - ifp->if_capenable |= IFCAP_TXCSUM; - /* enable TXCSUM, restore TSO if previously enabled */ - if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { - vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; - ifp->if_capenable |= IFCAP_TSO4; - } - } - else if (mask & IFCAP_TSO4) { - ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); - vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; - device_printf(dev, - "TSO4 requires txcsum, enabling both...\n"); - } - } else if((ifp->if_capenable & IFCAP_TXCSUM) - && !(ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) - ifp->if_capenable &= ~IFCAP_TXCSUM; - else if (mask & IFCAP_TSO4) - ifp->if_capenable |= IFCAP_TSO4; - } else if((ifp->if_capenable & IFCAP_TXCSUM) - && (ifp->if_capenable & IFCAP_TSO4)) { - if (mask & IFCAP_TXCSUM) { - vsi->flags |= IXL_FLAGS_KEEP_TSO4; - ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); - device_printf(dev, - "TSO4 requires txcsum, disabling both...\n"); - } else if (mask & IFCAP_TSO4) - ifp->if_capenable &= ~IFCAP_TSO4; - } - - /* Enable/disable TXCSUM_IPV6/TSO6 */ - if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && !(ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) { - ifp->if_capenable |= IFCAP_TXCSUM_IPV6; - if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { - vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; - ifp->if_capenable |= IFCAP_TSO6; - } - } else if (mask & IFCAP_TSO6) { - ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); - vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; - device_printf(dev, - "TSO6 requires txcsum6, enabling both...\n"); - } - } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && !(ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) - ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; - else if (mask & IFCAP_TSO6) - ifp->if_capenable |= IFCAP_TSO6; - } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) - && (ifp->if_capenable & IFCAP_TSO6)) { - if (mask & IFCAP_TXCSUM_IPV6) { - vsi->flags |= IXL_FLAGS_KEEP_TSO6; - ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); - device_printf(dev, - "TSO6 requires txcsum6, disabling both...\n"); - } else if (mask & IFCAP_TSO6) - ifp->if_capenable &= ~IFCAP_TSO6; - } + return (0); } /* For the set_advertise sysctl */ @@ -522,7 +340,8 @@ status = i40e_shutdown_lan_hmc(hw); if (status) { device_printf(dev, - "init: LAN HMC shutdown failure; status %d\n", status); + "init: LAN HMC shutdown failure; status %s\n", + i40e_stat_str(hw, status)); goto err_out; } } @@ -532,7 +351,8 @@ status = i40e_shutdown_adminq(hw); if (status) device_printf(dev, - "init: Admin Queue shutdown failure; status %d\n", status); + "init: Admin Queue shutdown failure; status %s\n", + i40e_stat_str(hw, status)); err_out: return (status); @@ -543,7 +363,7 @@ { struct i40e_hw *hw = &pf->hw; device_t dev = pf->dev; - u8 set_fc_err_mask; + u32 reg; int error = 0; // XXX: clear_hw() actually writes to hw registers -- maybe this isn't necessary @@ -565,6 +385,7 @@ i40e_clear_pxe_mode(hw); +#if 0 error = ixl_get_hw_capabilities(pf); if (error) { device_printf(dev, "init: Error retrieving HW capabilities;" @@ -636,95 +457,65 @@ err_out: return (error); +#endif + // TODO: Fix second parameter + ixl_rebuild_hw_structs_after_reset(pf, false); + + /* The PF reset should have cleared any critical errors */ + atomic_clear_32(&pf->state, IXL_PF_STATE_PF_CRIT_ERR); + atomic_clear_32(&pf->state, IXL_PF_STATE_PF_RESET_REQ); + + reg = rd32(hw, I40E_PFINT_ICR0_ENA); + reg |= IXL_ICR0_CRIT_ERR_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, reg); + + err_out: + return (error); } /* -** MSIX Interrupt Handlers and Tasklets -*/ -void -ixl_handle_que(void *context, int pending) -{ - struct ixl_queue *que = context; - struct ixl_vsi *vsi = que->vsi; - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - struct i40e_hw *hw = vsi->hw; - struct tx_ring *txr = &que->txr; - struct ifnet *ifp = vsi->ifp; - bool more; - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - more = ixl_rxeof(que, IXL_RX_LIMIT); - IXL_TX_LOCK(txr); - ixl_txeof(que); - if (!drbr_empty(ifp, txr->br)) - ixl_mq_start_locked(ifp, txr); - IXL_TX_UNLOCK(txr); - if (more) { - taskqueue_enqueue(que->tq, &que->task); - return; - } - } - - /* Re-enable queue interrupt */ - if (pf->msix > 1) - ixl_enable_queue(hw, que->me); - else - ixl_enable_intr0(hw); -} - - -/********************************************************************* - * - * Legacy Interrupt Service routine - * - **********************************************************************/ -void + * TODO: Make sure this properly handles admin queue / single rx queue intr + */ +int ixl_intr(void *arg) { struct ixl_pf *pf = arg; struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; - struct ixl_queue *que = vsi->queues; - struct ifnet *ifp = vsi->ifp; - struct tx_ring *txr = &que->txr; + struct ixl_rx_queue *que = vsi->rx_queues; u32 icr0; - bool more; - pf->admin_irq++; + // pf->admin_irq++ + ++que->irqs; +// TODO: Check against proper field +#if 0 /* Clear PBA at start of ISR if using legacy interrupts */ if (pf->msix == 0) wr32(hw, I40E_PFINT_DYN_CTL0, I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)); +#endif icr0 = rd32(hw, I40E_PFINT_ICR0); #ifdef PCI_IOV if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) - taskqueue_enqueue(pf->tq, &pf->vflr_task); + iflib_iov_intr_deferred(vsi->ctx); #endif + // TODO!: Do the stuff that's done in ixl_msix_adminq here, too! if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) - taskqueue_enqueue(pf->tq, &pf->adminq); - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - ++que->irqs; - - more = ixl_rxeof(que, IXL_RX_LIMIT); - - IXL_TX_LOCK(txr); - ixl_txeof(que); - if (!drbr_empty(vsi->ifp, txr->br)) - ixl_mq_start_locked(ifp, txr); - IXL_TX_UNLOCK(txr); - - if (more) - taskqueue_enqueue(que->tq, &que->task); - } - + iflib_admin_intr_deferred(vsi->ctx); + + // TODO: Is intr0 enabled somewhere else? ixl_enable_intr0(hw); + + if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) + return (FILTER_SCHEDULE_THREAD); + else + return (FILTER_HANDLED); } @@ -733,43 +524,17 @@ * MSIX VSI Interrupt Service routine * **********************************************************************/ -void +int ixl_msix_que(void *arg) { - struct ixl_queue *que = arg; - struct ixl_vsi *vsi = que->vsi; - struct i40e_hw *hw = vsi->hw; - struct tx_ring *txr = &que->txr; - bool more_tx, more_rx; - - /* Protect against spurious interrupts */ - if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) - return; + struct ixl_rx_queue *que = arg; ++que->irqs; - more_rx = ixl_rxeof(que, IXL_RX_LIMIT); - - IXL_TX_LOCK(txr); - more_tx = ixl_txeof(que); - /* - ** Make certain that if the stack - ** has anything queued the task gets - ** scheduled to handle it. - */ - if (!drbr_empty(vsi->ifp, txr->br)) - more_tx = 1; - IXL_TX_UNLOCK(txr); - ixl_set_queue_rx_itr(que); - ixl_set_queue_tx_itr(que); + // ixl_set_queue_tx_itr(que); - if (more_tx || more_rx) - taskqueue_enqueue(que->tq, &que->task); - else - ixl_enable_queue(hw, que->me); - - return; + return (FILTER_SCHEDULE_THREAD); } @@ -778,7 +543,7 @@ * MSIX Admin Queue Interrupt Service routine * **********************************************************************/ -void +int ixl_msix_adminq(void *arg) { struct ixl_pf *pf = arg; @@ -787,23 +552,29 @@ u32 reg, mask, rstat_reg; bool do_task = FALSE; + DDPRINTF(dev, "begin"); + ++pf->admin_irq; reg = rd32(hw, I40E_PFINT_ICR0); + // For masking off interrupt causes that need to be handled before + // they can be re-enabled mask = rd32(hw, I40E_PFINT_ICR0_ENA); /* Check on the cause */ if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) { - mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK; + mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK; do_task = TRUE; } if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) { - ixl_handle_mdd_event(pf); - mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK; + mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; + atomic_set_32(&pf->state, IXL_PF_STATE_MDD_PENDING); + do_task = TRUE; } if (reg & I40E_PFINT_ICR0_GRST_MASK) { + mask &= ~I40E_PFINT_ICR0_ENA_GRST_MASK; device_printf(dev, "Reset Requested!\n"); rstat_reg = rd32(hw, I40E_GLGEN_RSTAT); rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK) @@ -819,20 +590,39 @@ break; case I40E_RESET_EMPR: printf("EMPR\n"); - atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); break; default: printf("POR\n"); break; } /* overload admin queue task to check reset progress */ + atomic_set_int(&pf->state, IXL_PF_STATE_ADAPTER_RESETTING); do_task = TRUE; } - if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) { - device_printf(dev, "ECC Error detected!\n"); + /* + * PE / PCI / ECC exceptions are all handled in the same way: + * mask out these three causes, then request a PF reset + * + * TODO: I think at least ECC error requires a GLOBR, not PFR + */ + if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) + device_printf(dev, "ECC Error detected!\n"); + if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) + device_printf(dev, "PCI Exception detected!\n"); + if (reg & I40E_PFINT_ICR0_PE_CRITERR_MASK) + device_printf(dev, "Critical Protocol Engine Error detected!\n"); + /* Checks against the conditions above */ + if (reg & IXL_ICR0_CRIT_ERR_MASK) { + mask &= ~IXL_ICR0_CRIT_ERR_MASK; + atomic_set_32(&pf->state, + IXL_PF_STATE_PF_RESET_REQ | IXL_PF_STATE_PF_CRIT_ERR); + do_task = TRUE; } + // TODO: Linux driver never re-enables this interrupt once it has been detected + // Then what is supposed to happen? A PF reset? Should it never happen? + // TODO: Parse out this error into something human readable if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) { reg = rd32(hw, I40E_PFHMC_ERRORINFO); if (reg & I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK) { @@ -844,55 +634,19 @@ } } - if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) { - device_printf(dev, "PCI Exception detected!\n"); - } - #ifdef PCI_IOV if (reg & I40E_PFINT_ICR0_VFLR_MASK) { mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; - taskqueue_enqueue(pf->tq, &pf->vflr_task); + atomic_set_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ); + do_task = TRUE; } #endif + wr32(hw, I40E_PFINT_ICR0_ENA, mask); if (do_task) - taskqueue_enqueue(pf->tq, &pf->adminq); + return (FILTER_SCHEDULE_THREAD); else - ixl_enable_intr0(hw); -} - -void -ixl_set_promisc(struct ixl_vsi *vsi) -{ - struct ifnet *ifp = vsi->ifp; - struct i40e_hw *hw = vsi->hw; - int err, mcnt = 0; - bool uni = FALSE, multi = FALSE; - - if (ifp->if_flags & IFF_PROMISC) - uni = multi = TRUE; - else if (ifp->if_flags & IFF_ALLMULTI) - multi = TRUE; - else { /* Need to count the multicast addresses */ - struct ifmultiaddr *ifma; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (mcnt == MAX_MULTICAST_ADDR) { - multi = TRUE; - break; - } - mcnt++; - } - if_maddr_runlock(ifp); - } - - err = i40e_aq_set_vsi_unicast_promiscuous(hw, - vsi->seid, uni, NULL, TRUE); - err = i40e_aq_set_vsi_multicast_promiscuous(hw, - vsi->seid, multi, NULL); - return; + return (FILTER_HANDLED); } /********************************************************************* @@ -947,7 +701,6 @@ } IOCTL_DEBUGOUT("ixl_add_multi: end"); - return; } void @@ -987,36 +740,6 @@ ixl_del_hw_filters(vsi, mcnt); } -/********************************************************************* - * Timer routine - * - * This routine checks for link status, updates statistics, - * and runs the watchdog check. - * - * Only runs when the driver is configured UP and RUNNING. - * - **********************************************************************/ - -void -ixl_local_timer(void *arg) -{ - struct ixl_pf *pf = arg; - - IXL_PF_LOCK_ASSERT(pf); - - /* Fire off the adminq task */ - taskqueue_enqueue(pf->tq, &pf->adminq); - - /* Update stats */ - ixl_update_stats_counters(pf); - - /* Increment stat when a queue shows hung */ - if (ixl_queue_hang_check(&pf->vsi)) - pf->watchdog_events++; - - callout_reset(&pf->timer, hz, ixl_local_timer, pf); -} - void ixl_link_up_msg(struct ixl_pf *pf) { @@ -1053,473 +776,6 @@ ixl_fc_string[1] : ixl_fc_string[0]); } -/* -** Note: this routine updates the OS on the link state -** the real check of the hardware only happens with -** a link interrupt. -*/ -void -ixl_update_link_status(struct ixl_pf *pf) -{ - struct ixl_vsi *vsi = &pf->vsi; - struct ifnet *ifp = vsi->ifp; - device_t dev = pf->dev; - - if (pf->link_up) { - if (vsi->link_active == FALSE) { - vsi->link_active = TRUE; -#if __FreeBSD_version >= 1100000 - ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->link_speed); -#else - if_initbaudrate(ifp, ixl_max_aq_speed_to_value(pf->link_speed)); -#endif - if_link_state_change(ifp, LINK_STATE_UP); - ixl_link_up_msg(pf); -#ifdef PCI_IOV - ixl_broadcast_link_state(pf); -#endif - } - } else { /* Link down */ - if (vsi->link_active == TRUE) { - if (bootverbose) - device_printf(dev, "Link is Down\n"); - if_link_state_change(ifp, LINK_STATE_DOWN); - vsi->link_active = FALSE; -#ifdef PCI_IOV - ixl_broadcast_link_state(pf); -#endif - } - } -} - -/********************************************************************* - * - * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. - * - **********************************************************************/ - -void -ixl_stop_locked(struct ixl_pf *pf) -{ - struct ixl_vsi *vsi = &pf->vsi; - struct ifnet *ifp = vsi->ifp; - - INIT_DEBUGOUT("ixl_stop: begin\n"); - - IXL_PF_LOCK_ASSERT(pf); - -#ifdef IXL_IW - /* Stop iWARP device */ - if (ixl_enable_iwarp && pf->iw_enabled) - ixl_iw_pf_stop(pf); -#endif - - /* Stop the local timer */ - callout_stop(&pf->timer); - - ixl_disable_rings_intr(vsi); - ixl_disable_rings(vsi); - - /* Tell the stack that the interface is no longer active */ - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); -} - -void -ixl_stop(struct ixl_pf *pf) -{ - IXL_PF_LOCK(pf); - ixl_stop_locked(pf); - IXL_PF_UNLOCK(pf); -} - -/********************************************************************* - * - * Setup MSIX Interrupt resources and handlers for the VSI - * - **********************************************************************/ -int -ixl_setup_legacy(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - int error, rid = 0; - - if (pf->msix == 1) - rid = 1; - pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &rid, RF_SHAREABLE | RF_ACTIVE); - if (pf->res == NULL) { - device_printf(dev, "bus_alloc_resource_any() for" - " legacy/msi interrupt\n"); - return (ENXIO); - } - - /* Set the handler function */ - error = bus_setup_intr(dev, pf->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixl_intr, pf, &pf->tag); - if (error) { - pf->res = NULL; - device_printf(dev, "bus_setup_intr() for legacy/msi" - " interrupt handler failed, error %d\n", error); - return (ENXIO); - } - error = bus_describe_intr(dev, pf->res, pf->tag, "irq"); - if (error) { - /* non-fatal */ - device_printf(dev, "bus_describe_intr() for Admin Queue" - " interrupt name failed, error %d\n", error); - } - - return (0); -} - -int -ixl_setup_adminq_tq(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - int error = 0; - - /* Tasklet for Admin Queue interrupts */ - TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); -#ifdef PCI_IOV - /* VFLR Tasklet */ - TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf); -#endif - /* Create and start Admin Queue taskqueue */ - pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT, - taskqueue_thread_enqueue, &pf->tq); - if (!pf->tq) { - device_printf(dev, "taskqueue_create_fast (for AQ) returned NULL!\n"); - return (ENOMEM); - } - error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq", - device_get_nameunit(dev)); - if (error) { - device_printf(dev, "taskqueue_start_threads (for AQ) error: %d\n", - error); - taskqueue_free(pf->tq); - return (error); - } - return (0); -} - -int -ixl_setup_queue_tqs(struct ixl_vsi *vsi) -{ - struct ixl_queue *que = vsi->queues; - device_t dev = vsi->dev; -#ifdef RSS - int cpu_id = 0; - cpuset_t cpu_mask; -#endif - - /* Create queue tasks and start queue taskqueues */ - for (int i = 0; i < vsi->num_queues; i++, que++) { - TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); - TASK_INIT(&que->task, 0, ixl_handle_que, que); - que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, - taskqueue_thread_enqueue, &que->tq); -#ifdef RSS - CPU_SETOF(cpu_id, &cpu_mask); - taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, - &cpu_mask, "%s (bucket %d)", - device_get_nameunit(dev), cpu_id); -#else - taskqueue_start_threads(&que->tq, 1, PI_NET, - "%s (que %d)", device_get_nameunit(dev), que->me); -#endif - } - - return (0); -} - -void -ixl_free_adminq_tq(struct ixl_pf *pf) -{ - if (pf->tq) { - taskqueue_free(pf->tq); - pf->tq = NULL; - } -} - -void -ixl_free_queue_tqs(struct ixl_vsi *vsi) -{ - struct ixl_queue *que = vsi->queues; - - for (int i = 0; i < vsi->num_queues; i++, que++) { - if (que->tq) { - taskqueue_free(que->tq); - que->tq = NULL; - } - } -} - -int -ixl_setup_adminq_msix(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - int rid, error = 0; - - /* Admin IRQ rid is 1, vector is 0 */ - rid = 1; - /* Get interrupt resource from bus */ - pf->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (!pf->res) { - device_printf(dev, "bus_alloc_resource_any() for Admin Queue" - " interrupt failed [rid=%d]\n", rid); - return (ENXIO); - } - /* Then associate interrupt with handler */ - error = bus_setup_intr(dev, pf->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixl_msix_adminq, pf, &pf->tag); - if (error) { - pf->res = NULL; - device_printf(dev, "bus_setup_intr() for Admin Queue" - " interrupt handler failed, error %d\n", error); - return (ENXIO); - } - error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); - if (error) { - /* non-fatal */ - device_printf(dev, "bus_describe_intr() for Admin Queue" - " interrupt name failed, error %d\n", error); - } - pf->admvec = 0; - - return (0); -} - -/* - * Allocate interrupt resources from bus and associate an interrupt handler - * to those for the VSI's queues. - */ -int -ixl_setup_queue_msix(struct ixl_vsi *vsi) -{ - device_t dev = vsi->dev; - struct ixl_queue *que = vsi->queues; - struct tx_ring *txr; - int error, rid, vector = 1; - - /* Queue interrupt vector numbers start at 1 (adminq intr is 0) */ - for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { - int cpu_id = i; - rid = vector + 1; - txr = &que->txr; - que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (!que->res) { - device_printf(dev, "bus_alloc_resource_any() for" - " Queue %d interrupt failed [rid=%d]\n", - que->me, rid); - return (ENXIO); - } - /* Set the handler function */ - error = bus_setup_intr(dev, que->res, - INTR_TYPE_NET | INTR_MPSAFE, NULL, - ixl_msix_que, que, &que->tag); - if (error) { - device_printf(dev, "bus_setup_intr() for Queue %d" - " interrupt handler failed, error %d\n", - que->me, error); - bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); - return (error); - } - error = bus_describe_intr(dev, que->res, que->tag, "q%d", i); - if (error) { - device_printf(dev, "bus_describe_intr() for Queue %d" - " interrupt name failed, error %d\n", - que->me, error); - } - /* Bind the vector to a CPU */ -#ifdef RSS - cpu_id = rss_getcpu(i % rss_getnumbuckets()); -#endif - error = bus_bind_intr(dev, que->res, cpu_id); - if (error) { - device_printf(dev, "bus_bind_intr() for Queue %d" - " to CPU %d failed, error %d\n", - que->me, cpu_id, error); - } - que->msix = vector; - } - - return (0); -} - -/* - * Allocate MSI/X vectors from the OS. - * Returns 0 for legacy, 1 for MSI, >1 for MSIX. - */ -int -ixl_init_msix(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - struct i40e_hw *hw = &pf->hw; -#ifdef IXL_IW -#if __FreeBSD_version >= 1100000 - cpuset_t cpu_set; -#endif -#endif - int auto_max_queues; - int rid, want, vectors, queues, available; -#ifdef IXL_IW - int iw_want=0, iw_vectors; - - pf->iw_msix = 0; -#endif - - /* Override by tuneable */ - if (!pf->enable_msix) - goto no_msix; - - /* First try MSI/X */ - rid = PCIR_BAR(IXL_MSIX_BAR); - pf->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!pf->msix_mem) { - /* May not be enabled */ - device_printf(pf->dev, - "Unable to map MSIX table\n"); - goto no_msix; - } - - available = pci_msix_count(dev); - if (available < 2) { - /* system has msix disabled (0), or only one vector (1) */ - device_printf(pf->dev, "Less than two MSI-X vectors available\n"); - bus_release_resource(dev, SYS_RES_MEMORY, - rid, pf->msix_mem); - pf->msix_mem = NULL; - goto no_msix; - } - - /* Clamp max number of queues based on: - * - # of MSI-X vectors available - * - # of cpus available - * - # of queues that can be assigned to the LAN VSI - */ - auto_max_queues = min(mp_ncpus, available - 1); - if (hw->mac.type == I40E_MAC_X722) - auto_max_queues = min(auto_max_queues, 128); - else - auto_max_queues = min(auto_max_queues, 64); - - /* Override with tunable value if tunable is less than autoconfig count */ - if ((pf->max_queues != 0) && (pf->max_queues <= auto_max_queues)) - queues = pf->max_queues; - /* Use autoconfig amount if that's lower */ - else if ((pf->max_queues != 0) && (pf->max_queues > auto_max_queues)) { - device_printf(dev, "ixl_max_queues (%d) is too large, using " - "autoconfig amount (%d)...\n", - pf->max_queues, auto_max_queues); - queues = auto_max_queues; - } - /* Limit maximum auto-configured queues to 8 if no user value is set */ - else - queues = min(auto_max_queues, 8); - -#ifdef RSS - /* If we're doing RSS, clamp at the number of RSS buckets */ - if (queues > rss_getnumbuckets()) - queues = rss_getnumbuckets(); -#endif - - /* - ** Want one vector (RX/TX pair) per queue - ** plus an additional for the admin queue. - */ - want = queues + 1; - if (want <= available) /* Have enough */ - vectors = want; - else { - device_printf(pf->dev, - "MSIX Configuration Problem, " - "%d vectors available but %d wanted!\n", - available, want); - pf->msix_mem = NULL; - goto no_msix; /* Will go to Legacy setup */ - } - -#ifdef IXL_IW - if (ixl_enable_iwarp && hw->func_caps.iwarp) { -#if __FreeBSD_version >= 1100000 - if(bus_get_cpus(dev, INTR_CPUS, sizeof(cpu_set), &cpu_set) == 0) - { - iw_want = min(CPU_COUNT(&cpu_set), IXL_IW_MAX_MSIX); - } -#endif - if(!iw_want) - iw_want = min(mp_ncpus, IXL_IW_MAX_MSIX); - if(ixl_limit_iwarp_msix > 0) - iw_want = min(iw_want, ixl_limit_iwarp_msix); - else - iw_want = min(iw_want, 1); - - available -= vectors; - if (available > 0) { - iw_vectors = (available >= iw_want) ? - iw_want : available; - vectors += iw_vectors; - } else - iw_vectors = 0; - } -#endif - - ixl_set_msix_enable(dev); - if (pci_alloc_msix(dev, &vectors) == 0) { - device_printf(pf->dev, - "Using MSIX interrupts with %d vectors\n", vectors); - pf->msix = vectors; -#ifdef IXL_IW - if (ixl_enable_iwarp && hw->func_caps.iwarp) - { - pf->iw_msix = iw_vectors; - device_printf(pf->dev, - "Reserving %d MSIX interrupts for iWARP CEQ and AEQ\n", - iw_vectors); - } -#endif - - pf->vsi.num_queues = queues; -#ifdef RSS - /* - * If we're doing RSS, the number of queues needs to - * match the number of RSS buckets that are configured. - * - * + If there's more queues than RSS buckets, we'll end - * up with queues that get no traffic. - * - * + If there's more RSS buckets than queues, we'll end - * up having multiple RSS buckets map to the same queue, - * so there'll be some contention. - */ - if (queues != rss_getnumbuckets()) { - device_printf(dev, - "%s: queues (%d) != RSS buckets (%d)" - "; performance will be impacted.\n", - __func__, queues, rss_getnumbuckets()); - } -#endif - return (vectors); - } -no_msix: - vectors = pci_msi_count(dev); - pf->vsi.num_queues = 1; - pf->max_queues = 1; - if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) - device_printf(pf->dev, "Using an MSI interrupt\n"); - else { - vectors = 0; - device_printf(pf->dev, "Using a Legacy interrupt\n"); - } - return (vectors); -} - /* * Configure admin queue/misc interrupt cause registers in hardware. */ @@ -1561,19 +817,28 @@ /* * Configure queue interrupt cause registers in hardware. + * + * Linked list for each vector LNKLSTN(i) -> RQCTL(i) -> TQCTL(i) -> EOL */ void ixl_configure_queue_intr_msix(struct ixl_pf *pf) { - struct i40e_hw *hw = &pf->hw; + struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; u32 reg; u16 vector = 1; - for (int i = 0; i < vsi->num_queues; i++, vector++) { + // TODO: See if max is really necessary + for (int i = 0; i < max(vsi->num_rx_queues, vsi->num_tx_queues); i++, vector++) { + /* Make sure interrupt is disabled */ wr32(hw, I40E_PFINT_DYN_CTLN(i), 0); - /* First queue type is RX / 0 */ - wr32(hw, I40E_PFINT_LNKLSTN(i), i); + /* Set linked list head to point to corresponding RX queue + * e.g. vector 1 (LNKLSTN register 0) points to queue pair 0's RX queue */ + reg = ((i << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) + & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK) | + ((I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) + & I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK); + wr32(hw, I40E_PFINT_LNKLSTN(i), reg); reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | @@ -1592,18 +857,17 @@ } /* - * Configure for MSI single vector operation + * Configure for single interrupt vector operation */ void ixl_configure_legacy(struct ixl_pf *pf) { struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; - struct ixl_queue *que = vsi->queues; - struct rx_ring *rxr = &que->rxr; - struct tx_ring *txr = &que->txr; u32 reg; +// TODO: Fix +#if 0 /* Configure ITR */ vsi->tx_itr_setting = pf->tx_itr; wr32(hw, I40E_PFINT_ITR0(IXL_TX_ITR), @@ -1614,6 +878,9 @@ wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), vsi->rx_itr_setting); rxr->itr = vsi->rx_itr_setting; + /* XXX: Assuming only 1 queue in single interrupt mode */ +#endif + vsi->rx_queues[0].rxr.itr = vsi->rx_itr_setting; /* Setup "other" causes */ reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK @@ -1646,151 +913,28 @@ wr32(hw, I40E_QINT_TQCTL(0), reg); } -int -ixl_allocate_pci_resources(struct ixl_pf *pf) -{ - int rid; - struct i40e_hw *hw = &pf->hw; - device_t dev = pf->dev; - - /* Map BAR0 */ - rid = PCIR_BAR(0); - pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE); - - if (!(pf->pci_mem)) { - device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); - return (ENXIO); - } - /* Ensure proper PCI device operation */ - ixl_set_busmaster(dev); - - /* Save off the PCI information */ - hw->vendor_id = pci_get_vendor(dev); - hw->device_id = pci_get_device(dev); - hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); - hw->subsystem_vendor_id = - pci_read_config(dev, PCIR_SUBVEND_0, 2); - hw->subsystem_device_id = - pci_read_config(dev, PCIR_SUBDEV_0, 2); - - hw->bus.device = pci_get_slot(dev); - hw->bus.func = pci_get_function(dev); - - /* Save off register access information */ - pf->osdep.mem_bus_space_tag = - rman_get_bustag(pf->pci_mem); - pf->osdep.mem_bus_space_handle = - rman_get_bushandle(pf->pci_mem); - pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); - pf->osdep.flush_reg = I40E_GLGEN_STAT; - pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; - - pf->hw.back = &pf->osdep; - - return (0); -} - -/* - * Teardown and release the admin queue/misc vector - * interrupt. - */ -int -ixl_teardown_adminq_msix(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - int rid, error = 0; - - if (pf->admvec) /* we are doing MSIX */ - rid = pf->admvec + 1; - else - (pf->msix != 0) ? (rid = 1):(rid = 0); - - if (pf->tag != NULL) { - bus_teardown_intr(dev, pf->res, pf->tag); - if (error) { - device_printf(dev, "bus_teardown_intr() for" - " interrupt 0 failed\n"); - // return (ENXIO); - } - pf->tag = NULL; - } - if (pf->res != NULL) { - bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); - if (error) { - device_printf(dev, "bus_release_resource() for" - " interrupt 0 failed [rid=%d]\n", rid); - // return (ENXIO); - } - pf->res = NULL; - } - - return (0); -} - -int -ixl_teardown_queue_msix(struct ixl_vsi *vsi) -{ - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - struct ixl_queue *que = vsi->queues; - device_t dev = vsi->dev; - int rid, error = 0; - - /* We may get here before stations are setup */ - if ((pf->msix < 2) || (que == NULL)) - return (0); - - /* Release all MSIX queue resources */ - for (int i = 0; i < vsi->num_queues; i++, que++) { - rid = que->msix + 1; - if (que->tag != NULL) { - error = bus_teardown_intr(dev, que->res, que->tag); - if (error) { - device_printf(dev, "bus_teardown_intr() for" - " Queue %d interrupt failed\n", - que->me); - // return (ENXIO); - } - que->tag = NULL; - } - if (que->res != NULL) { - error = bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); - if (error) { - device_printf(dev, "bus_release_resource() for" - " Queue %d interrupt failed [rid=%d]\n", - que->me, rid); - // return (ENXIO); - } - que->res = NULL; - } - } - - return (0); -} - void ixl_free_pci_resources(struct ixl_pf *pf) { - device_t dev = pf->dev; - int memrid; + struct ixl_vsi *vsi = &pf->vsi; + device_t dev = iflib_get_dev(vsi->ctx); + struct ixl_rx_queue *rx_que = vsi->rx_queues; - ixl_teardown_queue_msix(&pf->vsi); - ixl_teardown_adminq_msix(pf); + /* We may get here before stations are setup */ + if (rx_que == NULL) + goto early; - if (pf->msix > 0) - pci_release_msi(dev); - - memrid = PCIR_BAR(IXL_MSIX_BAR); - - if (pf->msix_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - memrid, pf->msix_mem); + /* + ** Release all msix VSI resources: + */ + iflib_irq_free(vsi->ctx, &vsi->irq); + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) + iflib_irq_free(vsi->ctx, &rx_que->que_irq); +early: if (pf->pci_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), pf->pci_mem); - - return; } void @@ -1798,73 +942,73 @@ { /* Display supported media types */ if (phy_types & (I40E_CAP_PHY_TYPE_100BASE_TX)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_T)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_SX)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_LX)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_XAUI) || phy_types & (I40E_CAP_PHY_TYPE_XFI) || phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_LR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_T)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4) || phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4_CU) || phy_types & (I40E_CAP_PHY_TYPE_40GBASE_AOC) || phy_types & (I40E_CAP_PHY_TYPE_XLAUI) || phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_SR4)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_LR4)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_KX)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1_CU) || phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_AOC)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_AOC, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_AOC, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_SFI)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KX4)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_20GBASE_KR2)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_XLPPI)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_KR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_KR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_KR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_CR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_CR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_CR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_SR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_SR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_SR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_LR)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_LR, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_LR, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_AOC)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_AOC, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_AOC, 0, NULL); if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_ACC)) - ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_ACC, 0, NULL); + ifmedia_add(vsi->media, IFM_ETHER | IFM_25G_ACC, 0, NULL); } /********************************************************************* @@ -1873,66 +1017,29 @@ * **********************************************************************/ int -ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) +ixl_setup_interface(device_t dev, struct ixl_pf *pf) { - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - struct ifnet *ifp; - struct i40e_hw *hw = vsi->hw; - struct ixl_queue *que = vsi->queues; + struct ixl_vsi *vsi = &pf->vsi; + if_ctx_t ctx = vsi->ctx; + struct i40e_hw *hw = &pf->hw; + struct ifnet *ifp = iflib_get_ifp(ctx); struct i40e_aq_get_phy_abilities_resp abilities; enum i40e_status_code aq_error = 0; - INIT_DEBUGOUT("ixl_setup_interface: begin"); + uint64_t cap; - ifp = vsi->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - device_printf(dev, "can not allocate ifnet structure\n"); - return (-1); - } - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_mtu = ETHERMTU; - ifp->if_init = ixl_init; - ifp->if_softc = vsi; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ixl_ioctl; + INIT_DBG_DEV(dev, "begin"); -#if __FreeBSD_version >= 1100036 - if_setgetcounterfn(ifp, ixl_get_counter); -#endif - - ifp->if_transmit = ixl_mq_start; - - ifp->if_qflush = ixl_qflush; - - ifp->if_snd.ifq_maxlen = que->num_tx_desc - 2; - - vsi->max_frame_size = + /* initialize fast path functions */ + cap = IXL_CAPS; + if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); + if_setcapabilitiesbit(ifp, cap, 0); + if_setcapenable(ifp, if_getcapabilities(ifp)); + /* TODO: Remove VLAN_ENCAP_LEN? */ + vsi->shared->isc_max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN; - /* Set TSO limits */ - ifp->if_hw_tsomax = IP_MAXPACKET - (ETHER_HDR_LEN + ETHER_CRC_LEN); - ifp->if_hw_tsomaxsegcount = IXL_MAX_TSO_SEGS; - ifp->if_hw_tsomaxsegsize = IXL_MAX_DMA_SEG_SIZE; - - /* - * Tell the upper layer(s) we support long frames. - */ - ifp->if_hdrlen = sizeof(struct ether_vlan_header); - - ifp->if_capabilities |= IFCAP_HWCSUM; - ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; - ifp->if_capabilities |= IFCAP_TSO; - ifp->if_capabilities |= IFCAP_JUMBO_MTU; - ifp->if_capabilities |= IFCAP_LRO; - - /* VLAN capabilties */ - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING - | IFCAP_VLAN_HWTSO - | IFCAP_VLAN_MTU - | IFCAP_VLAN_HWCSUM; - ifp->if_capenable = ifp->if_capabilities; - /* ** Don't turn this on by default, if vlans are ** created on another pseudo device (eg. lagg) @@ -1941,19 +1048,13 @@ ** using vlans directly on the ixl driver you can ** enable this and get full hardware tag filtering. */ - ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; - - /* - * Specify the media types supported by this adapter and register - * callbacks to update media and link information - */ - ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, - ixl_media_status); + if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWFILTER, 0); aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities, NULL); /* May need delay to detect fiber correctly */ if (aq_error == I40E_ERR_UNKNOWN_PHY) { + /* TODO: Maybe just retry this in a task... */ i40e_msec_delay(200); aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities, NULL); @@ -1968,7 +1069,7 @@ } else { pf->supported_speeds = abilities.link_speed; #if __FreeBSD_version >= 1100000 - ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->supported_speeds); + if_setbaudrate(ifp, ixl_max_aq_speed_to_value(pf->supported_speeds)); #else if_initbaudrate(ifp, ixl_max_aq_speed_to_value(pf->supported_speeds)); #endif @@ -1977,10 +1078,8 @@ } /* Use autoselect media by default */ - ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); - ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); - - ether_ifattach(ifp, hw->mac.addr); + ifmedia_add(vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(vsi->media, IFM_ETHER | IFM_AUTO); return (0); } @@ -1991,8 +1090,8 @@ void ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e) { - struct i40e_hw *hw = &pf->hw; - device_t dev = pf->dev; + struct i40e_hw *hw = &pf->hw; + device_t dev = iflib_get_dev(pf->vsi.ctx); struct i40e_aqc_get_link_status *status = (struct i40e_aqc_get_link_status *)&e->desc.params.raw; @@ -2008,8 +1107,7 @@ device_printf(dev, "Link failed because " "an unqualified module was detected!\n"); - /* Update OS link info */ - ixl_update_link_status(pf); + /* OS link info is updated elsewhere */ } /********************************************************************* @@ -2024,7 +1122,7 @@ { struct i40e_hw *hw = &pf->hw; struct ixl_vsi *vsi = &pf->vsi; - device_t dev = vsi->dev; + device_t dev = iflib_get_dev(vsi->ctx); struct i40e_aqc_get_switch_config_resp *sw_config; u8 aq_buf[I40E_AQ_LARGE_BUF]; int ret; @@ -2069,9 +1167,11 @@ int ixl_initialize_vsi(struct ixl_vsi *vsi) { - struct ixl_pf *pf = vsi->back; - struct ixl_queue *que = vsi->queues; - device_t dev = vsi->dev; + struct ixl_pf *pf = vsi->back; + if_softc_ctx_t scctx = iflib_get_softc_ctx(vsi->ctx); + struct ixl_tx_queue *tx_que = vsi->tx_queues; + struct ixl_rx_queue *rx_que = vsi->rx_queues; + device_t dev = iflib_get_dev(vsi->ctx); struct i40e_hw *hw = vsi->hw; struct i40e_vsi_context ctxt; int tc_queues; @@ -2110,7 +1210,7 @@ * queue allocation at queue 0, and assign it 2^tc_queues queues (though * the driver may not use all of them). */ - tc_queues = bsrl(pf->qtag.num_allocated); + tc_queues = fls(pf->qtag.num_allocated) - 1; ctxt.info.tc_mapping[0] = ((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) & I40E_AQ_VSI_TC_QUE_OFFSET_MASK) | ((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) @@ -2119,6 +1219,7 @@ /* Set VLAN receive stripping mode */ ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; + // TODO: Call function to get this cap bit, instead if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; else @@ -2150,20 +1251,16 @@ return (err); } - for (int i = 0; i < vsi->num_queues; i++, que++) { - struct tx_ring *txr = &que->txr; - struct rx_ring *rxr = &que->rxr; + for (int i = 0; i < vsi->num_tx_queues; i++, tx_que++) { + struct tx_ring *txr = &tx_que->txr; struct i40e_hmc_obj_txq tctx; - struct i40e_hmc_obj_rxq rctx; u32 txctl; - u16 size; /* Setup the HMC TX Context */ - size = que->num_tx_desc * sizeof(struct i40e_tx_desc); bzero(&tctx, sizeof(tctx)); tctx.new_context = 1; - tctx.base = (txr->dma.pa/IXL_TX_CTX_BASE_UNITS); - tctx.qlen = que->num_tx_desc; + tctx.base = (txr->tx_paddr/IXL_TX_CTX_BASE_UNITS); + tctx.qlen = scctx->isc_ntxd[0]; tctx.fc_ena = 0; /* Disable FCoE */ /* * This value needs to pulled from the VSI that this queue @@ -2177,8 +1274,11 @@ */ if (vsi->enable_head_writeback) { tctx.head_wb_ena = 1; - tctx.head_wb_addr = txr->dma.pa + - (que->num_tx_desc * sizeof(struct i40e_tx_desc)); + tctx.head_wb_addr = txr->tx_paddr + + (scctx->isc_ntxd[0] * sizeof(struct i40e_tx_desc)); + } else { + tctx.head_wb_ena = 0; + tctx.head_wb_addr = 0; } tctx.rdylist_act = 0; err = i40e_clear_lan_tx_queue_context(hw, i); @@ -2199,10 +1299,14 @@ ixl_flush(hw); /* Do ring (re)init */ - ixl_init_tx_ring(que); + ixl_init_tx_ring(vsi, tx_que); + } + for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) { + struct rx_ring *rxr = &rx_que->rxr; + struct i40e_hmc_obj_rxq rctx; /* Next setup the HMC RX Context */ - if (vsi->max_frame_size <= MCLBYTES) + if (scctx->isc_max_frame_size <= MCLBYTES) rxr->mbuf_sz = MCLBYTES; else rxr->mbuf_sz = MJUMPAGESIZE; @@ -2214,18 +1318,18 @@ rctx.dbuff = rxr->mbuf_sz >> I40E_RXQ_CTX_DBUFF_SHIFT; /* ignore header split for now */ rctx.hbuff = 0 >> I40E_RXQ_CTX_HBUFF_SHIFT; - rctx.rxmax = (vsi->max_frame_size < max_rxmax) ? - vsi->max_frame_size : max_rxmax; + rctx.rxmax = (scctx->isc_max_frame_size < max_rxmax) ? + scctx->isc_max_frame_size : max_rxmax; rctx.dtype = 0; rctx.dsize = 1; /* do 32byte descriptors */ rctx.hsplit_0 = 0; /* no header split */ - rctx.base = (rxr->dma.pa/IXL_RX_CTX_BASE_UNITS); - rctx.qlen = que->num_rx_desc; + rctx.base = (rxr->rx_paddr/IXL_RX_CTX_BASE_UNITS); + rctx.qlen = scctx->isc_nrxd[0]; rctx.tphrdesc_ena = 1; rctx.tphwdesc_ena = 1; rctx.tphdata_ena = 0; /* Header Split related */ rctx.tphhead_ena = 0; /* Header Split related */ - rctx.lrxqthresh = 2; /* Interrupt at <128 desc avail */ + rctx.lrxqthresh = 1; /* Interrupt at <64 desc avail */ rctx.crcstrip = 1; rctx.l2tsel = 1; rctx.showiv = 1; /* Strip inner VLAN header */ @@ -2243,82 +1347,11 @@ device_printf(dev, "Unable to set RX context %d\n", i); break; } - err = ixl_init_rx_ring(que); - if (err) { - device_printf(dev, "Fail in init_rx_ring %d\n", i); - break; - } -#ifdef DEV_NETMAP - /* preserve queue */ - if (vsi->ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(vsi->ifp); - struct netmap_kring *kring = na->rx_rings[i]; - int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); - wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); - } else -#endif /* DEV_NETMAP */ - wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_rx_desc - 1); + wr32(vsi->hw, I40E_QRX_TAIL(i), 0); } return (err); } - - - -void -ixl_vsi_free_queues(struct ixl_vsi *vsi) -{ - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - struct ixl_queue *que = vsi->queues; - - if (NULL == vsi->queues) - return; - - for (int i = 0; i < vsi->num_queues; i++, que++) { - struct tx_ring *txr = &que->txr; - struct rx_ring *rxr = &que->rxr; - - if (!mtx_initialized(&txr->mtx)) /* uninitialized */ - continue; - IXL_TX_LOCK(txr); - if (txr->br) - buf_ring_free(txr->br, M_DEVBUF); - ixl_free_que_tx(que); - if (txr->base) - i40e_free_dma_mem(&pf->hw, &txr->dma); - IXL_TX_UNLOCK(txr); - IXL_TX_LOCK_DESTROY(txr); - - if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ - continue; - IXL_RX_LOCK(rxr); - ixl_free_que_rx(que); - if (rxr->base) - i40e_free_dma_mem(&pf->hw, &rxr->dma); - IXL_RX_UNLOCK(rxr); - IXL_RX_LOCK_DESTROY(rxr); - } -} - - -/********************************************************************* - * - * Free all VSI structs. - * - **********************************************************************/ -void -ixl_free_vsi(struct ixl_vsi *vsi) -{ - - /* Free station queues */ - ixl_vsi_free_queues(vsi); - if (vsi->queues) - free(vsi->queues, M_DEVBUF); - - /* Free VSI filter list */ - ixl_free_mac_filters(vsi); -} - void ixl_free_mac_filters(struct ixl_vsi *vsi) { @@ -2331,179 +1364,12 @@ } } -/* - * Fill out fields in queue struct and setup tx/rx memory and structs - */ -static int -ixl_vsi_setup_queue(struct ixl_vsi *vsi, struct ixl_queue *que, int index) -{ - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - device_t dev = pf->dev; - struct i40e_hw *hw = &pf->hw; - struct tx_ring *txr = &que->txr; - struct rx_ring *rxr = &que->rxr; - int error = 0; - int rsize, tsize; - - que->num_tx_desc = vsi->num_tx_desc; - que->num_rx_desc = vsi->num_rx_desc; - que->me = index; - que->vsi = vsi; - - txr->que = que; - txr->tail = I40E_QTX_TAIL(que->me); - - /* Initialize the TX lock */ - snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", - device_get_nameunit(dev), que->me); - mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); - /* - * Create the TX descriptor ring - * - * In Head Writeback mode, the descriptor ring is one bigger - * than the number of descriptors for space for the HW to - * write back index of last completed descriptor. - */ - if (vsi->enable_head_writeback) { - tsize = roundup2((que->num_tx_desc * - sizeof(struct i40e_tx_desc)) + - sizeof(u32), DBA_ALIGN); - } else { - tsize = roundup2((que->num_tx_desc * - sizeof(struct i40e_tx_desc)), DBA_ALIGN); - } - if (i40e_allocate_dma_mem(hw, - &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { - device_printf(dev, - "Unable to allocate TX Descriptor memory\n"); - error = ENOMEM; - goto err_destroy_tx_mtx; - } - txr->base = (struct i40e_tx_desc *)txr->dma.va; - bzero((void *)txr->base, tsize); - /* Now allocate transmit soft structs for the ring */ - if (ixl_allocate_tx_data(que)) { - device_printf(dev, - "Critical Failure setting up TX structures\n"); - error = ENOMEM; - goto err_free_tx_dma; - } - /* Allocate a buf ring */ - txr->br = buf_ring_alloc(DEFAULT_TXBRSZ, M_DEVBUF, - M_NOWAIT, &txr->mtx); - if (txr->br == NULL) { - device_printf(dev, - "Critical Failure setting up TX buf ring\n"); - error = ENOMEM; - goto err_free_tx_data; - } - - rsize = roundup2(que->num_rx_desc * - sizeof(union i40e_rx_desc), DBA_ALIGN); - rxr->que = que; - rxr->tail = I40E_QRX_TAIL(que->me); - - /* Initialize the RX side lock */ - snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", - device_get_nameunit(dev), que->me); - mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); - - if (i40e_allocate_dma_mem(hw, - &rxr->dma, i40e_mem_reserved, rsize, 4096)) { - device_printf(dev, - "Unable to allocate RX Descriptor memory\n"); - error = ENOMEM; - goto err_destroy_rx_mtx; - } - rxr->base = (union i40e_rx_desc *)rxr->dma.va; - bzero((void *)rxr->base, rsize); - /* Allocate receive soft structs for the ring*/ - if (ixl_allocate_rx_data(que)) { - device_printf(dev, - "Critical Failure setting up receive structs\n"); - error = ENOMEM; - goto err_free_rx_dma; - } - - return (0); - -err_free_rx_dma: - i40e_free_dma_mem(&pf->hw, &rxr->dma); -err_destroy_rx_mtx: - mtx_destroy(&rxr->mtx); - /* err_free_tx_buf_ring */ - buf_ring_free(txr->br, M_DEVBUF); -err_free_tx_data: - ixl_free_que_tx(que); -err_free_tx_dma: - i40e_free_dma_mem(&pf->hw, &txr->dma); -err_destroy_tx_mtx: - mtx_destroy(&txr->mtx); - - return (error); -} - -int -ixl_vsi_setup_queues(struct ixl_vsi *vsi) -{ - struct ixl_queue *que; - int error = 0; - - for (int i = 0; i < vsi->num_queues; i++) { - que = &vsi->queues[i]; - error = ixl_vsi_setup_queue(vsi, que, i); - if (error) - break; - } - return (error); -} - - -/********************************************************************* - * - * Allocate memory for the VSI (virtual station interface) and their - * associated queues, rings and the descriptors associated with each, - * called only once at attach. - * - **********************************************************************/ -int -ixl_setup_stations(struct ixl_pf *pf) -{ - device_t dev = pf->dev; - struct ixl_vsi *vsi; - int error = 0; - - vsi = &pf->vsi; - vsi->back = (void *)pf; - vsi->hw = &pf->hw; - vsi->id = 0; - vsi->num_vlans = 0; - vsi->back = pf; - - if (pf->msix > 1) - vsi->flags |= IXL_FLAGS_USES_MSIX; - - /* Get memory for the station queues */ - if (!(vsi->queues = - (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * - vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate queue memory\n"); - error = ENOMEM; - goto ixl_setup_stations_err; - } - - /* Then setup each queue */ - error = ixl_vsi_setup_queues(vsi); -ixl_setup_stations_err: - return (error); -} - /* ** Provide a update to the queue RX ** interrupt moderation value. */ void -ixl_set_queue_rx_itr(struct ixl_queue *que) +ixl_set_queue_rx_itr(struct ixl_rx_queue *que) { struct ixl_vsi *vsi = que->vsi; struct ixl_pf *pf = (struct ixl_pf *)vsi->back; @@ -2554,7 +1420,7 @@ ((9 * rx_itr) + rxr->itr); rxr->itr = min(rx_itr, IXL_MAX_ITR); wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, - que->me), rxr->itr); + rxr->me), rxr->itr); } } else { /* We may have have toggled to non-dynamic */ if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) @@ -2563,12 +1429,11 @@ if (rxr->itr != vsi->rx_itr_setting) { rxr->itr = vsi->rx_itr_setting; wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, - que->me), rxr->itr); + rxr->me), rxr->itr); } } rxr->bytes = 0; rxr->packets = 0; - return; } @@ -2577,7 +1442,7 @@ ** interrupt moderation value. */ void -ixl_set_queue_tx_itr(struct ixl_queue *que) +ixl_set_queue_tx_itr(struct ixl_tx_queue *que) { struct ixl_vsi *vsi = que->vsi; struct ixl_pf *pf = (struct ixl_pf *)vsi->back; @@ -2628,7 +1493,7 @@ ((9 * tx_itr) + txr->itr); txr->itr = min(tx_itr, IXL_MAX_ITR); wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, - que->me), txr->itr); + txr->me), txr->itr); } } else { /* We may have have toggled to non-dynamic */ @@ -2638,7 +1503,7 @@ if (txr->itr != vsi->tx_itr_setting) { txr->itr = vsi->tx_itr_setting; wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, - que->me), txr->itr); + txr->me), txr->itr); } } txr->bytes = 0; @@ -2669,17 +1534,17 @@ * Retrieves I40E_QTX_TAIL value from hardware * for a sysctl. */ -static int +int ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) { - struct ixl_queue *que; + struct ixl_tx_queue *tx_que; int error; u32 val; - que = ((struct ixl_queue *)oidp->oid_arg1); - if (!que) return 0; + tx_que = ((struct ixl_tx_queue *)oidp->oid_arg1); + if (!tx_que) return 0; - val = rd32(que->vsi->hw, que->txr.tail); + val = rd32(tx_que->vsi->hw, tx_que->txr.tail); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) return error; @@ -2691,17 +1556,17 @@ * Retrieves I40E_QRX_TAIL value from hardware * for a sysctl. */ -static int +int ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) { - struct ixl_queue *que; + struct ixl_rx_queue *rx_que; int error; u32 val; - que = ((struct ixl_queue *)oidp->oid_arg1); - if (!que) return 0; + rx_que = ((struct ixl_rx_queue *)oidp->oid_arg1); + if (!rx_que) return 0; - val = rd32(que->vsi->hw, que->rxr.tail); + val = rd32(rx_que->vsi->hw, rx_que->rxr.tail); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) return error; @@ -2780,22 +1645,21 @@ void ixl_add_hw_stats(struct ixl_pf *pf) { - device_t dev = pf->dev; struct ixl_vsi *vsi = &pf->vsi; - struct ixl_queue *queues = vsi->queues; + device_t dev = iflib_get_dev(vsi->ctx); struct i40e_hw_port_stats *pf_stats = &pf->stats; struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); - struct sysctl_oid_list *vsi_list; - + struct sysctl_oid_list *vsi_list, *queue_list; struct sysctl_oid *queue_node; - struct sysctl_oid_list *queue_list; + char queue_namebuf[32]; + struct ixl_rx_queue *rx_que; + struct ixl_tx_queue *tx_que; struct tx_ring *txr; struct rx_ring *rxr; - char queue_namebuf[QUEUE_NAME_LEN]; /* Driver statistics */ SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events", @@ -2809,81 +1673,68 @@ vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); /* Queue statistics */ - for (int q = 0; q < vsi->num_queues; q++) { - snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); + for (int q = 0; q < vsi->num_rx_queues; q++) { + snprintf(queue_namebuf, QUEUE_NAME_LEN, "rxq%02d", q); queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, - OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); + OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "RX Queue #"); queue_list = SYSCTL_CHILDREN(queue_node); - txr = &(queues[q].txr); - rxr = &(queues[q].rxr); + rx_que = &(vsi->rx_queues[q]); + rxr = &(rx_que->rxr); + - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", - CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), - "m_defrag() failed"); SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", - CTLFLAG_RD, &(queues[q].irqs), - "irqs on this queue"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", - CTLFLAG_RD, &(queues[q].tso), - "TSO"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dmamap_failed", - CTLFLAG_RD, &(queues[q].tx_dmamap_failed), - "Driver tx dma failure in xmit"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small", - CTLFLAG_RD, &(queues[q].mss_too_small), - "TSO sends with an MSS less than 64"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", - CTLFLAG_RD, &(txr->no_desc), - "Queue No Descriptor Available"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", - CTLFLAG_RD, &(txr->total_packets), - "Queue Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", - CTLFLAG_RD, &(txr->tx_bytes), - "Queue Bytes Transmitted"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", + CTLFLAG_RD, &(rx_que->irqs), + "irqs on this queue (both Tx and Rx)"); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets", CTLFLAG_RD, &(rxr->rx_packets), "Queue Packets Received"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes", CTLFLAG_RD, &(rxr->rx_bytes), "Queue Bytes Received"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_desc_err", + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "desc_err", CTLFLAG_RD, &(rxr->desc_errs), "Queue Rx Descriptor Errors"); - SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr", + SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr", CTLFLAG_RD, &(rxr->itr), 0, "Queue Rx ITR Interval"); - SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr", +#ifdef IXL_DEBUG + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail", + CTLTYPE_UINT | CTLFLAG_RD, rx_que, + sizeof(struct ixl_rx_queue), + ixl_sysctl_qrx_tail_handler, "IU", + "Queue Receive Descriptor Tail"); +#endif + } + for (int q = 0; q < vsi->num_tx_queues; q++) { + snprintf(queue_namebuf, QUEUE_NAME_LEN, "txq%02d", q); + queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, + OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "TX Queue #"); + queue_list = SYSCTL_CHILDREN(queue_node); + + tx_que = &(vsi->tx_queues[q]); + txr = &(tx_que->txr); + + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso", + CTLFLAG_RD, &(tx_que->tso), + "TSO"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small", + CTLFLAG_RD, &(txr->mss_too_small), + "TSO sends with an MSS less than 64"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "packets", + CTLFLAG_RD, &(txr->tx_packets), + "Queue Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "bytes", + CTLFLAG_RD, &(txr->tx_bytes), + "Queue Bytes Transmitted"); + SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "itr", CTLFLAG_RD, &(txr->itr), 0, "Queue Tx ITR Interval"); #ifdef IXL_DEBUG - SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "txr_watchdog", - CTLFLAG_RD, &(txr->watchdog_timer), 0, - "Ticks before watchdog timer causes interface reinit"); - SYSCTL_ADD_U16(ctx, queue_list, OID_AUTO, "tx_next_avail", - CTLFLAG_RD, &(txr->next_avail), 0, - "Next TX descriptor to be used"); - SYSCTL_ADD_U16(ctx, queue_list, OID_AUTO, "tx_next_to_clean", - CTLFLAG_RD, &(txr->next_to_clean), 0, - "Next TX descriptor to be cleaned"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_not_done", - CTLFLAG_RD, &(rxr->not_done), - "Queue Rx Descriptors not Done"); - SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_refresh", - CTLFLAG_RD, &(rxr->next_refresh), 0, - "Queue Rx Descriptors not Done"); - SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_check", - CTLFLAG_RD, &(rxr->next_check), 0, - "Queue Rx Descriptors not Done"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail", - CTLTYPE_UINT | CTLFLAG_RD, &queues[q], - sizeof(struct ixl_queue), - ixl_sysctl_qrx_tail_handler, "IU", - "Queue Receive Descriptor Tail"); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail", - CTLTYPE_UINT | CTLFLAG_RD, &queues[q], - sizeof(struct ixl_queue), + CTLTYPE_UINT | CTLFLAG_RD, tx_que, + sizeof(struct ixl_tx_queue), ixl_sysctl_qtx_tail_handler, "IU", "Queue Transmit Descriptor Tail"); #endif @@ -3063,8 +1914,8 @@ ixl_set_rss_hlut(struct ixl_pf *pf) { struct i40e_hw *hw = &pf->hw; - device_t dev = pf->dev; struct ixl_vsi *vsi = &pf->vsi; + device_t dev = iflib_get_dev(vsi->ctx); int i, que_id; int lut_entry_width; u32 lut = 0; @@ -3082,9 +1933,9 @@ * num_queues.) */ que_id = rss_get_indirection_to_bucket(i); - que_id = que_id % vsi->num_queues; + que_id = que_id % vsi->num_rx_queues; #else - que_id = i % vsi->num_queues; + que_id = i % vsi->num_rx_queues; #endif lut = (que_id & ((0x1 << lut_entry_width) - 1)); hlut_buf[i] = lut; @@ -3113,56 +1964,6 @@ ixl_set_rss_hlut(pf); } -/* -** This routine is run via an vlan config EVENT, -** it enables us to use the HW Filter table since -** we can get the vlan id. This just creates the -** entry in the soft version of the VFTA, init will -** repopulate the real table. -*/ -void -ixl_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct i40e_hw *hw = vsi->hw; - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - - if (ifp->if_softc != arg) /* Not our event */ - return; - - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ - return; - - IXL_PF_LOCK(pf); - ++vsi->num_vlans; - ixl_add_filter(vsi, hw->mac.addr, vtag); - IXL_PF_UNLOCK(pf); -} - -/* -** This routine is run via an vlan -** unconfig EVENT, remove our entry -** in the soft vfta. -*/ -void -ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct i40e_hw *hw = vsi->hw; - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - - if (ifp->if_softc != arg) - return; - - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ - return; - - IXL_PF_LOCK(pf); - --vsi->num_vlans; - ixl_del_filter(vsi, hw->mac.addr, vtag); - IXL_PF_UNLOCK(pf); -} - /* ** This routine updates vlan filters, called by init ** it scans the filter table and then updates the hw @@ -3196,7 +1997,30 @@ flags = IXL_FILTER_VLAN; flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); ixl_add_hw_filters(vsi, flags, cnt); - return; +} + +/* + * In some firmware versions there is default MAC/VLAN filter + * configured which interferes with filters managed by driver. + * Make sure it's removed. + */ +static void +ixl_del_default_hw_filters(struct ixl_vsi *vsi) +{ + struct i40e_aqc_remove_macvlan_element_data e; + + bzero(&e, sizeof(e)); + bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN); + e.vlan_tag = 0; + e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; + i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL); + + bzero(&e, sizeof(e)); + bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN); + e.vlan_tag = 0; + e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | + I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; + i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL); } /* @@ -3210,9 +2034,15 @@ { struct ixl_pf *pf = (struct ixl_pf *)vsi->back; - /* Add broadcast address */ - ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); + /* Initialize mac filter list for VSI */ + SLIST_INIT(&vsi->ftl); + /* Receive broadcast Ethernet frames */ + i40e_aq_set_vsi_broadcast(&pf->hw, vsi->seid, TRUE, NULL); + + ixl_del_default_hw_filters(vsi); + + ixl_add_filter(vsi, vsi->hw->mac.addr, IXL_VLAN_ANY); /* * Prevent Tx flow control frames from being sent out by * non-firmware transmitters. @@ -3235,15 +2065,11 @@ if (f != NULL) return; - f = ixl_get_filter(vsi); - if (f == NULL) { + f = ixl_new_filter(vsi, macaddr, IXL_VLAN_ANY); + if (f != NULL) + f->flags |= IXL_FILTER_MC; + else printf("WARNING: no filter available!!\n"); - return; - } - bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); - f->vlan = IXL_VLAN_ANY; - f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED - | IXL_FILTER_MC); return; } @@ -3286,14 +2112,11 @@ } } - f = ixl_get_filter(vsi); + f = ixl_new_filter(vsi, macaddr, vlan); if (f == NULL) { device_printf(dev, "WARNING: no filter available!!\n"); return; } - bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); - f->vlan = vlan; - f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); if (f->vlan != IXL_VLAN_ANY) f->flags |= IXL_FILTER_VLAN; else @@ -3314,7 +2137,8 @@ f->flags |= IXL_FILTER_DEL; ixl_del_hw_filters(vsi, 1); - vsi->num_macs--; + if (f->vlan == IXL_VLAN_ANY && (f->flags & IXL_FILTER_VLAN) != 0) + vsi->num_macs--; /* Check if this is the last vlan removal */ if (vlan != IXL_VLAN_ANY && vsi->num_vlans == 0) { @@ -3332,20 +2156,15 @@ ixl_find_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan) { struct ixl_mac_filter *f; - bool match = FALSE; SLIST_FOREACH(f, &vsi->ftl, next) { - if (!cmp_etheraddr(f->macaddr, macaddr)) - continue; - if (f->vlan == vlan) { - match = TRUE; - break; + if ((cmp_etheraddr(f->macaddr, macaddr) != 0) + && (f->vlan == vlan)) { + return (f); } } - if (!match) - f = NULL; - return (f); + return (NULL); } /* @@ -3361,12 +2180,14 @@ struct ixl_pf *pf; struct i40e_hw *hw; device_t dev; - int err, j = 0; + enum i40e_status_code status; + int j = 0; + + MPASS(cnt > 0); pf = vsi->back; - dev = pf->dev; + dev = iflib_get_dev(vsi->ctx); hw = &pf->hw; - IXL_PF_LOCK_ASSERT(pf); a = malloc(sizeof(struct i40e_aqc_add_macvlan_element_data) * cnt, M_DEVBUF, M_NOWAIT | M_ZERO); @@ -3399,10 +2220,11 @@ break; } if (j > 0) { - err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); - if (err) - device_printf(dev, "aq_add_macvlan err %d, " - "aq_error %d\n", err, hw->aq.asq_last_status); + status = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); + if (status) + device_printf(dev, "i40e_aq_add_macvlan status %s, " + "error %s\n", i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); else vsi->hw_filters_add += j; } @@ -3423,18 +2245,17 @@ struct i40e_hw *hw; device_t dev; struct ixl_mac_filter *f, *f_temp; - int err, j = 0; - - DEBUGOUT("ixl_del_hw_filters: begin\n"); + enum i40e_status_code status; + int j = 0; pf = vsi->back; hw = &pf->hw; - dev = pf->dev; + dev = iflib_get_dev(vsi->ctx); d = malloc(sizeof(struct i40e_aqc_remove_macvlan_element_data) * cnt, M_DEVBUF, M_NOWAIT | M_ZERO); if (d == NULL) { - printf("del hw filter failed to get memory\n"); + device_printf(dev, "%s: failed to get memory\n", __func__); return; } @@ -3458,21 +2279,19 @@ break; } if (j > 0) { - err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); - if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { + status = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); + if (status) { int sc = 0; for (int i = 0; i < j; i++) sc += (!d[i].error_code); vsi->hw_filters_del += sc; device_printf(dev, - "Failed to remove %d/%d filters, aq error %d\n", - j - sc, j, hw->aq.asq_last_status); + "Failed to remove %d/%d filters, error %s\n", + j - sc, j, i40e_aq_str(hw, hw->aq.asq_last_status)); } else vsi->hw_filters_del += j; } free(d, M_DEVBUF); - - DEBUGOUT("ixl_del_hw_filters: end\n"); return; } @@ -3566,11 +2385,11 @@ struct ixl_pf *pf = vsi->back; int error = 0; - for (int i = 0; i < vsi->num_queues; i++) { - error = ixl_enable_ring(pf, &pf->qtag, i); - if (error) - return (error); - } + for (int i = 0; i < vsi->num_tx_queues; i++) + error = ixl_enable_tx_ring(pf, &pf->qtag, i); + + for (int i = 0; i < vsi->num_rx_queues; i++) + error = ixl_enable_rx_ring(pf, &pf->qtag, i); return (error); } @@ -3662,11 +2481,11 @@ struct ixl_pf *pf = vsi->back; int error = 0; - for (int i = 0; i < vsi->num_queues; i++) { - error = ixl_disable_ring(pf, &pf->qtag, i); - if (error) - return (error); - } + for (int i = 0; i < vsi->num_tx_queues; i++) + error = ixl_disable_tx_ring(pf, &pf->qtag, i); + + for (int i = 0; i < vsi->num_rx_queues; i++) + error = ixl_disable_rx_ring(pf, &pf->qtag, i); return (error); } @@ -3682,8 +2501,10 @@ { struct i40e_hw *hw = &pf->hw; device_t dev = pf->dev; + struct ixl_vf *vf; bool mdd_detected = false; bool pf_mdd_detected = false; + bool vf_mdd_detected = false; u32 reg; /* find what triggered the MDD event */ @@ -3735,6 +2556,39 @@ } } + if (pf_mdd_detected) { + atomic_set_32(&pf->state, IXL_PF_STATE_PF_RESET_REQ); + goto end; + } + + // Handle VF detection + for (int i = 0; i < pf->num_vfs && mdd_detected; i++) { + vf = &(pf->vfs[i]); + reg = rd32(hw, I40E_VP_MDET_TX(i)); + if (reg & I40E_VP_MDET_TX_VALID_MASK) { + wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF); + vf->num_mdd_events++; + device_printf(dev, "MDD TX event is for VF %d\n", i); + vf_mdd_detected = true; + } + + reg = rd32(hw, I40E_VP_MDET_RX(i)); + if (reg & I40E_VP_MDET_RX_VALID_MASK) { + wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF); + vf->num_mdd_events++; + device_printf(dev, "MDD RX event is for VF %d\n", i); + vf_mdd_detected = true; + } + + // TODO: Disable VF if there are too many MDD events from it + } + + if (vf_mdd_detected) + atomic_set_32(&pf->state, IXL_PF_STATE_VF_RESET_REQ); + +end: + atomic_clear_32(&pf->state, IXL_PF_STATE_MDD_PENDING); + /* re-enable mdd interrupt cause */ reg = rd32(hw, I40E_PFINT_ICR0_ENA); reg |= I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK; @@ -3742,16 +2596,17 @@ ixl_flush(hw); } +/* This only enables HW interrupts for the RX queues */ void ixl_enable_intr(struct ixl_vsi *vsi) { - struct ixl_pf *pf = (struct ixl_pf *)vsi->back; struct i40e_hw *hw = vsi->hw; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *que = vsi->rx_queues; - if (pf->msix > 1) { - for (int i = 0; i < vsi->num_queues; i++, que++) - ixl_enable_queue(hw, que->me); + // TODO: Check iflib interrupt mode instead? + if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + ixl_enable_queue(hw, que->rxr.me); } else ixl_enable_intr0(hw); } @@ -3760,10 +2615,10 @@ ixl_disable_rings_intr(struct ixl_vsi *vsi) { struct i40e_hw *hw = vsi->hw; - struct ixl_queue *que = vsi->queues; + struct ixl_rx_queue *que = vsi->rx_queues; - for (int i = 0; i < vsi->num_queues; i++, que++) - ixl_disable_queue(hw, que->me); + for (int i = 0; i < vsi->num_rx_queues; i++, que++) + ixl_disable_queue(hw, que->rxr.me); } void @@ -3988,39 +2843,22 @@ ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up) { struct i40e_hw *hw = &pf->hw; - struct ixl_vsi *vsi = &pf->vsi; device_t dev = pf->dev; int error = 0; - /* Teardown */ - if (is_up) - ixl_stop(pf); - - ixl_teardown_queue_msix(vsi); - error = i40e_shutdown_lan_hmc(hw); if (error) device_printf(dev, "Shutdown LAN HMC failed with code %d\n", error); ixl_disable_intr0(hw); - ixl_teardown_adminq_msix(pf); error = i40e_shutdown_adminq(hw); if (error) device_printf(dev, "Shutdown Admin queue failed with code %d\n", error); - callout_drain(&pf->timer); - - /* Free ring buffers, locks and filters */ - ixl_vsi_free_queues(vsi); - - /* Free VSI filter list */ - ixl_free_mac_filters(vsi); - ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag); - return (error); } @@ -4071,16 +2909,13 @@ } /* reserve a contiguous allocation for the PF's VSI */ - error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); + error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_tx_queues, &pf->qtag); if (error) { device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", error); /* TODO: error handling */ } - device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", - pf->qtag.num_allocated, pf->qtag.num_active); - error = ixl_switch_config(pf); if (error) { device_printf(dev, "ixl_rebuild_hw_structs_after_reset: ixl_switch_config() failed: %d\n", @@ -4088,37 +2923,8 @@ goto ixl_rebuild_hw_structs_after_reset_err; } - if (ixl_vsi_setup_queues(vsi)) { - device_printf(dev, "setup queues failed!\n"); - error = ENOMEM; - goto ixl_rebuild_hw_structs_after_reset_err; - } - - if (pf->msix > 1) { - error = ixl_setup_adminq_msix(pf); - if (error) { - device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", - error); - goto ixl_rebuild_hw_structs_after_reset_err; - } - - ixl_configure_intr0_msix(pf); - ixl_enable_intr0(hw); - - error = ixl_setup_queue_msix(vsi); - if (error) { - device_printf(dev, "ixl_setup_queue_msix() error: %d\n", - error); - goto ixl_rebuild_hw_structs_after_reset_err; - } - } else { - error = ixl_setup_legacy(pf); - if (error) { - device_printf(dev, "ixl_setup_legacy() error: %d\n", - error); - goto ixl_rebuild_hw_structs_after_reset_err; - } - } + /* Remove default filters reinstalled by FW on reset */ + ixl_del_default_hw_filters(vsi); /* Determine link state */ if (ixl_attach_get_link_status(pf)) { @@ -4129,8 +2935,11 @@ i40e_aq_set_dcb_parameters(hw, TRUE, NULL); ixl_get_fw_lldp_status(pf); - if (is_up) - ixl_init(pf); + /* Keep admin queue interrupts active while driver is loaded */ + if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { + ixl_configure_intr0_msix(pf); + ixl_enable_intr0(hw); + } device_printf(dev, "Rebuilding driver state done.\n"); return (0); @@ -4161,81 +2970,11 @@ break; } ixl_dbg(pf, IXL_DBG_INFO, - "EMPR reset wait count: %d\n", count); + "Reset wait count: %d\n", count); ixl_rebuild_hw_structs_after_reset(pf, is_up); - atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); -} - -/* -** Tasklet handler for MSIX Adminq interrupts -** - do outside interrupt since it might sleep -*/ -void -ixl_do_adminq(void *context, int pending) -{ - struct ixl_pf *pf = context; - struct i40e_hw *hw = &pf->hw; - struct i40e_arq_event_info event; - i40e_status ret; - device_t dev = pf->dev; - u32 loop = 0; - u16 opcode, result; - - if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { - /* Flag cleared at end of this function */ - ixl_handle_empr_reset(pf); - return; - } - - /* Admin Queue handling */ - event.buf_len = IXL_AQ_BUF_SZ; - event.msg_buf = malloc(event.buf_len, - M_DEVBUF, M_NOWAIT | M_ZERO); - if (!event.msg_buf) { - device_printf(dev, "%s: Unable to allocate memory for Admin" - " Queue event!\n", __func__); - return; - } - - IXL_PF_LOCK(pf); - /* clean and process any events */ - do { - ret = i40e_clean_arq_element(hw, &event, &result); - if (ret) - break; - opcode = LE16_TO_CPU(event.desc.opcode); - ixl_dbg(pf, IXL_DBG_AQ, - "Admin Queue event: %#06x\n", opcode); - switch (opcode) { - case i40e_aqc_opc_get_link_status: - ixl_link_event(pf, &event); - break; - case i40e_aqc_opc_send_msg_to_pf: -#ifdef PCI_IOV - ixl_handle_vf_msg(pf, &event); -#endif - break; - case i40e_aqc_opc_event_lan_overflow: - default: - break; - } - - } while (result && (loop++ < IXL_ADM_LIMIT)); - - free(event.msg_buf, M_DEVBUF); - - /* - * If there are still messages to process, reschedule ourselves. - * Otherwise, re-enable our interrupt. - */ - if (result > 0) - taskqueue_enqueue(pf->tq, &pf->adminq); - else - ixl_enable_intr0(hw); - - IXL_PF_UNLOCK(pf); + atomic_clear_int(&pf->state, IXL_PF_STATE_ADAPTER_RESETTING); } /** @@ -4317,8 +3056,6 @@ ixl_update_eth_stats(vsi); tx_discards = es->tx_discards + nsd->tx_dropped_link_down; - for (int i = 0; i < vsi->num_queues; i++) - tx_discards += vsi->queues[i].txr.br->br_drops; /* Update ifnet stats */ IXL_SET_IPACKETS(vsi, es->rx_unicast + @@ -4476,14 +3213,6 @@ OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, &pf->dynamic_tx_itr, 0, "Enable dynamic TX ITR"); - SYSCTL_ADD_INT(ctx, ctx_list, - OID_AUTO, "tx_ring_size", CTLFLAG_RD, - &pf->vsi.num_tx_desc, 0, "TX ring size"); - - SYSCTL_ADD_INT(ctx, ctx_list, - OID_AUTO, "rx_ring_size", CTLFLAG_RD, - &pf->vsi.num_rx_desc, 0, "RX ring size"); - /* Add FEC sysctls for 25G adapters */ if (i40e_is_25G_device(hw->device_id)) { fec_node = SYSCTL_ADD_NODE(ctx, ctx_list, @@ -4527,7 +3256,7 @@ SYSCTL_ADD_UINT(ctx, debug_list, OID_AUTO, "core_debug_mask", CTLFLAG_RW, - &pf->dbg_mask, 0, "Non-hared code debug message level"); + &pf->dbg_mask, 0, "Non-shared code debug message level"); SYSCTL_ADD_PROC(ctx, debug_list, OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD, @@ -4569,14 +3298,39 @@ OID_AUTO, "dump_debug_data", CTLTYPE_STRING | CTLFLAG_RD, pf, 0, ixl_sysctl_dump_debug_data, "A", "Dump Debug Data from FW"); + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "do_pf_reset", CTLTYPE_INT | CTLFLAG_WR, + pf, 0, ixl_sysctl_do_pf_reset, "I", "Tell HW to initiate a PF reset"); + + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "do_core_reset", CTLTYPE_INT | CTLFLAG_WR, + pf, 0, ixl_sysctl_do_core_reset, "I", "Tell HW to initiate a CORE reset"); + + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "do_global_reset", CTLTYPE_INT | CTLFLAG_WR, + pf, 0, ixl_sysctl_do_global_reset, "I", "Tell HW to initiate a GLOBAL reset"); + + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "do_emp_reset", CTLTYPE_INT | CTLFLAG_WR, + pf, 0, ixl_sysctl_do_emp_reset, "I", + "(This doesn't work) Tell HW to initiate a EMP (entire firmware) reset"); + + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "queue_interrupt_table", CTLTYPE_STRING | CTLFLAG_RD, + pf, 0, ixl_sysctl_queue_interrupt_table, "A", "View MSI-X indices for TX/RX queues"); + if (pf->has_i2c) { SYSCTL_ADD_PROC(ctx, debug_list, OID_AUTO, "read_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, - pf, 0, ixl_sysctl_read_i2c_byte, "I", "Read byte from I2C bus"); + pf, 0, ixl_sysctl_read_i2c_byte, "I", IXL_SYSCTL_HELP_READ_I2C); SYSCTL_ADD_PROC(ctx, debug_list, OID_AUTO, "write_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, - pf, 0, ixl_sysctl_write_i2c_byte, "I", "Write byte to I2C bus"); + pf, 0, ixl_sysctl_write_i2c_byte, "I", IXL_SYSCTL_HELP_WRITE_I2C); + + SYSCTL_ADD_PROC(ctx, debug_list, + OID_AUTO, "read_i2c_diag_data", CTLTYPE_STRING | CTLFLAG_RD, + pf, 0, ixl_sysctl_read_i2c_diag_data, "A", "Dump selected diagnostic data from FW"); } #ifdef PCI_IOV @@ -4596,9 +3350,9 @@ struct ixl_pf *pf = (struct ixl_pf *)arg1; int queues; - IXL_PF_LOCK(pf); + //IXL_PF_LOCK(pf); queues = (int)ixl_pf_qmgr_get_num_free(&pf->qmgr); - IXL_PF_UNLOCK(pf); + //IXL_PF_UNLOCK(pf); return sysctl_handle_int(oidp, NULL, queues, req); } @@ -4642,11 +3396,6 @@ } pf->fc = requested_fc; - /* Get new link state */ - i40e_msec_delay(250); - hw->phy.get_link_info = TRUE; - i40e_get_link_status(hw, &pf->link_up); - return (0); } @@ -4855,29 +3604,6 @@ return (0); } -/* - * Input: bitmap of enum i40e_aq_link_speed - */ -static u64 -ixl_max_aq_speed_to_value(u8 link_speeds) -{ - if (link_speeds & I40E_LINK_SPEED_40GB) - return IF_Gbps(40); - if (link_speeds & I40E_LINK_SPEED_25GB) - return IF_Gbps(25); - if (link_speeds & I40E_LINK_SPEED_20GB) - return IF_Gbps(20); - if (link_speeds & I40E_LINK_SPEED_10GB) - return IF_Gbps(10); - if (link_speeds & I40E_LINK_SPEED_1GB) - return IF_Gbps(1); - if (link_speeds & I40E_LINK_SPEED_100MB) - return IF_Mbps(100); - else - /* Minimum supported link speed */ - return IF_Mbps(100); -} - /* ** Get the width and transaction speed of ** the bus this adapter is plugged into. @@ -4960,7 +3686,7 @@ // device_printf(dev, "- Get Driver Status Command\n"); } else if (nvma->command == I40E_NVM_READ) { - + } else { switch (nvma->command) { @@ -5010,19 +3736,20 @@ if (pf->dbg_mask & IXL_DBG_NVMUPD) ixl_print_nvm_cmd(dev, nvma); - if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { + if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING) { int count = 0; while (count++ < 100) { i40e_msec_delay(100); - if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) + if (!(pf->state & IXL_PF_STATE_ADAPTER_RESETTING)) break; } } - if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { - IXL_PF_LOCK(pf); + if (!(pf->state & IXL_PF_STATE_ADAPTER_RESETTING)) { + // TODO: Might need a different lock here + // IXL_PF_LOCK(pf); status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); - IXL_PF_UNLOCK(pf); + // IXL_PF_UNLOCK(pf); } else { perrno = -EBUSY; } @@ -5042,389 +3769,6 @@ return (perrno); } -/********************************************************************* - * - * Media Ioctl callback - * - * This routine is called whenever the user queries the status of - * the interface using ifconfig. - * - * When adding new media types here, make sure to add them to - * ixl_add_ifmedia(), too. - * - **********************************************************************/ -void -ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct ixl_pf *pf = vsi->back; - struct i40e_hw *hw = &pf->hw; - - INIT_DEBUGOUT("ixl_media_status: begin"); - - /* Don't touch PF during reset */ - if (atomic_load_acq_int(&pf->state) & IXL_PF_STATE_EMPR_RESETTING) - return; - - IXL_PF_LOCK(pf); - - i40e_get_link_status(hw, &pf->link_up); - ixl_update_link_status(pf); - - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - if (!pf->link_up) { - IXL_PF_UNLOCK(pf); - return; - } - - ifmr->ifm_status |= IFM_ACTIVE; - - /* Hardware always does full-duplex */ - ifmr->ifm_active |= IFM_FDX; - - switch (hw->phy.link_info.phy_type) { - /* 100 M */ - case I40E_PHY_TYPE_100BASE_TX: - ifmr->ifm_active |= IFM_100_TX; - break; - /* 1 G */ - case I40E_PHY_TYPE_1000BASE_T: - ifmr->ifm_active |= IFM_1000_T; - break; - case I40E_PHY_TYPE_1000BASE_SX: - ifmr->ifm_active |= IFM_1000_SX; - break; - case I40E_PHY_TYPE_1000BASE_LX: - ifmr->ifm_active |= IFM_1000_LX; - break; - case I40E_PHY_TYPE_1000BASE_T_OPTICAL: - ifmr->ifm_active |= IFM_1000_T; - break; - /* 10 G */ - case I40E_PHY_TYPE_10GBASE_SFPP_CU: - ifmr->ifm_active |= IFM_10G_TWINAX; - break; - case I40E_PHY_TYPE_10GBASE_SR: - ifmr->ifm_active |= IFM_10G_SR; - break; - case I40E_PHY_TYPE_10GBASE_LR: - ifmr->ifm_active |= IFM_10G_LR; - break; - case I40E_PHY_TYPE_10GBASE_T: - ifmr->ifm_active |= IFM_10G_T; - break; - case I40E_PHY_TYPE_XAUI: - case I40E_PHY_TYPE_XFI: - ifmr->ifm_active |= IFM_10G_TWINAX; - break; - case I40E_PHY_TYPE_10GBASE_AOC: - ifmr->ifm_active |= IFM_10G_AOC; - break; - /* 25 G */ - case I40E_PHY_TYPE_25GBASE_KR: - ifmr->ifm_active |= IFM_25G_KR; - break; - case I40E_PHY_TYPE_25GBASE_CR: - ifmr->ifm_active |= IFM_25G_CR; - break; - case I40E_PHY_TYPE_25GBASE_SR: - ifmr->ifm_active |= IFM_25G_SR; - break; - case I40E_PHY_TYPE_25GBASE_LR: - ifmr->ifm_active |= IFM_25G_LR; - break; - case I40E_PHY_TYPE_25GBASE_AOC: - ifmr->ifm_active |= IFM_25G_AOC; - break; - case I40E_PHY_TYPE_25GBASE_ACC: - ifmr->ifm_active |= IFM_25G_ACC; - break; - /* 40 G */ - case I40E_PHY_TYPE_40GBASE_CR4: - case I40E_PHY_TYPE_40GBASE_CR4_CU: - ifmr->ifm_active |= IFM_40G_CR4; - break; - case I40E_PHY_TYPE_40GBASE_SR4: - ifmr->ifm_active |= IFM_40G_SR4; - break; - case I40E_PHY_TYPE_40GBASE_LR4: - ifmr->ifm_active |= IFM_40G_LR4; - break; - case I40E_PHY_TYPE_XLAUI: - ifmr->ifm_active |= IFM_OTHER; - break; - case I40E_PHY_TYPE_1000BASE_KX: - ifmr->ifm_active |= IFM_1000_KX; - break; - case I40E_PHY_TYPE_SGMII: - ifmr->ifm_active |= IFM_1000_SGMII; - break; - /* ERJ: What's the difference between these? */ - case I40E_PHY_TYPE_10GBASE_CR1_CU: - case I40E_PHY_TYPE_10GBASE_CR1: - ifmr->ifm_active |= IFM_10G_CR1; - break; - case I40E_PHY_TYPE_10GBASE_KX4: - ifmr->ifm_active |= IFM_10G_KX4; - break; - case I40E_PHY_TYPE_10GBASE_KR: - ifmr->ifm_active |= IFM_10G_KR; - break; - case I40E_PHY_TYPE_SFI: - ifmr->ifm_active |= IFM_10G_SFI; - break; - /* Our single 20G media type */ - case I40E_PHY_TYPE_20GBASE_KR2: - ifmr->ifm_active |= IFM_20G_KR2; - break; - case I40E_PHY_TYPE_40GBASE_KR4: - ifmr->ifm_active |= IFM_40G_KR4; - break; - case I40E_PHY_TYPE_XLPPI: - case I40E_PHY_TYPE_40GBASE_AOC: - ifmr->ifm_active |= IFM_40G_XLPPI; - break; - /* Unknown to driver */ - default: - ifmr->ifm_active |= IFM_UNKNOWN; - break; - } - /* Report flow control status as well */ - if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) - ifmr->ifm_active |= IFM_ETH_TXPAUSE; - if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) - ifmr->ifm_active |= IFM_ETH_RXPAUSE; - - IXL_PF_UNLOCK(pf); -} - -void -ixl_init(void *arg) -{ - struct ixl_pf *pf = arg; - - IXL_PF_LOCK(pf); - ixl_init_locked(pf); - IXL_PF_UNLOCK(pf); -} - -/* - * NOTE: Fortville does not support forcing media speeds. Instead, - * use the set_advertise sysctl to set the speeds Fortville - * will advertise or be allowed to operate at. - */ -int -ixl_media_change(struct ifnet * ifp) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct ifmedia *ifm = &vsi->media; - - INIT_DEBUGOUT("ixl_media_change: begin"); - - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) - return (EINVAL); - - if_printf(ifp, "Use 'advertise_speed' sysctl to change advertised speeds\n"); - - return (ENODEV); -} - -/********************************************************************* - * Ioctl entry point - * - * ixl_ioctl is called when the user wants to configure the - * interface. - * - * return 0 on success, positive on failure - **********************************************************************/ - -int -ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct ixl_pf *pf = vsi->back; - struct ifreq *ifr = (struct ifreq *)data; - struct ifdrv *ifd = (struct ifdrv *)data; -#if defined(INET) || defined(INET6) - struct ifaddr *ifa = (struct ifaddr *)data; - bool avoid_reset = FALSE; -#endif - int error = 0; - - switch (command) { - - case SIOCSIFADDR: - IOCTL_DEBUGOUT("ioctl: SIOCSIFADDR (Set Interface Address)"); -#ifdef INET - if (ifa->ifa_addr->sa_family == AF_INET) - avoid_reset = TRUE; -#endif -#ifdef INET6 - if (ifa->ifa_addr->sa_family == AF_INET6) - avoid_reset = TRUE; -#endif -#if defined(INET) || defined(INET6) - /* - ** Calling init results in link renegotiation, - ** so we avoid doing it when possible. - */ - if (avoid_reset) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - ixl_init(pf); -#ifdef INET - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); -#endif - } else - error = ether_ioctl(ifp, command, data); - break; -#endif - case SIOCSIFMTU: - IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); - if (ifr->ifr_mtu > IXL_MAX_FRAME - - ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { - error = EINVAL; - } else { - IXL_PF_LOCK(pf); - ifp->if_mtu = ifr->ifr_mtu; - vsi->max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN - + ETHER_VLAN_ENCAP_LEN; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ixl_init_locked(pf); - IXL_PF_UNLOCK(pf); - } - break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); - IXL_PF_LOCK(pf); - if (ifp->if_flags & IFF_UP) { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if ((ifp->if_flags ^ pf->if_flags) & - (IFF_PROMISC | IFF_ALLMULTI)) { - ixl_set_promisc(vsi); - } - } else { - IXL_PF_UNLOCK(pf); - ixl_init(pf); - IXL_PF_LOCK(pf); - } - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - ixl_stop_locked(pf); - } - } - pf->if_flags = ifp->if_flags; - IXL_PF_UNLOCK(pf); - break; - case SIOCSDRVSPEC: - case SIOCGDRVSPEC: - IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " - "Info)\n"); - - /* NVM update command */ - if (ifd->ifd_cmd == I40E_NVM_ACCESS) - error = ixl_handle_nvmupd_cmd(pf, ifd); - else - error = EINVAL; - break; - case SIOCADDMULTI: - IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXL_PF_LOCK(pf); - ixl_disable_rings_intr(vsi); - ixl_add_multi(vsi); - ixl_enable_intr(vsi); - IXL_PF_UNLOCK(pf); - } - break; - case SIOCDELMULTI: - IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXL_PF_LOCK(pf); - ixl_disable_rings_intr(vsi); - ixl_del_multi(vsi); - ixl_enable_intr(vsi); - IXL_PF_UNLOCK(pf); - } - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - case SIOCGIFXMEDIA: - IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); - error = ifmedia_ioctl(ifp, ifr, &vsi->media, command); - break; - case SIOCSIFCAP: - { - int mask = ifr->ifr_reqcap ^ ifp->if_capenable; - IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); - - ixl_cap_txcsum_tso(vsi, ifp, mask); - - if (mask & IFCAP_RXCSUM) - ifp->if_capenable ^= IFCAP_RXCSUM; - if (mask & IFCAP_RXCSUM_IPV6) - ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; - if (mask & IFCAP_LRO) - ifp->if_capenable ^= IFCAP_LRO; - if (mask & IFCAP_VLAN_HWTAGGING) - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_VLAN_HWFILTER) - ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; - if (mask & IFCAP_VLAN_HWTSO) - ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - IXL_PF_LOCK(pf); - ixl_init_locked(pf); - IXL_PF_UNLOCK(pf); - } - VLAN_CAPABILITIES(ifp); - - break; - } -#if __FreeBSD_version >= 1003000 - case SIOCGI2C: - { - struct ifi2creq i2c; - int i; - - IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); - if (!pf->has_i2c) - return (ENOTTY); - - error = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c)); - if (error != 0) - break; - if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { - error = EINVAL; - break; - } - if (i2c.len > sizeof(i2c.data)) { - error = EINVAL; - break; - } - - for (i = 0; i < i2c.len; i++) - if (ixl_read_i2c_byte(pf, i2c.offset + i, - i2c.dev_addr, &i2c.data[i])) - return (EIO); - - error = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c)); - break; - } -#endif - default: - IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); - error = ether_ioctl(ifp, command, data); - break; - } - - return (error); -} - int ixl_find_i2c_interface(struct ixl_pf *pf) { @@ -5499,6 +3843,7 @@ return (ext) ? ext_phy_types_str[bit_pos] : phy_types_str[bit_pos]; } +/* TODO: ERJ: I don't this is necessary anymore. */ int ixl_aq_get_link_status(struct ixl_pf *pf, struct i40e_aqc_get_link_status *link_status) { @@ -5567,7 +3912,7 @@ "Power : 0x%02x", link_status.phy_type, ixl_phy_type_string_ls(link_status.phy_type), - link_status.link_speed, + link_status.link_speed, link_status.link_info, link_status.an_info, link_status.ext_info, @@ -5647,7 +3992,7 @@ "ModType E: %01x\n" "FEC Cfg : %02x\n" "Ext CC : %02x", - abilities.link_speed, + abilities.link_speed, abilities.abilities, abilities.eee_capability, abilities.eeer_val, abilities.d3_lpan, abilities.phy_id[0], abilities.phy_id[1], @@ -5689,7 +4034,7 @@ } buf_len = sizeof(char) * (entry_len + 1) * ftl_len + 2; - buf = buf_i = malloc(buf_len, M_DEVBUF, M_NOWAIT); + buf = buf_i = malloc(buf_len, M_DEVBUF, M_WAITOK); sprintf(buf_i++, "\n"); SLIST_FOREACH(f, &vsi->ftl, next) { @@ -5723,12 +4068,13 @@ } /* - * Longest string length: 25 + * Longest string length: 25 */ char * ixl_switch_res_type_string(u8 type) { - static char * ixl_switch_res_type_strings[0x14] = { + // TODO: This should be changed to static const + char * ixl_switch_res_type_strings[0x14] = { "VEB", "VSI", "Perfect Match MAC address", @@ -5823,9 +4169,6 @@ /* ** Caller must init and delete sbuf; this function will clear and ** finish it for caller. -** -** XXX: Cannot use the SEID for this, since there is no longer a -** fixed mapping between SEID and element type. */ char * ixl_switch_element_string(struct sbuf *s, @@ -6134,6 +4477,52 @@ return (0); } +/* + * Read some diagnostic data from an SFP module + * Bytes 96-99, 102-105 from device address 0xA2 + */ +static int +ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + device_t dev = pf->dev; + struct sbuf *sbuf; + int error = 0; + u8 output; + + error = pf->read_i2c_byte(pf, 0, 0xA0, &output); + if (error) { + device_printf(dev, "Error reading from i2c\n"); + return (error); + } + if (output != 0x3) { + device_printf(dev, "Module is not SFP/SFP+/SFP28 (%02X)\n", output); + return (EIO); + } + + pf->read_i2c_byte(pf, 92, 0xA0, &output); + if (!(output & 0x60)) { + device_printf(dev, "Module doesn't support diagnostics: %02X\n", output); + return (EIO); + } + + sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); + + for (u8 offset = 96; offset < 100; offset++) { + pf->read_i2c_byte(pf, offset, 0xA2, &output); + sbuf_printf(sbuf, "%02X ", output); + } + for (u8 offset = 102; offset < 106; offset++) { + pf->read_i2c_byte(pf, offset, 0xA2, &output); + sbuf_printf(sbuf, "%02X ", output); + } + + sbuf_finish(sbuf); + sbuf_delete(sbuf); + + return (0); +} + /* * Sysctl to read a byte from I2C bus. * @@ -6149,9 +4538,6 @@ struct ixl_pf *pf = (struct ixl_pf *)arg1; device_t dev = pf->dev; int input = -1, error = 0; - - device_printf(dev, "%s: start\n", __func__); - u8 dev_addr, offset, output; /* Read in I2C read parameters */ @@ -6165,7 +4551,7 @@ } offset = (input >> 8) & 0xFF; - error = ixl_read_i2c_byte(pf, offset, dev_addr, &output); + error = pf->read_i2c_byte(pf, offset, dev_addr, &output); if (error) return (error); @@ -6189,7 +4575,6 @@ struct ixl_pf *pf = (struct ixl_pf *)arg1; device_t dev = pf->dev; int input = -1, error = 0; - u8 dev_addr, offset, value; /* Read in I2C write parameters */ @@ -6204,7 +4589,7 @@ offset = (input >> 8) & 0xFF; value = (input >> 16) & 0xFF; - error = ixl_write_i2c_byte(pf, offset, dev_addr, value); + error = pf->write_i2c_byte(pf, offset, dev_addr, value); if (error) return (error); @@ -6549,3 +4934,116 @@ i40e_get_link_status(hw, &pf->link_up); return (0); } + +static int +ixl_sysctl_do_pf_reset(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + int requested = 0, error = 0; + + /* Read in new mode */ + error = sysctl_handle_int(oidp, &requested, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* Initiate the PF reset later in the admin task */ + atomic_set_32(&pf->state, IXL_PF_STATE_PF_RESET_REQ); + + return (error); +} + +static int +ixl_sysctl_do_core_reset(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + struct i40e_hw *hw = &pf->hw; + int requested = 0, error = 0; + + /* Read in new mode */ + error = sysctl_handle_int(oidp, &requested, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_CORER_MASK); + + return (error); +} + +static int +ixl_sysctl_do_global_reset(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + struct i40e_hw *hw = &pf->hw; + int requested = 0, error = 0; + + /* Read in new mode */ + error = sysctl_handle_int(oidp, &requested, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_GLOBR_MASK); + + return (error); +} + +static int +ixl_sysctl_do_emp_reset(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + struct i40e_hw *hw = &pf->hw; + int requested = 0, error = 0; + + /* Read in new mode */ + error = sysctl_handle_int(oidp, &requested, 0, req); + if ((error) || (req->newptr == NULL)) + return (error); + + /* TODO: Find out how to bypass this */ + if (!(rd32(hw, 0x000B818C) & 0x1)) { + device_printf(pf->dev, "SW not allowed to initiate EMPR\n"); + error = EINVAL; + } else + wr32(hw, I40E_GLGEN_RTRIG, I40E_GLGEN_RTRIG_EMPFWR_MASK); + + return (error); +} + +/* + * Print out mapping of TX queue indexes and Rx queue indexes + * to MSI-X vectors. + */ +static int +ixl_sysctl_queue_interrupt_table(SYSCTL_HANDLER_ARGS) +{ + struct ixl_pf *pf = (struct ixl_pf *)arg1; + struct ixl_vsi *vsi = &pf->vsi; + device_t dev = pf->dev; + struct sbuf *buf; + int error = 0; + + struct ixl_rx_queue *rx_que = vsi->rx_queues; + struct ixl_tx_queue *tx_que = vsi->tx_queues; + + buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); + if (!buf) { + device_printf(dev, "Could not allocate sbuf for output.\n"); + return (ENOMEM); + } + + sbuf_cat(buf, "\n"); + for (int i = 0; i < vsi->num_rx_queues; i++) { + rx_que = &vsi->rx_queues[i]; + sbuf_printf(buf, "(rxq %3d): %d\n", i, rx_que->msix); + } + for (int i = 0; i < vsi->num_tx_queues; i++) { + tx_que = &vsi->tx_queues[i]; + sbuf_printf(buf, "(txq %3d): %d\n", i, tx_que->msix); + } + + error = sbuf_finish(buf); + if (error) + device_printf(dev, "Error finishing sbuf: %d\n", error); + sbuf_delete(buf); + + return (error); +} Index: sys/dev/ixl/ixl_pf_qmgr.h =================================================================== --- sys/dev/ixl/ixl_pf_qmgr.h +++ sys/dev/ixl/ixl_pf_qmgr.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixl_pf_qmgr.c =================================================================== --- sys/dev/ixl/ixl_pf_qmgr.c +++ sys/dev/ixl/ixl_pf_qmgr.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -83,8 +83,8 @@ qtag->qmgr = qmgr; qtag->type = IXL_PF_QALLOC_CONTIGUOUS; qtag->qidx[0] = block_start; - qtag->num_allocated = num; - qtag->num_active = alloc_size; + qtag->num_allocated = alloc_size; + qtag->num_active = num; return (0); } Index: sys/dev/ixl/ixl_txrx.c =================================================================== --- sys/dev/ixl/ixl_txrx.c +++ sys/dev/ixl/ixl_txrx.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -51,27 +51,43 @@ #endif /* Local Prototypes */ -static void ixl_rx_checksum(struct mbuf *, u32, u32, u8); -static void ixl_refresh_mbufs(struct ixl_queue *, int); -static int ixl_xmit(struct ixl_queue *, struct mbuf **); -static int ixl_tx_setup_offload(struct ixl_queue *, - struct mbuf *, u32 *, u32 *); -static bool ixl_tso_setup(struct ixl_queue *, struct mbuf *); -static void ixl_queue_sw_irq(struct ixl_vsi *, int); +static void ixl_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype); -static inline void ixl_rx_discard(struct rx_ring *, int); -static inline void ixl_rx_input(struct rx_ring *, struct ifnet *, - struct mbuf *, u8); +static int ixl_isc_txd_encap(void *arg, if_pkt_info_t pi); +static void ixl_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx); +static int ixl_isc_txd_credits_update_hwb(void *arg, uint16_t txqid, bool clear); +static int ixl_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear); -static inline bool ixl_tso_detect_sparse(struct mbuf *mp); -static inline u32 ixl_get_tx_head(struct ixl_queue *que); +static void ixl_isc_rxd_refill(void *arg, if_rxd_update_t iru); +static void ixl_isc_rxd_flush(void *arg, uint16_t rxqid, uint8_t flid __unused, + qidx_t pidx); +static int ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, + qidx_t budget); +static int ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri); -#ifdef DEV_NETMAP -#include -#if __FreeBSD_version >= 1200000 -int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip = 1; -#endif -#endif /* DEV_NETMAP */ +extern int ixl_intr(void *arg); + +struct if_txrx ixl_txrx_hwb = { + ixl_isc_txd_encap, + ixl_isc_txd_flush, + ixl_isc_txd_credits_update_hwb, + ixl_isc_rxd_available, + ixl_isc_rxd_pkt_get, + ixl_isc_rxd_refill, + ixl_isc_rxd_flush, + ixl_intr +}; + +struct if_txrx ixl_txrx_dwb = { + ixl_isc_txd_encap, + ixl_isc_txd_flush, + ixl_isc_txd_credits_update_dwb, + ixl_isc_rxd_available, + ixl_isc_rxd_pkt_get, + ixl_isc_rxd_refill, + ixl_isc_rxd_flush, + ixl_intr +}; /* * @key key is saved into this parameter @@ -117,561 +133,70 @@ return hw->err_str; } -/* - * PCI BUSMASTER needs to be set for proper operation. - */ -void -ixl_set_busmaster(device_t dev) +static bool +ixl_is_tx_desc_done(struct tx_ring *txr, int idx) { - u16 pci_cmd_word; - - pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); - pci_cmd_word |= PCIM_CMD_BUSMASTEREN; - pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); + return (((txr->tx_base[idx].cmd_type_offset_bsz >> I40E_TXD_QW1_DTYPE_SHIFT) + & I40E_TXD_QW1_DTYPE_MASK) == I40E_TX_DESC_DTYPE_DESC_DONE); } -/* - * Rewrite the ENABLE bit in the MSIX control register - */ -void -ixl_set_msix_enable(device_t dev) -{ - int msix_ctrl, rid; - - pci_find_cap(dev, PCIY_MSIX, &rid); - rid += PCIR_MSIX_CTRL; - msix_ctrl = pci_read_config(dev, rid, 2); - msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; - pci_write_config(dev, rid, msix_ctrl, 2); -} - - -/* -** Multiqueue Transmit driver -*/ -int -ixl_mq_start(struct ifnet *ifp, struct mbuf *m) -{ - struct ixl_vsi *vsi = ifp->if_softc; - struct ixl_queue *que; - struct tx_ring *txr; - int err, i; -#ifdef RSS - u32 bucket_id; -#endif - - /* - * Which queue to use: - * - * When doing RSS, map it to the same outbound - * queue as the incoming flow would be mapped to. - * If everything is setup correctly, it should be - * the same bucket that the current CPU we're on is. - */ - if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { -#ifdef RSS - if (rss_hash2bucket(m->m_pkthdr.flowid, - M_HASHTYPE_GET(m), &bucket_id) == 0) { - i = bucket_id % vsi->num_queues; - } else -#endif - i = m->m_pkthdr.flowid % vsi->num_queues; - } else - i = curcpu % vsi->num_queues; - - que = &vsi->queues[i]; - txr = &que->txr; - - err = drbr_enqueue(ifp, txr->br, m); - if (err) - return (err); - if (IXL_TX_TRYLOCK(txr)) { - ixl_mq_start_locked(ifp, txr); - IXL_TX_UNLOCK(txr); - } else - taskqueue_enqueue(que->tq, &que->tx_task); - - return (0); -} - -int -ixl_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr) -{ - struct ixl_queue *que = txr->que; - struct ixl_vsi *vsi = que->vsi; - struct mbuf *next; - int err = 0; - - - if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) || - vsi->link_active == 0) - return (ENETDOWN); - - /* Process the transmit queue */ - while ((next = drbr_peek(ifp, txr->br)) != NULL) { - if ((err = ixl_xmit(que, &next)) != 0) { - if (next == NULL) - drbr_advance(ifp, txr->br); - else - drbr_putback(ifp, txr->br, next); - break; - } - drbr_advance(ifp, txr->br); - /* Send a copy of the frame to the BPF listener */ - ETHER_BPF_MTAP(ifp, next); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; - } - - if (txr->avail < IXL_TX_CLEANUP_THRESHOLD) - ixl_txeof(que); - - return (err); -} - -/* - * Called from a taskqueue to drain queued transmit packets. - */ -void -ixl_deferred_mq_start(void *arg, int pending) -{ - struct ixl_queue *que = arg; - struct tx_ring *txr = &que->txr; - struct ixl_vsi *vsi = que->vsi; - struct ifnet *ifp = vsi->ifp; - - IXL_TX_LOCK(txr); - if (!drbr_empty(ifp, txr->br)) - ixl_mq_start_locked(ifp, txr); - IXL_TX_UNLOCK(txr); -} - -/* -** Flush all queue ring buffers -*/ -void -ixl_qflush(struct ifnet *ifp) -{ - struct ixl_vsi *vsi = ifp->if_softc; - - for (int i = 0; i < vsi->num_queues; i++) { - struct ixl_queue *que = &vsi->queues[i]; - struct tx_ring *txr = &que->txr; - struct mbuf *m; - IXL_TX_LOCK(txr); - while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) - m_freem(m); - IXL_TX_UNLOCK(txr); - } - if_qflush(ifp); -} - -static inline bool -ixl_tso_detect_sparse(struct mbuf *mp) -{ - struct mbuf *m; - int num, mss; - - num = 0; - mss = mp->m_pkthdr.tso_segsz; - - /* Exclude first mbuf; assume it contains all headers */ - for (m = mp->m_next; m != NULL; m = m->m_next) { - if (m == NULL) - break; - num++; - mss -= m->m_len % mp->m_pkthdr.tso_segsz; - - if (num > IXL_SPARSE_CHAIN) - return (true); - if (mss < 1) { - num = (mss == 0) ? 0 : 1; - mss += mp->m_pkthdr.tso_segsz; - } - } - - return (false); -} - - -/********************************************************************* - * - * This routine maps the mbufs to tx descriptors, allowing the - * TX engine to transmit the packets. - * - return 0 on success, positive on failure - * - **********************************************************************/ -#define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) - static int -ixl_xmit(struct ixl_queue *que, struct mbuf **m_headp) +ixl_tso_detect_sparse(bus_dma_segment_t *segs, int nsegs, if_pkt_info_t pi) { - struct ixl_vsi *vsi = que->vsi; - struct i40e_hw *hw = vsi->hw; - struct tx_ring *txr = &que->txr; - struct ixl_tx_buf *buf; - struct i40e_tx_desc *txd = NULL; - struct mbuf *m_head, *m; - int i, j, error, nsegs; - int first, last = 0; - u16 vtag = 0; - u32 cmd, off; - bus_dmamap_t map; - bus_dma_tag_t tag; - bus_dma_segment_t segs[IXL_MAX_TSO_SEGS]; + int count, curseg, i, hlen, segsz, seglen, tsolen; - cmd = off = 0; - m_head = *m_headp; + if (nsegs <= IXL_MAX_TX_SEGS-2) + return (0); + segsz = pi->ipi_tso_segsz; + curseg = count = 0; - /* - * Important to capture the first descriptor - * used because it will contain the index of - * the one we tell the hardware to report back - */ - first = txr->next_avail; - buf = &txr->buffers[first]; - map = buf->map; - tag = txr->tx_tag; + hlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen; + tsolen = pi->ipi_len - hlen; - if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { - /* Use larger mapping for TSO */ - tag = txr->tso_tag; - if (ixl_tso_detect_sparse(m_head)) { - m = m_defrag(m_head, M_NOWAIT); - if (m == NULL) { - m_freem(*m_headp); - *m_headp = NULL; - return (ENOBUFS); + i = 0; + curseg = segs[0].ds_len; + while (hlen > 0) { + count++; + if (count > IXL_MAX_TX_SEGS - 2) + return (1); + if (curseg == 0) { + i++; + if (__predict_false(i == nsegs)) + return (1); + + curseg = segs[i].ds_len; + } + seglen = min(curseg, hlen); + curseg -= seglen; + hlen -= seglen; + // printf("H:seglen = %d, count=%d\n", seglen, count); + } + while (tsolen > 0) { + segsz = pi->ipi_tso_segsz; + while (segsz > 0 && tsolen != 0) { + count++; + if (count > IXL_MAX_TX_SEGS - 2) { + // printf("bad: count = %d\n", count); + return (1); } - *m_headp = m; - } - } - - /* - * Map the packet for DMA. - */ - error = bus_dmamap_load_mbuf_sg(tag, map, - *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); - - if (error == EFBIG) { - struct mbuf *m; - - m = m_defrag(*m_headp, M_NOWAIT); - if (m == NULL) { - que->mbuf_defrag_failed++; - m_freem(*m_headp); - *m_headp = NULL; - return (ENOBUFS); - } - *m_headp = m; - - /* Try it again */ - error = bus_dmamap_load_mbuf_sg(tag, map, - *m_headp, segs, &nsegs, BUS_DMA_NOWAIT); - - if (error != 0) { - que->tx_dmamap_failed++; - m_freem(*m_headp); - *m_headp = NULL; - return (error); - } - } else if (error != 0) { - que->tx_dmamap_failed++; - m_freem(*m_headp); - *m_headp = NULL; - return (error); - } - - /* Make certain there are enough descriptors */ - if (nsegs > txr->avail - 2) { - txr->no_desc++; - error = ENOBUFS; - goto xmit_fail; - } - m_head = *m_headp; - - /* Set up the TSO/CSUM offload */ - if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) { - error = ixl_tx_setup_offload(que, m_head, &cmd, &off); - if (error) - goto xmit_fail; - } - - cmd |= I40E_TX_DESC_CMD_ICRC; - /* Grab the VLAN tag */ - if (m_head->m_flags & M_VLANTAG) { - cmd |= I40E_TX_DESC_CMD_IL2TAG1; - vtag = htole16(m_head->m_pkthdr.ether_vtag); - } - - i = txr->next_avail; - for (j = 0; j < nsegs; j++) { - bus_size_t seglen; - - buf = &txr->buffers[i]; - buf->tag = tag; /* Keep track of the type tag */ - txd = &txr->base[i]; - seglen = segs[j].ds_len; - - txd->buffer_addr = htole64(segs[j].ds_addr); - txd->cmd_type_offset_bsz = - htole64(I40E_TX_DESC_DTYPE_DATA - | ((u64)cmd << I40E_TXD_QW1_CMD_SHIFT) - | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT) - | ((u64)seglen << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) - | ((u64)vtag << I40E_TXD_QW1_L2TAG1_SHIFT)); - - last = i; /* descriptor that will get completion IRQ */ - - if (++i == que->num_tx_desc) - i = 0; - - buf->m_head = NULL; - buf->eop_index = -1; - } - /* Set the last descriptor for report */ - txd->cmd_type_offset_bsz |= - htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT)); - txr->avail -= nsegs; - txr->next_avail = i; - - buf->m_head = m_head; - /* Swap the dma map between the first and last descriptor. - * The descriptor that gets checked on completion will now - * have the real map from the first descriptor. - */ - txr->buffers[first].map = buf->map; - buf->map = map; - bus_dmamap_sync(tag, map, BUS_DMASYNC_PREWRITE); - - /* Set the index of the descriptor that will be marked done */ - buf = &txr->buffers[first]; - buf->eop_index = last; - - bus_dmamap_sync(txr->dma.tag, txr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - /* - * Advance the Transmit Descriptor Tail (Tdt), this tells the - * hardware that this frame is available to transmit. - */ - ++txr->total_packets; - wr32(hw, txr->tail, i); - - /* Mark outstanding work */ - atomic_store_rel_32(&txr->watchdog_timer, IXL_WATCHDOG); - return (0); - -xmit_fail: - bus_dmamap_unload(tag, buf->map); - return (error); -} - - -/********************************************************************* - * - * Allocate memory for tx_buffer structures. The tx_buffer stores all - * the information needed to transmit a packet on the wire. This is - * called only once at attach, setup is done every reset. - * - **********************************************************************/ -int -ixl_allocate_tx_data(struct ixl_queue *que) -{ - struct tx_ring *txr = &que->txr; - struct ixl_vsi *vsi = que->vsi; - device_t dev = vsi->dev; - struct ixl_tx_buf *buf; - int i, error = 0; - - /* - * Setup DMA descriptor areas. - */ - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - IXL_TSO_SIZE, /* maxsize */ - IXL_MAX_TX_SEGS, /* nsegments */ - IXL_MAX_DMA_SEG_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &txr->tx_tag))) { - device_printf(dev,"Unable to allocate TX DMA tag\n"); - return (error); - } - - /* Make a special tag for TSO */ - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - IXL_TSO_SIZE, /* maxsize */ - IXL_MAX_TSO_SEGS, /* nsegments */ - IXL_MAX_DMA_SEG_SIZE, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &txr->tso_tag))) { - device_printf(dev,"Unable to allocate TX TSO DMA tag\n"); - goto free_tx_dma; - } - - if (!(txr->buffers = - (struct ixl_tx_buf *) malloc(sizeof(struct ixl_tx_buf) * - que->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate tx_buffer memory\n"); - error = ENOMEM; - goto free_tx_tso_dma; - } - - /* Create the descriptor buffer default dma maps */ - buf = txr->buffers; - for (i = 0; i < que->num_tx_desc; i++, buf++) { - buf->tag = txr->tx_tag; - error = bus_dmamap_create(buf->tag, 0, &buf->map); - if (error != 0) { - device_printf(dev, "Unable to create TX DMA map\n"); - goto free_buffers; - } - } - - return 0; - -free_buffers: - while (i--) { - buf--; - bus_dmamap_destroy(buf->tag, buf->map); - } - - free(txr->buffers, M_DEVBUF); - txr->buffers = NULL; -free_tx_tso_dma: - bus_dma_tag_destroy(txr->tso_tag); - txr->tso_tag = NULL; -free_tx_dma: - bus_dma_tag_destroy(txr->tx_tag); - txr->tx_tag = NULL; - - return (error); -} - - -/********************************************************************* - * - * (Re)Initialize a queue transmit ring. - * - called by init, it clears the descriptor ring, - * and frees any stale mbufs - * - **********************************************************************/ -void -ixl_init_tx_ring(struct ixl_queue *que) -{ -#ifdef DEV_NETMAP - struct netmap_adapter *na = NA(que->vsi->ifp); - struct netmap_slot *slot; -#endif /* DEV_NETMAP */ - struct tx_ring *txr = &que->txr; - struct ixl_tx_buf *buf; - - /* Clear the old ring contents */ - IXL_TX_LOCK(txr); - -#ifdef DEV_NETMAP - /* - * (under lock): if in netmap mode, do some consistency - * checks and set slot to entry 0 of the netmap ring. - */ - slot = netmap_reset(na, NR_TX, que->me, 0); -#endif /* DEV_NETMAP */ - - bzero((void *)txr->base, - (sizeof(struct i40e_tx_desc)) * que->num_tx_desc); - - /* Reset indices */ - txr->next_avail = 0; - txr->next_to_clean = 0; - - /* Reset watchdog status */ - txr->watchdog_timer = 0; - - /* Free any existing tx mbufs. */ - buf = txr->buffers; - for (int i = 0; i < que->num_tx_desc; i++, buf++) { - if (buf->m_head != NULL) { - bus_dmamap_sync(buf->tag, buf->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(buf->tag, buf->map); - m_freem(buf->m_head); - buf->m_head = NULL; - } -#ifdef DEV_NETMAP - /* - * In netmap mode, set the map for the packet buffer. - * NOTE: Some drivers (not this one) also need to set - * the physical buffer address in the NIC ring. - * netmap_idx_n2k() maps a nic index, i, into the corresponding - * netmap slot index, si - */ - if (slot) { - int si = netmap_idx_n2k(na->tx_rings[que->me], i); - netmap_load_map(na, buf->tag, buf->map, NMB(na, slot + si)); - } -#endif /* DEV_NETMAP */ - /* Clear the EOP index */ - buf->eop_index = -1; - } - - /* Set number of descriptors available */ - txr->avail = que->num_tx_desc; - - bus_dmamap_sync(txr->dma.tag, txr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - IXL_TX_UNLOCK(txr); -} - - -/********************************************************************* - * - * Free transmit ring related data structures. - * - **********************************************************************/ -void -ixl_free_que_tx(struct ixl_queue *que) -{ - struct tx_ring *txr = &que->txr; - struct ixl_tx_buf *buf; - - INIT_DBG_IF(que->vsi->ifp, "queue %d: begin", que->me); - - for (int i = 0; i < que->num_tx_desc; i++) { - buf = &txr->buffers[i]; - if (buf->m_head != NULL) { - bus_dmamap_sync(buf->tag, buf->map, - BUS_DMASYNC_POSTWRITE); - m_freem(buf->m_head); - buf->m_head = NULL; + if (curseg == 0) { + i++; + if (__predict_false(i == nsegs)) { + // printf("bad: tsolen = %d", tsolen); + return (1); + } + curseg = segs[i].ds_len; } - bus_dmamap_unload(buf->tag, buf->map); - bus_dmamap_destroy(buf->tag, buf->map); - } - if (txr->buffers != NULL) { - free(txr->buffers, M_DEVBUF); - txr->buffers = NULL; - } - if (txr->tx_tag != NULL) { - bus_dma_tag_destroy(txr->tx_tag); - txr->tx_tag = NULL; - } - if (txr->tso_tag != NULL) { - bus_dma_tag_destroy(txr->tso_tag); - txr->tso_tag = NULL; + seglen = min(curseg, segsz); + segsz -= seglen; + curseg -= seglen; + tsolen -= seglen; + // printf("D:seglen = %d, count=%d\n", seglen, count); + } + count = 0; } - INIT_DBG_IF(que->vsi->ifp, "queue %d: end", que->me); - return; + return (0); } /********************************************************************* @@ -680,55 +205,14 @@ * **********************************************************************/ -static int -ixl_tx_setup_offload(struct ixl_queue *que, - struct mbuf *mp, u32 *cmd, u32 *off) +static void +ixl_tx_setup_offload(struct ixl_tx_queue *que, + if_pkt_info_t pi, u32 *cmd, u32 *off) { - struct ether_vlan_header *eh; -#ifdef INET - struct ip *ip = NULL; -#endif - struct tcphdr *th = NULL; -#ifdef INET6 - struct ip6_hdr *ip6; -#endif - int elen, ip_hlen = 0, tcp_hlen; - u16 etype; - u8 ipproto = 0; - bool tso = FALSE; - - /* Set up the TSO context descriptor if required */ - if (mp->m_pkthdr.csum_flags & CSUM_TSO) { - tso = ixl_tso_setup(que, mp); - if (tso) - ++que->tso; - else - return (ENXIO); - } - - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present, - * helpful for QinQ too. - */ - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - elen = ETHER_HDR_LEN; - } - - switch (etype) { + switch (pi->ipi_etype) { #ifdef INET case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + elen); - ip_hlen = ip->ip_hl << 2; - ipproto = ip->ip_p; - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - /* The IP checksum must be recalculated with TSO */ - if (tso) + if (pi->ipi_csum_flags & CSUM_IP) *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM; else *cmd |= I40E_TX_DESC_CMD_IIPT_IPV4; @@ -736,10 +220,6 @@ #endif #ifdef INET6 case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + elen); - ip_hlen = sizeof(struct ip6_hdr); - ipproto = ip6->ip6_nxt; - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); *cmd |= I40E_TX_DESC_CMD_IIPT_IPV6; break; #endif @@ -747,27 +227,26 @@ break; } - *off |= (elen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; - *off |= (ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; + *off |= (pi->ipi_ehdrlen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; + *off |= (pi->ipi_ip_hlen >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT; - switch (ipproto) { + switch (pi->ipi_ipproto) { case IPPROTO_TCP: - tcp_hlen = th->th_off << 2; - if (mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_TCP_IPV6)) { + if (pi->ipi_csum_flags & IXL_CSUM_TCP) { *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP; - *off |= (tcp_hlen >> 2) << + *off |= (pi->ipi_tcp_hlen >> 2) << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; } break; case IPPROTO_UDP: - if (mp->m_pkthdr.csum_flags & (CSUM_UDP|CSUM_UDP_IPV6)) { + if (pi->ipi_csum_flags & IXL_CSUM_UDP) { *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP; *off |= (sizeof(struct udphdr) >> 2) << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; } break; case IPPROTO_SCTP: - if (mp->m_pkthdr.csum_flags & (CSUM_SCTP|CSUM_SCTP_IPV6)) { + if (pi->ipi_csum_flags & IXL_CSUM_SCTP) { *cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP; *off |= (sizeof(struct sctphdr) >> 2) << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT; @@ -776,104 +255,35 @@ default: break; } - - return (0); } - /********************************************************************** * * Setup context for hardware segmentation offload (TSO) * **********************************************************************/ -static bool -ixl_tso_setup(struct ixl_queue *que, struct mbuf *mp) +static int +ixl_tso_setup(struct tx_ring *txr, if_pkt_info_t pi) { - struct tx_ring *txr = &que->txr; + if_softc_ctx_t scctx; struct i40e_tx_context_desc *TXD; - struct ixl_tx_buf *buf; u32 cmd, mss, type, tsolen; - u16 etype; - int idx, elen, ip_hlen, tcp_hlen; - struct ether_vlan_header *eh; -#ifdef INET - struct ip *ip; -#endif -#ifdef INET6 - struct ip6_hdr *ip6; -#endif -#if defined(INET6) || defined(INET) - struct tcphdr *th; -#endif + int idx; u64 type_cmd_tso_mss; - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present - */ - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - elen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - etype = eh->evl_proto; - } else { - elen = ETHER_HDR_LEN; - etype = eh->evl_encap_proto; - } - - switch (ntohs(etype)) { -#ifdef INET6 - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + elen); - if (ip6->ip6_nxt != IPPROTO_TCP) - return (ENXIO); - ip_hlen = sizeof(struct ip6_hdr); - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); - th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); - tcp_hlen = th->th_off << 2; - /* - * The corresponding flag is set by the stack in the IPv4 - * TSO case, but not in IPv6 (at least in FreeBSD 10.2). - * So, set it here because the rest of the flow requires it. - */ - mp->m_pkthdr.csum_flags |= CSUM_TCP_IPV6; - break; -#endif -#ifdef INET - case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + elen); - if (ip->ip_p != IPPROTO_TCP) - return (ENXIO); - ip->ip_sum = 0; - ip_hlen = ip->ip_hl << 2; - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - th->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(IPPROTO_TCP)); - tcp_hlen = th->th_off << 2; - break; -#endif - default: - printf("%s: CSUM_TSO but no supported IP version (0x%04x)", - __func__, ntohs(etype)); - return FALSE; - } - - /* Ensure we have at least the IP+TCP header in the first mbuf. */ - if (mp->m_len < elen + ip_hlen + sizeof(struct tcphdr)) - return FALSE; - - idx = txr->next_avail; - buf = &txr->buffers[idx]; - TXD = (struct i40e_tx_context_desc *) &txr->base[idx]; - tsolen = mp->m_pkthdr.len - (elen + ip_hlen + tcp_hlen); + idx = pi->ipi_pidx; + TXD = (struct i40e_tx_context_desc *) &txr->tx_base[idx]; + tsolen = pi->ipi_len - (pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen); + scctx = txr->que->vsi->shared; type = I40E_TX_DESC_DTYPE_CONTEXT; cmd = I40E_TX_CTX_DESC_TSO; /* TSO MSS must not be less than 64 */ - if (mp->m_pkthdr.tso_segsz < IXL_MIN_TSO_MSS) { - que->mss_too_small++; - mp->m_pkthdr.tso_segsz = IXL_MIN_TSO_MSS; + if (pi->ipi_tso_segsz < IXL_MIN_TSO_MSS) { + txr->mss_too_small++; + pi->ipi_tso_segsz = IXL_MIN_TSO_MSS; } - mss = mp->m_pkthdr.tso_segsz; + mss = pi->ipi_tso_segsz; type_cmd_tso_mss = ((u64)type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) | ((u64)cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | @@ -882,16 +292,123 @@ TXD->type_cmd_tso_mss = htole64(type_cmd_tso_mss); TXD->tunneling_params = htole32(0); - buf->m_head = NULL; - buf->eop_index = -1; + txr->que->tso++; - if (++idx == que->num_tx_desc) - idx = 0; + return ((idx + 1) & (scctx->isc_ntxd[0]-1)); +} - txr->avail--; - txr->next_avail = idx; +/********************************************************************* + * + * This routine maps the mbufs to tx descriptors, allowing the + * TX engine to transmit the packets. + * - return 0 on success, positive on failure + * + **********************************************************************/ +#define IXL_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) - return TRUE; +static int +ixl_isc_txd_encap(void *arg, if_pkt_info_t pi) +{ + struct ixl_vsi *vsi = arg; + if_softc_ctx_t scctx = vsi->shared; + struct ixl_tx_queue *que = &vsi->tx_queues[pi->ipi_qsidx]; + struct tx_ring *txr = &que->txr; + int nsegs = pi->ipi_nsegs; + bus_dma_segment_t *segs = pi->ipi_segs; + struct i40e_tx_desc *txd = NULL; + int i, j, mask, pidx_last; + u32 cmd, off, tx_intr; + + // device_printf(iflib_get_dev(vsi->ctx), "%s: begin\n", __func__); + + cmd = off = 0; + i = pi->ipi_pidx; + + tx_intr = (pi->ipi_flags & IPI_TX_INTR); +#if 0 + device_printf(iflib_get_dev(vsi->ctx), "%s: tx_intr %d\n", __func__, tx_intr); +#endif + + /* Set up the TSO/CSUM offload */ + if (pi->ipi_csum_flags & CSUM_OFFLOAD) { + /* Set up the TSO context descriptor if required */ + if (pi->ipi_csum_flags & CSUM_TSO) { + if (ixl_tso_detect_sparse(segs, nsegs, pi)) + return (EFBIG); + i = ixl_tso_setup(txr, pi); + } + ixl_tx_setup_offload(que, pi, &cmd, &off); + } + if (pi->ipi_mflags & M_VLANTAG) + cmd |= I40E_TX_DESC_CMD_IL2TAG1; + + cmd |= I40E_TX_DESC_CMD_ICRC; + mask = scctx->isc_ntxd[0] - 1; + for (j = 0; j < nsegs; j++) { + bus_size_t seglen; + + txd = &txr->tx_base[i]; + seglen = segs[j].ds_len; + + txd->buffer_addr = htole64(segs[j].ds_addr); + txd->cmd_type_offset_bsz = + htole64(I40E_TX_DESC_DTYPE_DATA + | ((u64)cmd << I40E_TXD_QW1_CMD_SHIFT) + | ((u64)off << I40E_TXD_QW1_OFFSET_SHIFT) + | ((u64)seglen << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) + | ((u64)htole16(pi->ipi_vtag) << I40E_TXD_QW1_L2TAG1_SHIFT)); + + txr->tx_bytes += seglen; + pidx_last = i; + i = (i+1) & mask; + } + /* Set the last descriptor for report */ + txd->cmd_type_offset_bsz |= + htole64(((u64)IXL_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT)); + /* Add to report status array (if using TX interrupts) */ + if (!vsi->enable_head_writeback && tx_intr) { + txr->tx_rsq[txr->tx_rs_pidx] = pidx_last; + txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & mask; + MPASS(txr->tx_rs_pidx != txr->tx_rs_cidx); + } + pi->ipi_new_pidx = i; + + ++txr->tx_packets; + return (0); +} + +static void +ixl_isc_txd_flush(void *arg, uint16_t txqid, qidx_t pidx) +{ + struct ixl_vsi *vsi = arg; + struct tx_ring *txr = &vsi->tx_queues[txqid].txr; + + /* + * Advance the Transmit Descriptor Tail (Tdt), this tells the + * hardware that this frame is available to transmit. + */ + wr32(vsi->hw, txr->tail, pidx); +} + + +/********************************************************************* + * + * (Re)Initialize a queue transmit ring by clearing its memory. + * + **********************************************************************/ +void +ixl_init_tx_ring(struct ixl_vsi *vsi, struct ixl_tx_queue *que) +{ + struct tx_ring *txr = &que->txr; + + /* Clear the old ring contents */ + bzero((void *)txr->tx_base, + (sizeof(struct i40e_tx_desc)) * + (vsi->shared->isc_ntxd[0] + (vsi->enable_head_writeback ? 1 : 0))); + + // TODO: Write max descriptor index instead of 0? + wr32(vsi->hw, txr->tail, 0); + wr32(vsi->hw, I40E_QTX_HEAD(txr->me), 0); } /* @@ -899,726 +416,162 @@ * location the HW records its HEAD index */ static inline u32 -ixl_get_tx_head(struct ixl_queue *que) +ixl_get_tx_head(struct ixl_tx_queue *que) { + if_softc_ctx_t scctx = que->vsi->shared; struct tx_ring *txr = &que->txr; - void *head = &txr->base[que->num_tx_desc]; + void *head = &txr->tx_base[scctx->isc_ntxd[0]]; + return LE32_TO_CPU(*(volatile __le32 *)head); } -/********************************************************************** - * - * Get index of last used descriptor/buffer from hardware, and clean - * the descriptors/buffers up to that index. - * - **********************************************************************/ -static bool -ixl_txeof_hwb(struct ixl_queue *que) +static int +ixl_isc_txd_credits_update_hwb(void *arg, uint16_t qid, bool clear) { + struct ixl_vsi *vsi = arg; + if_softc_ctx_t scctx = vsi->shared; + struct ixl_tx_queue *que = &vsi->tx_queues[qid]; struct tx_ring *txr = &que->txr; - u32 first, last, head, done; - struct ixl_tx_buf *buf; - struct i40e_tx_desc *tx_desc, *eop_desc; - - mtx_assert(&txr->mtx, MA_OWNED); - -#ifdef DEV_NETMAP - // XXX todo: implement moderation - if (netmap_tx_irq(que->vsi->ifp, que->me)) - return FALSE; -#endif /* DEF_NETMAP */ - - /* These are not the descriptors you seek, move along :) */ - if (txr->avail == que->num_tx_desc) { - atomic_store_rel_32(&txr->watchdog_timer, 0); - return FALSE; - } - - first = txr->next_to_clean; - buf = &txr->buffers[first]; - tx_desc = (struct i40e_tx_desc *)&txr->base[first]; - last = buf->eop_index; - if (last == -1) - return FALSE; - eop_desc = (struct i40e_tx_desc *)&txr->base[last]; - - /* Sync DMA before reading head index from ring */ - bus_dmamap_sync(txr->dma.tag, txr->dma.map, - BUS_DMASYNC_POSTREAD); + int head, credits; /* Get the Head WB value */ head = ixl_get_tx_head(que); - /* - ** Get the index of the first descriptor - ** BEYOND the EOP and call that 'done'. - ** I do this so the comparison in the - ** inner while loop below can be simple - */ - if (++last == que->num_tx_desc) last = 0; - done = last; + credits = head - txr->tx_cidx_processed; + if (credits < 0) + credits += scctx->isc_ntxd[0]; + if (clear) + txr->tx_cidx_processed = head; - /* - ** The HEAD index of the ring is written in a - ** defined location, this rather than a done bit - ** is what is used to keep track of what must be - ** 'cleaned'. - */ - while (first != head) { - /* We clean the range of the packet */ - while (first != done) { - ++txr->avail; - - if (buf->m_head) { - txr->bytes += /* for ITR adjustment */ - buf->m_head->m_pkthdr.len; - txr->tx_bytes += /* for TX stats */ - buf->m_head->m_pkthdr.len; - bus_dmamap_sync(buf->tag, - buf->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(buf->tag, - buf->map); - m_freem(buf->m_head); - buf->m_head = NULL; - } - buf->eop_index = -1; - - if (++first == que->num_tx_desc) - first = 0; - - buf = &txr->buffers[first]; - tx_desc = &txr->base[first]; - } - ++txr->packets; - /* If a packet was successfully cleaned, reset the watchdog timer */ - atomic_store_rel_32(&txr->watchdog_timer, IXL_WATCHDOG); - /* See if there is more work now */ - last = buf->eop_index; - if (last != -1) { - eop_desc = &txr->base[last]; - /* Get next done point */ - if (++last == que->num_tx_desc) last = 0; - done = last; - } else - break; - } - bus_dmamap_sync(txr->dma.tag, txr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - txr->next_to_clean = first; - - /* - * If there are no pending descriptors, clear the timeout. - */ - if (txr->avail == que->num_tx_desc) { - atomic_store_rel_32(&txr->watchdog_timer, 0); - return FALSE; - } - - return TRUE; + return (credits); } -/********************************************************************** - * - * Use index kept by driver and the flag on each descriptor to find used - * descriptor/buffers and clean them up for re-use. - * - * This method of reclaiming descriptors is current incompatible with - * DEV_NETMAP. - * - * Returns TRUE if there are more descriptors to be cleaned after this - * function exits. - * - **********************************************************************/ -static bool -ixl_txeof_dwb(struct ixl_queue *que) +static int +ixl_isc_txd_credits_update_dwb(void *arg, uint16_t txqid, bool clear) { - struct tx_ring *txr = &que->txr; - u32 first, last, done; - u32 limit = 256; - struct ixl_tx_buf *buf; - struct i40e_tx_desc *tx_desc, *eop_desc; + struct ixl_vsi *vsi = arg; + struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid]; + if_softc_ctx_t scctx = vsi->shared; + struct tx_ring *txr = &tx_que->txr; - mtx_assert(&txr->mtx, MA_OWNED); + qidx_t processed = 0; + qidx_t cur, prev, ntxd, rs_cidx; + int32_t delta; + bool is_done; - /* There are no descriptors to clean */ - if (txr->avail == que->num_tx_desc) { - atomic_store_rel_32(&txr->watchdog_timer, 0); - return FALSE; - } + rs_cidx = txr->tx_rs_cidx; +#if 0 + device_printf(iflib_get_dev(vsi->ctx), "%s: (q%d) rs_cidx %d, txr->tx_rs_pidx %d\n", __func__, + txr->me, rs_cidx, txr->tx_rs_pidx); +#endif + if (rs_cidx == txr->tx_rs_pidx) + return (0); + cur = txr->tx_rsq[rs_cidx]; + MPASS(cur != QIDX_INVALID); + is_done = ixl_is_tx_desc_done(txr, cur); - /* Set starting index/descriptor/buffer */ - first = txr->next_to_clean; - buf = &txr->buffers[first]; - tx_desc = &txr->base[first]; + if (clear == false || !is_done) + return (0); - /* - * This function operates per-packet -- identifies the start of the - * packet and gets the index of the last descriptor of the packet from - * it, from eop_index. - * - * If the last descriptor is marked "done" by the hardware, then all - * of the descriptors for the packet are cleaned. - */ - last = buf->eop_index; - if (last == -1) - return FALSE; - eop_desc = &txr->base[last]; - - /* Sync DMA before reading from ring */ - bus_dmamap_sync(txr->dma.tag, txr->dma.map, BUS_DMASYNC_POSTREAD); - - /* - * Get the index of the first descriptor beyond the EOP and call that - * 'done'. Simplifies the comparison for the inner loop below. - */ - if (++last == que->num_tx_desc) - last = 0; - done = last; - - /* - * We find the last completed descriptor by examining each - * descriptor's status bits to see if it's done. - */ + prev = txr->tx_cidx_processed; + ntxd = scctx->isc_ntxd[0]; do { - /* Break if last descriptor in packet isn't marked done */ - if ((eop_desc->cmd_type_offset_bsz & I40E_TXD_QW1_DTYPE_MASK) - != I40E_TX_DESC_DTYPE_DESC_DONE) + delta = (int32_t)cur - (int32_t)prev; + MPASS(prev == 0 || delta != 0); + if (delta < 0) + delta += ntxd; +#if 0 + device_printf(iflib_get_dev(vsi->ctx), + "%s: (q%d) cidx_processed=%u cur=%u clear=%d delta=%d\n", + __func__, txr->me, prev, cur, clear, delta); +#endif + processed += delta; + prev = cur; + rs_cidx = (rs_cidx + 1) & (ntxd-1); + if (rs_cidx == txr->tx_rs_pidx) break; + cur = txr->tx_rsq[rs_cidx]; + MPASS(cur != QIDX_INVALID); + is_done = ixl_is_tx_desc_done(txr, cur); + } while (is_done); - /* Clean the descriptors that make up the processed packet */ - while (first != done) { - /* - * If there was a buffer attached to this descriptor, - * prevent the adapter from accessing it, and add its - * length to the queue's TX stats. - */ - if (buf->m_head) { - txr->bytes += buf->m_head->m_pkthdr.len; - txr->tx_bytes += buf->m_head->m_pkthdr.len; - bus_dmamap_sync(buf->tag, buf->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(buf->tag, buf->map); - m_freem(buf->m_head); - buf->m_head = NULL; - } - buf->eop_index = -1; - ++txr->avail; + txr->tx_rs_cidx = rs_cidx; + txr->tx_cidx_processed = prev; - if (++first == que->num_tx_desc) - first = 0; - buf = &txr->buffers[first]; - tx_desc = &txr->base[first]; - } - ++txr->packets; - /* If a packet was successfully cleaned, reset the watchdog timer */ - atomic_store_rel_32(&txr->watchdog_timer, IXL_WATCHDOG); - - /* - * Since buf is the first buffer after the one that was just - * cleaned, check if the packet it starts is done, too. - */ - last = buf->eop_index; - if (last != -1) { - eop_desc = &txr->base[last]; - /* Get next done point */ - if (++last == que->num_tx_desc) last = 0; - done = last; - } else - break; - } while (--limit); - - bus_dmamap_sync(txr->dma.tag, txr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - txr->next_to_clean = first; - - /* - * If there are no pending descriptors, clear the watchdog timer. - */ - if (txr->avail == que->num_tx_desc) { - atomic_store_rel_32(&txr->watchdog_timer, 0); - return FALSE; - } - - return TRUE; +#if 0 + device_printf(iflib_get_dev(vsi->ctx), "%s: (q%d) processed %d\n", __func__, txr->me, processed); +#endif + return (processed); } -bool -ixl_txeof(struct ixl_queue *que) -{ - struct ixl_vsi *vsi = que->vsi; - - return (vsi->enable_head_writeback) ? ixl_txeof_hwb(que) - : ixl_txeof_dwb(que); -} - - -/********************************************************************* - * - * Refresh mbuf buffers for RX descriptor rings - * - now keeps its own state so discards due to resource - * exhaustion are unnecessary, if an mbuf cannot be obtained - * it just returns, keeping its placeholder, thus it can simply - * be recalled to try again. - * - **********************************************************************/ static void -ixl_refresh_mbufs(struct ixl_queue *que, int limit) +ixl_isc_rxd_refill(void *arg, if_rxd_update_t iru) { - struct ixl_vsi *vsi = que->vsi; - struct rx_ring *rxr = &que->rxr; - bus_dma_segment_t hseg[1]; - bus_dma_segment_t pseg[1]; - struct ixl_rx_buf *buf; - struct mbuf *mh, *mp; - int i, j, nsegs, error; - bool refreshed = FALSE; + struct ixl_vsi *vsi = arg; + if_softc_ctx_t scctx = vsi->shared; + struct rx_ring *rxr = &((vsi->rx_queues[iru->iru_qsidx]).rxr); + uint64_t *paddrs; + uint32_t next_pidx, pidx; + uint16_t count; + int i; - i = j = rxr->next_refresh; - /* Control the loop with one beyond */ - if (++j == que->num_rx_desc) - j = 0; + paddrs = iru->iru_paddrs; + pidx = iru->iru_pidx; + count = iru->iru_count; - while (j != limit) { - buf = &rxr->buffers[i]; - if (rxr->hdr_split == FALSE) - goto no_split; - - if (buf->m_head == NULL) { - mh = m_gethdr(M_NOWAIT, MT_DATA); - if (mh == NULL) - goto update; - } else - mh = buf->m_head; - - mh->m_pkthdr.len = mh->m_len = MHLEN; - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->htag, - buf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - printf("Refresh mbufs: hdr dmamap load" - " failure - %d\n", error); - m_free(mh); - buf->m_head = NULL; - goto update; - } - buf->m_head = mh; - bus_dmamap_sync(rxr->htag, buf->hmap, - BUS_DMASYNC_PREREAD); - rxr->base[i].read.hdr_addr = - htole64(hseg[0].ds_addr); - -no_split: - if (buf->m_pack == NULL) { - mp = m_getjcl(M_NOWAIT, MT_DATA, - M_PKTHDR, rxr->mbuf_sz); - if (mp == NULL) - goto update; - } else - mp = buf->m_pack; - - mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->ptag, - buf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - printf("Refresh mbufs: payload dmamap load" - " failure - %d\n", error); - m_free(mp); - buf->m_pack = NULL; - goto update; - } - buf->m_pack = mp; - bus_dmamap_sync(rxr->ptag, buf->pmap, - BUS_DMASYNC_PREREAD); - rxr->base[i].read.pkt_addr = - htole64(pseg[0].ds_addr); - /* Used only when doing header split */ - rxr->base[i].read.hdr_addr = 0; - - refreshed = TRUE; - /* Next is precalculated */ - i = j; - rxr->next_refresh = i; - if (++j == que->num_rx_desc) - j = 0; - } -update: - if (refreshed) /* Update hardware tail index */ - wr32(vsi->hw, rxr->tail, rxr->next_refresh); - return; + for (i = 0, next_pidx = pidx; i < count; i++) { + rxr->rx_base[next_pidx].read.pkt_addr = htole64(paddrs[i]); + if (++next_pidx == scctx->isc_nrxd[0]) + next_pidx = 0; + } } - -/********************************************************************* - * - * Allocate memory for rx_buffer structures. Since we use one - * rx_buffer per descriptor, the maximum number of rx_buffer's - * that we'll need is equal to the number of receive descriptors - * that we've defined. - * - **********************************************************************/ -int -ixl_allocate_rx_data(struct ixl_queue *que) +static void +ixl_isc_rxd_flush(void * arg, uint16_t rxqid, uint8_t flid __unused, qidx_t pidx) { - struct rx_ring *rxr = &que->rxr; - struct ixl_vsi *vsi = que->vsi; - device_t dev = vsi->dev; - struct ixl_rx_buf *buf; - int i, bsize, error; + struct ixl_vsi *vsi = arg; + struct rx_ring *rxr = &vsi->rx_queues[rxqid].rxr; - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MSIZE, /* maxsize */ - 1, /* nsegments */ - MSIZE, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &rxr->htag))) { - device_printf(dev, "Unable to create RX DMA htag\n"); - return (error); - } - - if ((error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 1, /* nsegments */ - MJUM16BYTES, /* maxsegsize */ - 0, /* flags */ - NULL, /* lockfunc */ - NULL, /* lockfuncarg */ - &rxr->ptag))) { - device_printf(dev, "Unable to create RX DMA ptag\n"); - goto free_rx_htag; - } - - bsize = sizeof(struct ixl_rx_buf) * que->num_rx_desc; - if (!(rxr->buffers = - (struct ixl_rx_buf *) malloc(bsize, - M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate rx_buffer memory\n"); - error = ENOMEM; - goto free_rx_ptag; - } - - for (i = 0; i < que->num_rx_desc; i++) { - buf = &rxr->buffers[i]; - error = bus_dmamap_create(rxr->htag, - BUS_DMA_NOWAIT, &buf->hmap); - if (error) { - device_printf(dev, "Unable to create RX head map\n"); - goto free_buffers; - } - error = bus_dmamap_create(rxr->ptag, - BUS_DMA_NOWAIT, &buf->pmap); - if (error) { - bus_dmamap_destroy(rxr->htag, buf->hmap); - device_printf(dev, "Unable to create RX pkt map\n"); - goto free_buffers; - } - } - - return 0; -free_buffers: - while (i--) { - buf = &rxr->buffers[i]; - bus_dmamap_destroy(rxr->ptag, buf->pmap); - bus_dmamap_destroy(rxr->htag, buf->hmap); - } - free(rxr->buffers, M_DEVBUF); - rxr->buffers = NULL; -free_rx_ptag: - bus_dma_tag_destroy(rxr->ptag); - rxr->ptag = NULL; -free_rx_htag: - bus_dma_tag_destroy(rxr->htag); - rxr->htag = NULL; - return (error); + wr32(vsi->hw, rxr->tail, pidx); } - -/********************************************************************* - * - * (Re)Initialize the queue receive ring and its buffers. - * - **********************************************************************/ -int -ixl_init_rx_ring(struct ixl_queue *que) +static int +ixl_isc_rxd_available(void *arg, uint16_t rxqid, qidx_t idx, qidx_t budget) { - struct rx_ring *rxr = &que->rxr; - struct ixl_vsi *vsi = que->vsi; -#if defined(INET6) || defined(INET) - struct ifnet *ifp = vsi->ifp; - struct lro_ctrl *lro = &rxr->lro; -#endif - struct ixl_rx_buf *buf; - bus_dma_segment_t pseg[1], hseg[1]; - int rsize, nsegs, error = 0; -#ifdef DEV_NETMAP - struct netmap_adapter *na = NA(que->vsi->ifp); - struct netmap_slot *slot; -#endif /* DEV_NETMAP */ + struct ixl_vsi *vsi = arg; + struct rx_ring *rxr = &vsi->rx_queues[rxqid].rxr; + union i40e_rx_desc *rxd; + u64 qword; + uint32_t status; + int cnt, i, nrxd; - IXL_RX_LOCK(rxr); -#ifdef DEV_NETMAP - /* same as in ixl_init_tx_ring() */ - slot = netmap_reset(na, NR_RX, que->me, 0); -#endif /* DEV_NETMAP */ - /* Clear the ring contents */ - rsize = roundup2(que->num_rx_desc * - sizeof(union i40e_rx_desc), DBA_ALIGN); - bzero((void *)rxr->base, rsize); - /* Cleanup any existing buffers */ - for (int i = 0; i < que->num_rx_desc; i++) { - buf = &rxr->buffers[i]; - if (buf->m_head != NULL) { - bus_dmamap_sync(rxr->htag, buf->hmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->htag, buf->hmap); - buf->m_head->m_flags |= M_PKTHDR; - m_freem(buf->m_head); - } - if (buf->m_pack != NULL) { - bus_dmamap_sync(rxr->ptag, buf->pmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->ptag, buf->pmap); - buf->m_pack->m_flags |= M_PKTHDR; - m_freem(buf->m_pack); - } - buf->m_head = NULL; - buf->m_pack = NULL; + nrxd = vsi->shared->isc_nrxd[0]; + + if (budget == 1) { + rxd = &rxr->rx_base[idx]; + qword = le64toh(rxd->wb.qword1.status_error_len); + status = (qword & I40E_RXD_QW1_STATUS_MASK) + >> I40E_RXD_QW1_STATUS_SHIFT; + return !!(status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)); + } + + for (cnt = 0, i = idx; cnt < nrxd - 1 && cnt <= budget;) { + rxd = &rxr->rx_base[i]; + qword = le64toh(rxd->wb.qword1.status_error_len); + status = (qword & I40E_RXD_QW1_STATUS_MASK) + >> I40E_RXD_QW1_STATUS_SHIFT; + + if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0) + break; + if (++i == nrxd) + i = 0; + if (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)) + cnt++; } - /* header split is off */ - rxr->hdr_split = FALSE; - - /* Now replenish the mbufs */ - for (int j = 0; j != que->num_rx_desc; ++j) { - struct mbuf *mh, *mp; - - buf = &rxr->buffers[j]; -#ifdef DEV_NETMAP - /* - * In netmap mode, fill the map and set the buffer - * address in the NIC ring, considering the offset - * between the netmap and NIC rings (see comment in - * ixgbe_setup_transmit_ring() ). No need to allocate - * an mbuf, so end the block with a continue; - */ - if (slot) { - int sj = netmap_idx_n2k(na->rx_rings[que->me], j); - uint64_t paddr; - void *addr; - - addr = PNMB(na, slot + sj, &paddr); - netmap_load_map(na, rxr->dma.tag, buf->pmap, addr); - /* Update descriptor and the cached value */ - rxr->base[j].read.pkt_addr = htole64(paddr); - rxr->base[j].read.hdr_addr = 0; - continue; - } -#endif /* DEV_NETMAP */ - /* - ** Don't allocate mbufs if not - ** doing header split, its wasteful - */ - if (rxr->hdr_split == FALSE) - goto skip_head; - - /* First the header */ - buf->m_head = m_gethdr(M_NOWAIT, MT_DATA); - if (buf->m_head == NULL) { - error = ENOBUFS; - goto fail; - } - m_adj(buf->m_head, ETHER_ALIGN); - mh = buf->m_head; - mh->m_len = mh->m_pkthdr.len = MHLEN; - mh->m_flags |= M_PKTHDR; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->htag, - buf->hmap, buf->m_head, hseg, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0) /* Nothing elegant to do here */ - goto fail; - bus_dmamap_sync(rxr->htag, - buf->hmap, BUS_DMASYNC_PREREAD); - /* Update descriptor */ - rxr->base[j].read.hdr_addr = htole64(hseg[0].ds_addr); - -skip_head: - /* Now the payload cluster */ - buf->m_pack = m_getjcl(M_NOWAIT, MT_DATA, - M_PKTHDR, rxr->mbuf_sz); - if (buf->m_pack == NULL) { - error = ENOBUFS; - goto fail; - } - mp = buf->m_pack; - mp->m_pkthdr.len = mp->m_len = rxr->mbuf_sz; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_sg(rxr->ptag, - buf->pmap, mp, pseg, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0) - goto fail; - bus_dmamap_sync(rxr->ptag, - buf->pmap, BUS_DMASYNC_PREREAD); - /* Update descriptor */ - rxr->base[j].read.pkt_addr = htole64(pseg[0].ds_addr); - rxr->base[j].read.hdr_addr = 0; - } - - - /* Setup our descriptor indices */ - rxr->next_check = 0; - rxr->next_refresh = 0; - rxr->lro_enabled = FALSE; - rxr->split = 0; - rxr->bytes = 0; - rxr->discard = FALSE; - - wr32(vsi->hw, rxr->tail, que->num_rx_desc - 1); - ixl_flush(vsi->hw); - -#if defined(INET6) || defined(INET) - /* - ** Now set up the LRO interface: - */ - if (ifp->if_capenable & IFCAP_LRO) { - int err = tcp_lro_init(lro); - if (err) { - if_printf(ifp, "queue %d: LRO Initialization failed!\n", que->me); - goto fail; - } - INIT_DBG_IF(ifp, "queue %d: RX Soft LRO Initialized", que->me); - rxr->lro_enabled = TRUE; - lro->ifp = vsi->ifp; - } -#endif - - bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - -fail: - IXL_RX_UNLOCK(rxr); - return (error); + return (cnt); } - -/********************************************************************* - * - * Free station receive ring data structures - * - **********************************************************************/ -void -ixl_free_que_rx(struct ixl_queue *que) -{ - struct rx_ring *rxr = &que->rxr; - struct ixl_rx_buf *buf; - - /* Cleanup any existing buffers */ - if (rxr->buffers != NULL) { - for (int i = 0; i < que->num_rx_desc; i++) { - buf = &rxr->buffers[i]; - - /* Free buffers and unload dma maps */ - ixl_rx_discard(rxr, i); - - bus_dmamap_destroy(rxr->htag, buf->hmap); - bus_dmamap_destroy(rxr->ptag, buf->pmap); - } - free(rxr->buffers, M_DEVBUF); - rxr->buffers = NULL; - } - - if (rxr->htag != NULL) { - bus_dma_tag_destroy(rxr->htag); - rxr->htag = NULL; - } - if (rxr->ptag != NULL) { - bus_dma_tag_destroy(rxr->ptag); - rxr->ptag = NULL; - } -} - -static inline void -ixl_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u8 ptype) -{ - -#if defined(INET6) || defined(INET) - /* - * ATM LRO is only for IPv4/TCP packets and TCP checksum of the packet - * should be computed by hardware. Also it should not have VLAN tag in - * ethernet header. - */ - if (rxr->lro_enabled && - (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && - (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == - (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { - /* - * Send to the stack if: - ** - LRO not enabled, or - ** - no LRO resources, or - ** - lro enqueue fails - */ - if (rxr->lro.lro_cnt != 0) - if (tcp_lro_rx(&rxr->lro, m, 0) == 0) - return; - } -#endif - (*ifp->if_input)(ifp, m); -} - - -static inline void -ixl_rx_discard(struct rx_ring *rxr, int i) -{ - struct ixl_rx_buf *rbuf; - - KASSERT(rxr != NULL, ("Receive ring pointer cannot be null")); - KASSERT(i < rxr->que->num_rx_desc, ("Descriptor index must be less than que->num_desc")); - - rbuf = &rxr->buffers[i]; - - /* Free the mbufs in the current chain for the packet */ - if (rbuf->fmp != NULL) { - bus_dmamap_sync(rxr->ptag, rbuf->pmap, BUS_DMASYNC_POSTREAD); - m_freem(rbuf->fmp); - rbuf->fmp = NULL; - } - - /* - * Free the mbufs for the current descriptor; and let ixl_refresh_mbufs() - * assign new mbufs to these. - */ - if (rbuf->m_head) { - bus_dmamap_sync(rxr->htag, rbuf->hmap, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->htag, rbuf->hmap); - m_free(rbuf->m_head); - rbuf->m_head = NULL; - } - - if (rbuf->m_pack) { - bus_dmamap_sync(rxr->ptag, rbuf->pmap, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->ptag, rbuf->pmap); - m_free(rbuf->m_pack); - rbuf->m_pack = NULL; - } -} - -#ifdef RSS /* ** i40e_ptype_to_hash: parse the packet type ** to determine the appropriate hash. @@ -1631,13 +584,13 @@ decoded = decode_rx_desc_ptype(ptype); if (!decoded.known) - return M_HASHTYPE_OPAQUE_HASH; + return M_HASHTYPE_OPAQUE; - if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2) - return M_HASHTYPE_OPAQUE_HASH; + if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_L2) + return M_HASHTYPE_OPAQUE; /* Note: anything that gets to this point is IP */ - if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) { + if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) { switch (decoded.inner_prot) { case I40E_RX_PTYPE_INNER_PROT_TCP: return M_HASHTYPE_RSS_TCP_IPV6; @@ -1647,7 +600,7 @@ return M_HASHTYPE_RSS_IPV6; } } - if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) { + if (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4) { switch (decoded.inner_prot) { case I40E_RX_PTYPE_INNER_PROT_TCP: return M_HASHTYPE_RSS_TCP_IPV4; @@ -1658,56 +611,38 @@ } } /* We should never get here!! */ - return M_HASHTYPE_OPAQUE_HASH; + return M_HASHTYPE_OPAQUE; } -#endif /* RSS */ /********************************************************************* * - * This routine executes in interrupt context. It replenishes - * the mbufs in the descriptor and sends data which has been + * This routine executes in ithread context. It sends data which has been * dma'ed into host memory to upper layer. * - * We loop at most count times if count is > 0, or until done if - * count < 0. + * Returns 0 upon success, errno on failure * - * Return TRUE for more work, FALSE for all clean. *********************************************************************/ -bool -ixl_rxeof(struct ixl_queue *que, int count) +static int +ixl_isc_rxd_pkt_get(void *arg, if_rxd_info_t ri) { - struct ixl_vsi *vsi = que->vsi; + struct ixl_vsi *vsi = arg; + struct ixl_rx_queue *que = &vsi->rx_queues[ri->iri_qsidx]; struct rx_ring *rxr = &que->rxr; - struct ifnet *ifp = vsi->ifp; -#if defined(INET6) || defined(INET) - struct lro_ctrl *lro = &rxr->lro; -#endif - int i, nextp, processed = 0; union i40e_rx_desc *cur; - struct ixl_rx_buf *rbuf, *nbuf; + u32 status, error; + u16 plen, vtag; + u64 qword; + u8 ptype; + bool eop; + int i, cidx; - IXL_RX_LOCK(rxr); + cidx = ri->iri_cidx; + i = 0; + do { + /* 5 descriptor receive limit */ + MPASS(i < IXL_MAX_RX_SEGS); -#ifdef DEV_NETMAP - if (netmap_rx_irq(ifp, que->me, &count)) { - IXL_RX_UNLOCK(rxr); - return (FALSE); - } -#endif /* DEV_NETMAP */ - - for (i = rxr->next_check; count != 0;) { - struct mbuf *sendmp, *mh, *mp; - u32 status, error; - u16 hlen, plen, vtag; - u64 qword; - u8 ptype; - bool eop; - - /* Sync the ring. */ - bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - cur = &rxr->base[i]; + cur = &rxr->rx_base[cidx]; qword = le64toh(cur->wb.qword1.status_error_len); status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; @@ -1715,229 +650,54 @@ >> I40E_RXD_QW1_ERROR_SHIFT; plen = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT; - hlen = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK) - >> I40E_RXD_QW1_LENGTH_HBUF_SHIFT; ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; - if ((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) == 0) { - ++rxr->not_done; - break; - } - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; + /* we should never be called without a valid descriptor */ + MPASS((status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) != 0); + + ri->iri_len += plen; + rxr->bytes += plen; - count--; - sendmp = NULL; - nbuf = NULL; cur->wb.qword1.status_error_len = 0; - rbuf = &rxr->buffers[i]; - mh = rbuf->m_head; - mp = rbuf->m_pack; eop = (status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)); if (status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) vtag = le16toh(cur->wb.qword0.lo_dword.l2tag1); else vtag = 0; - /* Remove device access to the rx buffers. */ - if (rbuf->m_head != NULL) { - bus_dmamap_sync(rxr->htag, rbuf->hmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->htag, rbuf->hmap); - } - if (rbuf->m_pack != NULL) { - bus_dmamap_sync(rxr->ptag, rbuf->pmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->ptag, rbuf->pmap); - } - /* ** Make sure bad packets are discarded, ** note that only EOP descriptor has valid ** error results. */ - if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (eop && (error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { rxr->desc_errs++; - ixl_rx_discard(rxr, i); - goto next_desc; + return (EBADMSG); } + ri->iri_frags[i].irf_flid = 0; + ri->iri_frags[i].irf_idx = cidx; + ri->iri_frags[i].irf_len = plen; + if (++cidx == vsi->shared->isc_nrxd[0]) + cidx = 0; + i++; + } while (!eop); - /* Prefetch the next buffer */ - if (!eop) { - nextp = i + 1; - if (nextp == que->num_rx_desc) - nextp = 0; - nbuf = &rxr->buffers[nextp]; - prefetch(nbuf); - } + /* capture data for dynamic ITR adjustment */ + rxr->packets++; + rxr->rx_packets++; - /* - ** The header mbuf is ONLY used when header - ** split is enabled, otherwise we get normal - ** behavior, ie, both header and payload - ** are DMA'd into the payload buffer. - ** - ** Rather than using the fmp/lmp global pointers - ** we now keep the head of a packet chain in the - ** buffer struct and pass this along from one - ** descriptor to the next, until we get EOP. - */ - if (rxr->hdr_split && (rbuf->fmp == NULL)) { - if (hlen > IXL_RX_HDR) - hlen = IXL_RX_HDR; - mh->m_len = hlen; - mh->m_flags |= M_PKTHDR; - mh->m_next = NULL; - mh->m_pkthdr.len = mh->m_len; - /* Null buf pointer so it is refreshed */ - rbuf->m_head = NULL; - /* - ** Check the payload length, this - ** could be zero if its a small - ** packet. - */ - if (plen > 0) { - mp->m_len = plen; - mp->m_next = NULL; - mp->m_flags &= ~M_PKTHDR; - mh->m_next = mp; - mh->m_pkthdr.len += mp->m_len; - /* Null buf pointer so it is refreshed */ - rbuf->m_pack = NULL; - rxr->split++; - } - /* - ** Now create the forward - ** chain so when complete - ** we wont have to. - */ - if (eop == 0) { - /* stash the chain head */ - nbuf->fmp = mh; - /* Make forward chain */ - if (plen) - mp->m_next = nbuf->m_pack; - else - mh->m_next = nbuf->m_pack; - } else { - /* Singlet, prepare to send */ - sendmp = mh; - if (vtag) { - sendmp->m_pkthdr.ether_vtag = vtag; - sendmp->m_flags |= M_VLANTAG; - } - } - } else { - /* - ** Either no header split, or a - ** secondary piece of a fragmented - ** split packet. - */ - mp->m_len = plen; - /* - ** See if there is a stored head - ** that determines what we are - */ - sendmp = rbuf->fmp; - rbuf->m_pack = rbuf->fmp = NULL; - - if (sendmp != NULL) /* secondary frag */ - sendmp->m_pkthdr.len += mp->m_len; - else { - /* first desc of a non-ps chain */ - sendmp = mp; - sendmp->m_flags |= M_PKTHDR; - sendmp->m_pkthdr.len = mp->m_len; - } - /* Pass the head pointer on */ - if (eop == 0) { - nbuf->fmp = sendmp; - sendmp = NULL; - mp->m_next = nbuf->m_pack; - } - } - ++processed; - /* Sending this frame? */ - if (eop) { - sendmp->m_pkthdr.rcvif = ifp; - /* gather stats */ - rxr->rx_packets++; - rxr->rx_bytes += sendmp->m_pkthdr.len; - /* capture data for dynamic ITR adjustment */ - rxr->packets++; - rxr->bytes += sendmp->m_pkthdr.len; - /* Set VLAN tag (field only valid in eop desc) */ - if (vtag) { - sendmp->m_pkthdr.ether_vtag = vtag; - sendmp->m_flags |= M_VLANTAG; - } - if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) - ixl_rx_checksum(sendmp, status, error, ptype); -#ifdef RSS - sendmp->m_pkthdr.flowid = - le32toh(cur->wb.qword0.hi_dword.rss); - M_HASHTYPE_SET(sendmp, ixl_ptype_to_hash(ptype)); -#else - sendmp->m_pkthdr.flowid = que->msix; - M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE); -#endif - } -next_desc: - bus_dmamap_sync(rxr->dma.tag, rxr->dma.map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - /* Advance our pointers to the next descriptor. */ - if (++i == que->num_rx_desc) - i = 0; - - /* Now send to the stack or do LRO */ - if (sendmp != NULL) { - rxr->next_check = i; - IXL_RX_UNLOCK(rxr); - ixl_rx_input(rxr, ifp, sendmp, ptype); - IXL_RX_LOCK(rxr); - /* - * Update index used in loop in case another - * ixl_rxeof() call executes when lock is released - */ - i = rxr->next_check; - } - - /* Every 8 descriptors we go to refresh mbufs */ - if (processed == 8) { - ixl_refresh_mbufs(que, i); - processed = 0; - } - } - - /* Refresh any remaining buf structs */ - if (ixl_rx_unrefreshed(que)) - ixl_refresh_mbufs(que, i); - - rxr->next_check = i; - - IXL_RX_UNLOCK(rxr); - -#if defined(INET6) || defined(INET) - /* - * Flush any outstanding LRO work - */ -#if __FreeBSD_version >= 1100105 - tcp_lro_flush_all(lro); -#else - struct lro_entry *queued; - while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { - SLIST_REMOVE_HEAD(&lro->lro_active, next); - tcp_lro_flush(lro, queued); - } -#endif -#endif /* defined(INET6) || defined(INET) */ - - return (FALSE); + if ((vsi->ifp->if_capenable & IFCAP_RXCSUM) != 0) + ixl_rx_checksum(ri, status, error, ptype); + ri->iri_flowid = le32toh(cur->wb.qword0.hi_dword.rss); + ri->iri_rsstype = ixl_ptype_to_hash(ptype); + ri->iri_vtag = vtag; + ri->iri_nfrags = i; + if (vtag) + ri->iri_flags |= M_VLANTAG; + return (0); } - /********************************************************************* * * Verify that the hardware indicated that the checksum is valid. @@ -1946,194 +706,64 @@ * *********************************************************************/ static void -ixl_rx_checksum(struct mbuf * mp, u32 status, u32 error, u8 ptype) +ixl_rx_checksum(if_rxd_info_t ri, u32 status, u32 error, u8 ptype) { struct i40e_rx_ptype_decoded decoded; - decoded = decode_rx_desc_ptype(ptype); + ri->iri_csum_flags = 0; - /* Errors? */ - if (error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | - (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) { - mp->m_pkthdr.csum_flags = 0; + /* No L3 or L4 checksum was calculated */ + if (!(status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; - } + + decoded = decode_rx_desc_ptype(ptype); /* IPv6 with extension headers likely have bad csum */ if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && - decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) + decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6) { if (status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) { - mp->m_pkthdr.csum_flags = 0; + ri->iri_csum_flags = 0; return; } - - - /* IP Checksum Good */ - mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; - mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; - - if (status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)) { - mp->m_pkthdr.csum_flags |= - (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); - mp->m_pkthdr.csum_data |= htons(0xffff); } - return; + + ri->iri_csum_flags |= CSUM_L3_CALC; + + /* IPv4 checksum error */ + if (error & (1 << I40E_RX_DESC_ERROR_IPE_SHIFT)) + return; + + ri->iri_csum_flags |= CSUM_L3_VALID; + ri->iri_csum_flags |= CSUM_L4_CALC; + + /* L4 checksum error */ + if (error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) + return; + + ri->iri_csum_flags |= CSUM_L4_VALID; + ri->iri_csum_data |= htons(0xffff); } -#if __FreeBSD_version >= 1100000 -uint64_t -ixl_get_counter(if_t ifp, ift_counter cnt) -{ - struct ixl_vsi *vsi; - - vsi = if_getsoftc(ifp); - - switch (cnt) { - case IFCOUNTER_IPACKETS: - return (vsi->ipackets); - case IFCOUNTER_IERRORS: - return (vsi->ierrors); - case IFCOUNTER_OPACKETS: - return (vsi->opackets); - case IFCOUNTER_OERRORS: - return (vsi->oerrors); - case IFCOUNTER_COLLISIONS: - /* Collisions are by standard impossible in 40G/10G Ethernet */ - return (0); - case IFCOUNTER_IBYTES: - return (vsi->ibytes); - case IFCOUNTER_OBYTES: - return (vsi->obytes); - case IFCOUNTER_IMCASTS: - return (vsi->imcasts); - case IFCOUNTER_OMCASTS: - return (vsi->omcasts); - case IFCOUNTER_IQDROPS: - return (vsi->iqdrops); - case IFCOUNTER_OQDROPS: - return (vsi->oqdrops); - case IFCOUNTER_NOPROTO: - return (vsi->noproto); - default: - return (if_get_counter_default(ifp, cnt)); - } -} -#endif - /* - * Set TX and RX ring size adjusting value to supported range + * Input: bitmap of enum i40e_aq_link_speed */ -void -ixl_vsi_setup_rings_size(struct ixl_vsi * vsi, int tx_ring_size, int rx_ring_size) +u64 +ixl_max_aq_speed_to_value(u8 link_speeds) { - struct device * dev = vsi->dev; - - if (tx_ring_size < IXL_MIN_RING - || tx_ring_size > IXL_MAX_RING - || tx_ring_size % IXL_RING_INCREMENT != 0) { - device_printf(dev, "Invalid tx_ring_size value of %d set!\n", - tx_ring_size); - device_printf(dev, "tx_ring_size must be between %d and %d, " - "inclusive, and must be a multiple of %d\n", - IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT); - device_printf(dev, "Using default value of %d instead\n", - IXL_DEFAULT_RING); - vsi->num_tx_desc = IXL_DEFAULT_RING; - } else - vsi->num_tx_desc = tx_ring_size; - - if (rx_ring_size < IXL_MIN_RING - || rx_ring_size > IXL_MAX_RING - || rx_ring_size % IXL_RING_INCREMENT != 0) { - device_printf(dev, "Invalid rx_ring_size value of %d set!\n", - rx_ring_size); - device_printf(dev, "rx_ring_size must be between %d and %d, " - "inclusive, and must be a multiple of %d\n", - IXL_MIN_RING, IXL_MAX_RING, IXL_RING_INCREMENT); - device_printf(dev, "Using default value of %d instead\n", - IXL_DEFAULT_RING); - vsi->num_rx_desc = IXL_DEFAULT_RING; - } else - vsi->num_rx_desc = rx_ring_size; - - device_printf(dev, "using %d tx descriptors and %d rx descriptors\n", - vsi->num_tx_desc, vsi->num_rx_desc); - + if (link_speeds & I40E_LINK_SPEED_40GB) + return IF_Gbps(40); + if (link_speeds & I40E_LINK_SPEED_25GB) + return IF_Gbps(25); + if (link_speeds & I40E_LINK_SPEED_20GB) + return IF_Gbps(20); + if (link_speeds & I40E_LINK_SPEED_10GB) + return IF_Gbps(10); + if (link_speeds & I40E_LINK_SPEED_1GB) + return IF_Gbps(1); + if (link_speeds & I40E_LINK_SPEED_100MB) + return IF_Mbps(100); + else + /* Minimum supported link speed */ + return IF_Mbps(100); } - -static void -ixl_queue_sw_irq(struct ixl_vsi *vsi, int qidx) -{ - struct i40e_hw *hw = vsi->hw; - u32 reg, mask; - - if ((vsi->flags & IXL_FLAGS_IS_VF) != 0) { - mask = (I40E_VFINT_DYN_CTLN1_INTENA_MASK | - I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | - I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK); - - reg = I40E_VFINT_DYN_CTLN1(qidx); - } else { - mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | - I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | - I40E_PFINT_DYN_CTLN_ITR_INDX_MASK); - - reg = ((vsi->flags & IXL_FLAGS_USES_MSIX) != 0) ? - I40E_PFINT_DYN_CTLN(qidx) : I40E_PFINT_DYN_CTL0; - } - - wr32(hw, reg, mask); -} - -int -ixl_queue_hang_check(struct ixl_vsi *vsi) -{ - struct ixl_queue *que = vsi->queues; - device_t dev = vsi->dev; - struct tx_ring *txr; - s32 timer, new_timer; - int hung = 0; - - for (int i = 0; i < vsi->num_queues; i++, que++) { - txr = &que->txr; - /* - * If watchdog_timer is equal to defualt value set by ixl_txeof - * just substract hz and move on - the queue is most probably - * running. Otherwise check the value. - */ - if (atomic_cmpset_rel_32(&txr->watchdog_timer, - IXL_WATCHDOG, (IXL_WATCHDOG) - hz) == 0) { - timer = atomic_load_acq_32(&txr->watchdog_timer); - /* - * Again - if the timer was reset to default value - * then queue is running. Otherwise check if watchdog - * expired and act accrdingly. - */ - - if (timer > 0 && timer != IXL_WATCHDOG) { - new_timer = timer - hz; - if (new_timer <= 0) { - atomic_store_rel_32(&txr->watchdog_timer, -1); - device_printf(dev, "WARNING: queue %d " - "appears to be hung!\n", que->me); - ++hung; - /* Try to unblock the queue with SW IRQ */ - ixl_queue_sw_irq(vsi, i); - } else { - /* - * If this fails, that means something in the TX path - * has updated the watchdog, so it means the TX path - * is still working and the watchdog doesn't need - * to countdown. - */ - atomic_cmpset_rel_32(&txr->watchdog_timer, - timer, new_timer); - } - } - } - } - - return (hung); -} - Index: sys/dev/ixl/ixlv.h =================================================================== --- sys/dev/ixl/ixlv.h +++ sys/dev/ixl/ixlv.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -38,8 +38,7 @@ #include "ixlv_vc_mgr.h" -#define IXLV_AQ_MAX_ERR 30 -#define IXLV_MAX_INIT_WAIT 120 +#define IXLV_AQ_MAX_ERR 200 #define IXLV_MAX_FILTERS 128 #define IXLV_MAX_QUEUES 16 #define IXLV_AQ_TIMEOUT (1 * hz) @@ -79,6 +78,8 @@ "\23I40E_VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2" \ "\24I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF" +static MALLOC_DEFINE(M_IXLV, "ixlv", "ixlv driver allocations"); + /* Driver state */ enum ixlv_state_t { IXLV_START, @@ -144,9 +145,10 @@ u32 qbase; u32 admvec; struct timeout_task timeout; +#ifdef notyet struct task aq_irq; struct task aq_sched; - struct taskqueue *tq; +#endif struct ixl_vsi vsi; @@ -186,7 +188,6 @@ u8 aq_buffer[IXL_AQ_BUF_SZ]; }; -#define IXLV_CORE_LOCK_ASSERT(sc) mtx_assert(&(sc)->mtx, MA_OWNED) /* ** This checks for a zero mac addr, something that will be likely ** unless the Admin on the Host has created one. @@ -205,6 +206,8 @@ /* ** VF Common function prototypes */ +void ixlv_if_init(if_ctx_t ctx); + int ixlv_send_api_ver(struct ixlv_sc *); int ixlv_verify_api_ver(struct ixlv_sc *); int ixlv_send_vf_config_msg(struct ixlv_sc *); Index: sys/dev/ixl/ixlv_vc_mgr.h =================================================================== --- sys/dev/ixl/ixlv_vc_mgr.h +++ sys/dev/ixl/ixlv_vc_mgr.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/ixl/ixlvc.c =================================================================== --- sys/dev/ixl/ixlvc.c +++ sys/dev/ixl/ixlvc.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -386,7 +386,9 @@ { device_t dev = sc->dev; struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; ++ if_softc_ctx_t scctx = iflib_get_softc_ctx(vsi->ctx); ++ struct ixl_tx_queue *tx_que = vsi->tx_queues; ++ struct ixl_rx_queue *rx_que = vsi->rx_queues; struct tx_ring *txr; struct rx_ring *rxr; int len, pairs; @@ -394,7 +396,9 @@ struct virtchnl_vsi_queue_config_info *vqci; struct virtchnl_queue_pair_info *vqpi; - pairs = vsi->num_queues; ++ /* XXX: Linux PF driver wants matching ids in each tx/rx struct, so both TX/RX ++ * queues of a pair need to be configured */ ++ pairs = max(vsi->num_tx_queues, vsi->num_rx_queues); len = sizeof(struct virtchnl_vsi_queue_config_info) + (sizeof(struct virtchnl_queue_pair_info) * pairs); vqci = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO); @@ -409,25 +413,24 @@ /* Size check is not needed here - HW max is 16 queue pairs, and we * can fit info for 31 of them into the AQ buffer before it overflows. */ - for (int i = 0; i < pairs; i++, que++, vqpi++) { - txr = &que->txr; - rxr = &que->rxr; ++ for (int i = 0; i < pairs; i++, tx_que++, rx_que++, vqpi++) { ++ txr = &tx_que->txr; ++ rxr = &rx_que->rxr; ++ vqpi->txq.vsi_id = vqci->vsi_id; vqpi->txq.queue_id = i; - vqpi->txq.ring_len = que->num_tx_desc; - vqpi->txq.dma_ring_addr = txr->dma.pa; ++ vqpi->txq.ring_len = scctx->isc_ntxd[0]; ++ vqpi->txq.dma_ring_addr = txr->tx_paddr; /* Enable Head writeback */ - if (vsi->enable_head_writeback) { - vqpi->txq.headwb_enabled = 1; - vqpi->txq.dma_headwb_addr = txr->dma.pa + - (que->num_tx_desc * sizeof(struct i40e_tx_desc)); - } + vqpi->txq.headwb_enabled = 0; + vqpi->txq.dma_headwb_addr = 0; vqpi->rxq.vsi_id = vqci->vsi_id; vqpi->rxq.queue_id = i; - vqpi->rxq.ring_len = que->num_rx_desc; - vqpi->rxq.dma_ring_addr = rxr->dma.pa; - vqpi->rxq.max_pkt_size = vsi->max_frame_size; ++ vqpi->rxq.ring_len = scctx->isc_nrxd[0]; ++ vqpi->rxq.dma_ring_addr = rxr->rx_paddr; ++ vqpi->rxq.max_pkt_size = scctx->isc_max_frame_size; ++ // TODO: Get this value from iflib, somehow vqpi->rxq.databuffer_size = rxr->mbuf_sz; vqpi->rxq.splithdr_enabled = 0; } @@ -448,6 +451,8 @@ struct virtchnl_queue_select vqs; vqs.vsi_id = sc->vsi_res->vsi_id; ++ /* XXX: In Linux PF, as long as neither of these is 0, ++ * every queue in VF VSI is enabled. */ vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1; vqs.rx_queues = vqs.tx_queues; ixlv_send_pf_msg(sc, VIRTCHNL_OP_ENABLE_QUEUES, @@ -465,6 +470,8 @@ struct virtchnl_queue_select vqs; vqs.vsi_id = sc->vsi_res->vsi_id; ++ /* XXX: In Linux PF, as long as neither of these is 0, ++ * every queue in VF VSI is disabled. */ vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1; vqs.rx_queues = vqs.tx_queues; ixlv_send_pf_msg(sc, VIRTCHNL_OP_DISABLE_QUEUES, @@ -483,27 +490,33 @@ struct virtchnl_irq_map_info *vm; int i, q, len; struct ixl_vsi *vsi = &sc->vsi; - struct ixl_queue *que = vsi->queues; ++ struct ixl_rx_queue *rx_que = vsi->rx_queues; ++ if_softc_ctx_t scctx = vsi->shared; ++ device_t dev = sc->dev; ++ ++ // XXX: What happens if we only get 1 MSI-X vector? ++ MPASS(scctx->isc_vectors > 1); /* How many queue vectors, adminq uses one */ - q = sc->msix - 1; ++ // XXX: How do we know how many interrupt vectors we have? ++ q = scctx->isc_vectors - 1; len = sizeof(struct virtchnl_irq_map_info) + - (sc->msix * sizeof(struct virtchnl_vector_map)); ++ (scctx->isc_vectors * sizeof(struct i40e_virtchnl_vector_map)); vm = malloc(len, M_DEVBUF, M_NOWAIT); if (!vm) { - printf("%s: unable to allocate memory\n", __func__); ++ device_printf(dev, "%s: unable to allocate memory\n", __func__); ixl_vc_schedule_retry(&sc->vc_mgr); return; } - vm->num_vectors = sc->msix; ++ vm->num_vectors = scctx->isc_vectors; /* Queue vectors first */ - for (i = 0; i < q; i++, que++) { ++ for (i = 0; i < q; i++, rx_que++) { vm->vecmap[i].vsi_id = sc->vsi_res->vsi_id; vm->vecmap[i].vector_id = i + 1; /* first is adminq */ - vm->vecmap[i].txq_map = (1 << que->me); - vm->vecmap[i].rxq_map = (1 << que->me); + // vm->vecmap[i].txq_map = (1 << que->me); + vm->vecmap[i].rxq_map = (1 << rx_que->rxr.me); vm->vecmap[i].rxitr_idx = 0; vm->vecmap[i].txitr_idx = 1; } @@ -811,8 +824,10 @@ uint64_t tx_discards; tx_discards = es->tx_discards; +#if 0 for (int i = 0; i < vsi->num_queues; i++) tx_discards += sc->vsi.queues[i].txr.br->br_drops; +#endif /* Update ifnet stats */ IXL_SET_IPACKETS(vsi, es->rx_unicast + @@ -875,8 +890,12 @@ ixlv_set_rss_hena(struct ixlv_sc *sc) { struct virtchnl_rss_hena hena; ++ struct i40e_hw *hw = &sc->hw; - hena.hena = IXL_DEFAULT_RSS_HENA_X722; ++ if (hw->mac.type == I40E_MAC_X722_VF) ++ hena.hena = IXL_DEFAULT_RSS_HENA_X722; ++ else ++ hena.hena = IXL_DEFAULT_RSS_HENA_XL710; ixlv_send_pf_msg(sc, VIRTCHNL_OP_SET_RSS_HENA, (u8 *)&hena, sizeof(hena)); @@ -912,9 +931,9 @@ * num_queues.) */ que_id = rss_get_indirection_to_bucket(i); - que_id = que_id % sc->vsi.num_queues; ++ que_id = que_id % sc->vsi.num_rx_queues; #else - que_id = i % sc->vsi.num_queues; ++ que_id = i % sc->vsi.num_rx_queues; #endif lut = que_id & IXL_RSS_VSI_LUT_ENTRY_MASK; rss_lut_msg->lut[i] = lut; @@ -961,9 +980,9 @@ case VIRTCHNL_EVENT_RESET_IMPENDING: device_printf(dev, "PF initiated reset!\n"); sc->init_state = IXLV_RESET_PENDING; - mtx_unlock(&sc->mtx); - ixlv_init(vsi); - mtx_lock(&sc->mtx); ++ // mtx_unlock(&sc->mtx); ++ ixlv_if_init(sc->vsi.ctx); ++ // mtx_lock(&sc->mtx); break; default: device_printf(dev, "%s: Unknown event %d from AQ\n", @@ -1023,7 +1042,7 @@ /* Turn on all interrupts */ ixlv_enable_intr(vsi); /* And inform the stack we're ready */ - vsi->ifp->if_drv_flags |= IFF_DRV_RUNNING; + // vsi->ifp->if_drv_flags |= IFF_DRV_RUNNING; /* TODO: Clear a state flag, so we know we're ready to run init again */ } break; @@ -1161,7 +1180,6 @@ { struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg; - IXLV_CORE_LOCK_ASSERT(mgr->sc); ixl_vc_process_completion(mgr, I40E_ERR_TIMEOUT); } @@ -1170,7 +1188,6 @@ { struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg; - IXLV_CORE_LOCK_ASSERT(mgr->sc); ixl_vc_send_current(mgr); } @@ -1213,8 +1230,6 @@ ixl_vc_enqueue(struct ixl_vc_mgr *mgr, struct ixl_vc_cmd *cmd, uint32_t req, ixl_vc_callback_t *callback, void *arg) { - IXLV_CORE_LOCK_ASSERT(mgr->sc); - if (cmd->flags & IXLV_VC_CMD_FLAG_BUSY) { if (mgr->current == cmd) mgr->current = NULL; @@ -1236,7 +1251,6 @@ { struct ixl_vc_cmd *cmd; - IXLV_CORE_LOCK_ASSERT(mgr->sc); KASSERT(TAILQ_EMPTY(&mgr->pending) || mgr->current != NULL, ("ixlv: pending commands waiting but no command in progress")); Index: sys/dev/ixl/virtchnl.h =================================================================== --- sys/dev/ixl/virtchnl.h +++ sys/dev/ixl/virtchnl.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2013-2017, Intel Corporation + Copyright (c) 2013-2018, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without Index: sys/dev/rtwn/rtl8812a/r12a_reg.h =================================================================== --- sys/dev/rtwn/rtl8812a/r12a_reg.h +++ sys/dev/rtwn/rtl8812a/r12a_reg.h @@ -58,6 +58,16 @@ /* Bits for R92C_LEDCFG2. */ #define R12A_LEDCFG2_ENA 0x20 +/* Bits for R12A_RXDMA_PRO. */ +#define R12A_DMA_MODE 0x02 +#define R12A_BURST_CNT_M 0x0c +#define R12A_BURST_CNT_S 2 +#define R12A_BURST_SZ_M 0x30 +#define R12A_BURST_SZ_S 4 +#define R12A_BURST_SZ_USB3 0 +#define R12A_BURST_SZ_USB2 1 +#define R12A_BURST_SZ_USB1 2 + /* Bits for R12A_CCK_CHECK. */ #define R12A_CCK_CHECK_BCN1 0x20 #define R12A_CCK_CHECK_5GHZ 0x80 Index: sys/dev/rtwn/rtl8812a/usb/r12au.h =================================================================== --- sys/dev/rtwn/rtl8812a/usb/r12au.h +++ sys/dev/rtwn/rtl8812a/usb/r12au.h @@ -37,6 +37,7 @@ */ /* r12au_init.c */ void r12au_init_rx_agg(struct rtwn_softc *); +void r12au_init_burstlen_usb2(struct rtwn_softc *); void r12au_init_burstlen(struct rtwn_softc *); void r12au_init_ampdu_fwhw(struct rtwn_softc *); void r12au_init_ampdu(struct rtwn_softc *); Index: sys/dev/rtwn/rtl8812a/usb/r12au_init.c =================================================================== --- sys/dev/rtwn/rtl8812a/usb/r12au_init.c +++ sys/dev/rtwn/rtl8812a/usb/r12au_init.c @@ -71,20 +71,33 @@ R92C_TRXDMA_CTRL_RXDMA_AGG_EN); } +void +r12au_init_burstlen_usb2(struct rtwn_softc *sc) +{ + const uint8_t dma_count = R12A_DMA_MODE | SM(R12A_BURST_CNT, 3); + + if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { + /* Set burst packet length to 512 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, R12A_BURST_SZ_M, + dma_count | SM(R12A_BURST_SZ, R12A_BURST_SZ_USB2)); + } else { + /* Set burst packet length to 64 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, R12A_BURST_SZ_M, + dma_count | SM(R12A_BURST_SZ, R12A_BURST_SZ_USB1)); + } +} + void r12au_init_burstlen(struct rtwn_softc *sc) { - if (rtwn_read_1(sc, R92C_TYPE_ID + 3) & 0x80) { - if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { - /* Set burst packet length to 512 B. */ - rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); - } else { - /* Set burst packet length to 64 B. */ - rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); - } - } else { /* USB 3.0 */ + const uint8_t dma_count = R12A_DMA_MODE | SM(R12A_BURST_CNT, 3); + + if (rtwn_read_1(sc, R92C_TYPE_ID + 3) & 0x80) + r12au_init_burstlen_usb2(sc); + else { /* USB 3.0 */ /* Set burst packet length to 1 KB. */ - rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x30, 0x0e); + rtwn_setbits_1(sc, R12A_RXDMA_PRO, R12A_BURST_SZ_M, + dma_count | SM(R12A_BURST_SZ, R12A_BURST_SZ_USB3)); rtwn_setbits_1(sc, 0xf008, 0x18, 0); } Index: sys/dev/rtwn/rtl8821a/usb/r21au.h =================================================================== --- sys/dev/rtwn/rtl8821a/usb/r21au.h +++ sys/dev/rtwn/rtl8821a/usb/r21au.h @@ -37,7 +37,6 @@ */ /* r21au_init.c */ void r21au_init_tx_agg(struct rtwn_softc *); -void r21au_init_burstlen(struct rtwn_softc *); /* r21au_dfs.c */ void r21au_chan_check(void *, int); Index: sys/dev/rtwn/rtl8821a/usb/r21au_attach.c =================================================================== --- sys/dev/rtwn/rtl8821a/usb/r21au_attach.c +++ sys/dev/rtwn/rtl8821a/usb/r21au_attach.c @@ -135,7 +135,7 @@ rs->rs_fix_spur = rtwn_nop_softc_chan; rs->rs_set_band_2ghz = r21a_set_band_2ghz; rs->rs_set_band_5ghz = r21a_set_band_5ghz; - rs->rs_init_burstlen = r21au_init_burstlen; + rs->rs_init_burstlen = r12au_init_burstlen_usb2; rs->rs_init_ampdu_fwhw = r21a_init_ampdu_fwhw; rs->rs_crystalcap_write = r21a_crystalcap_write; #ifndef RTWN_WITHOUT_UCODE Index: sys/dev/rtwn/rtl8821a/usb/r21au_init.c =================================================================== --- sys/dev/rtwn/rtl8821a/usb/r21au_init.c +++ sys/dev/rtwn/rtl8821a/usb/r21au_init.c @@ -70,14 +70,3 @@ rtwn_write_1(sc, R21A_DWBCN1_CTRL, uc->tx_agg_desc_num << 1); } -void -r21au_init_burstlen(struct rtwn_softc *sc) -{ - if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { - /* Set burst packet length to 512 B. */ - rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); - } else { - /* Set burst packet length to 64 B. */ - rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); - } -} Index: sys/kern/subr_witness.c =================================================================== --- sys/kern/subr_witness.c +++ sys/kern/subr_witness.c @@ -561,14 +561,14 @@ /* * UDP/IP */ - { "udp", &lock_class_rw }, + { "udp", &lock_class_mtx_sleep }, { "udpinp", &lock_class_rw }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, /* * TCP/IP */ - { "tcp", &lock_class_rw }, + { "tcp", &lock_class_mtx_sleep }, { "tcpinp", &lock_class_rw }, { "so_snd", &lock_class_mtx_sleep }, { NULL, NULL }, Index: sys/modules/Makefile =================================================================== --- sys/modules/Makefile +++ sys/modules/Makefile @@ -121,7 +121,6 @@ ${_ena} \ ${_ep} \ ${_epic} \ - epoch_test \ esp \ ${_et} \ evdev \ @@ -206,7 +205,6 @@ ${_ix} \ ${_ixv} \ ${_ixl} \ - ${_ixlv} \ jme \ joy \ kbdmux \ Index: sys/modules/ixl/Makefile =================================================================== --- sys/modules/ixl/Makefile +++ sys/modules/ixl/Makefile @@ -3,11 +3,10 @@ .PATH: ${SRCTOP}/sys/dev/ixl KMOD = if_ixl -SRCS = device_if.h bus_if.h pci_if.h -SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h +SRCS = device_if.h bus_if.h pci_if.h ifdi_if.h +SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h opt_iflib.h SRCS += if_ixl.c ixl_pf_main.c ixl_pf_qmgr.c ixl_txrx.c ixl_pf_i2c.c i40e_osdep.c -SRCS += ixl_iw.c -SRCS.PCI_IOV= pci_iov_if.h ixl_pf_iov.c +SRCS.PCI_IOV = pci_iov_if.h ixl_pf_iov.c # Shared source SRCS += i40e_common.c i40e_nvm.c i40e_adminq.c i40e_lan_hmc.c i40e_hmc.c i40e_dcb.c @@ -15,4 +14,7 @@ # Debug messages / sysctls # CFLAGS += -DIXL_DEBUG +#CFLAGS += -DIXL_IW +#SRCS += ixl_iw.c + .include Index: sys/modules/ixlv/Makefile =================================================================== --- sys/modules/ixlv/Makefile +++ sys/modules/ixlv/Makefile @@ -3,8 +3,8 @@ .PATH: ${SRCTOP}/sys/dev/ixl KMOD = if_ixlv -SRCS = device_if.h bus_if.h pci_if.h -SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h +SRCS = device_if.h bus_if.h pci_if.h ifdi_if.h +SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ixl.h opt_iflib.h SRCS += if_ixlv.c ixlvc.c ixl_txrx.c i40e_osdep.c # Shared source Index: sys/net/iflib.c =================================================================== --- sys/net/iflib.c +++ sys/net/iflib.c @@ -2275,7 +2275,7 @@ } } } - done: +done: if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); IFDI_INTR_ENABLE(ctx); txq = ctx->ifc_txqs; @@ -4014,7 +4014,7 @@ */ if (avoid_reset) { if_setflagbits(ifp, IFF_UP,0); - if (!(if_getdrvflags(ifp)& IFF_DRV_RUNNING)) + if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) reinit = 1; #ifdef INET if (!(if_getflags(ifp) & IFF_NOARP)) @@ -4115,7 +4115,7 @@ #endif setmask |= (mask & IFCAP_FLAGS); - if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) + if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) setmask |= (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); if ((mask & IFCAP_WOL) && (if_getcapabilities(ifp) & IFCAP_WOL) != 0) @@ -4140,7 +4140,7 @@ CTX_UNLOCK(ctx); } break; - } + } case SIOCGPRIVATE_0: case SIOCSDRVSPEC: case SIOCGDRVSPEC: @@ -5097,7 +5097,7 @@ KASSERT(ntxqs > 0, ("number of queues per qset must be at least 1")); KASSERT(nrxqs > 0, ("number of queues per qset must be at least 1")); -/* Allocate the TX ring struct memory */ + /* Allocate the TX ring struct memory */ if (!(ctx->ifc_txqs = (iflib_txq_t) malloc(sizeof(struct iflib_txq) * ntxqsets, M_IFLIB, M_NOWAIT | M_ZERO))) { Index: sys/netinet/in_pcb.h =================================================================== --- sys/netinet/in_pcb.h +++ sys/netinet/in_pcb.h @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #endif #include @@ -157,6 +159,7 @@ * Key: * (b) - Protected by the hpts lock. * (c) - Constant after initialization + * (e) - Protected by the net_epoch_prempt epoch * (g) - Protected by the pcbgroup lock * (i) - Protected by the inpcb lock * (p) - Protected by the pcbinfo lock for the inpcb @@ -231,7 +234,7 @@ struct m_snd_tag; struct inpcb { /* Cache line #1 (amd64) */ - CK_LIST_ENTRY(inpcb) inp_hash; /* (h/i) hash list */ + CK_LIST_ENTRY(inpcb) inp_hash; /* [w](h/i) [r](e/i) hash list */ CK_LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */ struct rwlock inp_lock; /* Cache line #2 (amd64) */ @@ -324,8 +327,8 @@ struct route_in6 inp_route6; }; CK_LIST_ENTRY(inpcb) inp_list; /* (p/l) list for all PCBs for proto */ - /* (p[w]) for list iteration */ - /* (p[r]/l) for addition/removal */ + /* (e[r]) for list iteration */ + /* (p[w]/l) for addition/removal */ struct epoch_context inp_epoch_ctx; }; #endif /* _KERNEL */ @@ -436,22 +439,23 @@ * Locking key: * * (c) Constant or nearly constant after initialisation + * (e) - Protected by the net_epoch_prempt epoch * (g) Locked by ipi_lock * (l) Locked by ipi_list_lock - * (h) Read using either ipi_hash_lock or inpcb lock; write requires both + * (h) Read using either net_epoch_preempt or inpcb lock; write requires both ipi_hash_lock and inpcb lock * (p) Protected by one or more pcbgroup locks * (x) Synchronisation properties poorly defined */ struct inpcbinfo { /* - * Global lock protecting full inpcb list traversal + * Global lock protecting inpcb list modification */ - struct rwlock ipi_lock; + struct mtx ipi_lock; /* * Global list of inpcbs on the protocol. */ - struct inpcbhead *ipi_listhead; /* (g/l) */ + struct inpcbhead *ipi_listhead; /* [r](e) [w](g/l) */ u_int ipi_count; /* (l) */ /* @@ -482,9 +486,9 @@ u_int ipi_hashfields; /* (c) */ /* - * Global lock protecting non-pcbgroup hash lookup tables. + * Global lock protecting modification non-pcbgroup hash lookup tables. */ - struct rwlock ipi_hash_lock; + struct mtx ipi_hash_lock; /* * Global hash of inpcbs, hashed by local and foreign addresses and @@ -626,20 +630,18 @@ #endif /* _KERNEL */ #define INP_INFO_LOCK_INIT(ipi, d) \ - rw_init_flags(&(ipi)->ipi_lock, (d), RW_RECURSE) -#define INP_INFO_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_lock) -#define INP_INFO_RLOCK(ipi) rw_rlock(&(ipi)->ipi_lock) -#define INP_INFO_WLOCK(ipi) rw_wlock(&(ipi)->ipi_lock) -#define INP_INFO_TRY_RLOCK(ipi) rw_try_rlock(&(ipi)->ipi_lock) -#define INP_INFO_TRY_WLOCK(ipi) rw_try_wlock(&(ipi)->ipi_lock) -#define INP_INFO_TRY_UPGRADE(ipi) rw_try_upgrade(&(ipi)->ipi_lock) -#define INP_INFO_WLOCKED(ipi) rw_wowned(&(ipi)->ipi_lock) -#define INP_INFO_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_lock) -#define INP_INFO_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_lock) -#define INP_INFO_LOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_LOCKED) -#define INP_INFO_RLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_RLOCKED) -#define INP_INFO_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_WLOCKED) -#define INP_INFO_UNLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_UNLOCKED) + mtx_init(&(ipi)->ipi_lock, (d), NULL, MTX_DEF| MTX_RECURSE) +#define INP_INFO_LOCK_DESTROY(ipi) mtx_destroy(&(ipi)->ipi_lock) +#define INP_INFO_RLOCK(ipi) NET_EPOCH_ENTER() +#define INP_INFO_WLOCK(ipi) mtx_lock(&(ipi)->ipi_lock) +#define INP_INFO_TRY_WLOCK(ipi) mtx_trylock(&(ipi)->ipi_lock) +#define INP_INFO_WLOCKED(ipi) mtx_owned(&(ipi)->ipi_lock) +#define INP_INFO_RUNLOCK(ipi) NET_EPOCH_EXIT() +#define INP_INFO_WUNLOCK(ipi) mtx_unlock(&(ipi)->ipi_lock) +#define INP_INFO_LOCK_ASSERT(ipi) MPASS(in_epoch() || mtx_owned(&(ipi)->ipi_lock)) +#define INP_INFO_RLOCK_ASSERT(ipi) MPASS(in_epoch()) +#define INP_INFO_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_lock, MA_OWNED) +#define INP_INFO_UNLOCK_ASSERT(ipi) MPASS(!in_epoch() && !mtx_owned(&(ipi)->ipi_lock)) #define INP_LIST_LOCK_INIT(ipi, d) \ rw_init_flags(&(ipi)->ipi_list_lock, (d), 0) @@ -660,17 +662,14 @@ #define INP_LIST_UNLOCK_ASSERT(ipi) \ rw_assert(&(ipi)->ipi_list_lock, RA_UNLOCKED) -#define INP_HASH_LOCK_INIT(ipi, d) \ - rw_init_flags(&(ipi)->ipi_hash_lock, (d), 0) -#define INP_HASH_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_hash_lock) -#define INP_HASH_RLOCK(ipi) rw_rlock(&(ipi)->ipi_hash_lock) -#define INP_HASH_WLOCK(ipi) rw_wlock(&(ipi)->ipi_hash_lock) -#define INP_HASH_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_hash_lock) -#define INP_HASH_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_hash_lock) -#define INP_HASH_LOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \ - RA_LOCKED) -#define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \ - RA_WLOCKED) +#define INP_HASH_LOCK_INIT(ipi, d) mtx_init(&(ipi)->ipi_hash_lock, (d), NULL, MTX_DEF) +#define INP_HASH_LOCK_DESTROY(ipi) mtx_destroy(&(ipi)->ipi_hash_lock) +#define INP_HASH_RLOCK(ipi) NET_EPOCH_ENTER() +#define INP_HASH_WLOCK(ipi) mtx_lock(&(ipi)->ipi_hash_lock) +#define INP_HASH_RUNLOCK(ipi) NET_EPOCH_EXIT() +#define INP_HASH_WUNLOCK(ipi) mtx_unlock(&(ipi)->ipi_hash_lock) +#define INP_HASH_LOCK_ASSERT(ipi) MPASS(in_epoch() || mtx_owned(&(ipi)->ipi_hash_lock)) +#define INP_HASH_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_hash_lock, MA_OWNED); #define INP_GROUP_LOCK_INIT(ipg, d) mtx_init(&(ipg)->ipg_lock, (d), NULL, \ MTX_DEF | MTX_DUPOK) Index: sys/netinet/tcp_hpts.c =================================================================== --- sys/netinet/tcp_hpts.c +++ sys/netinet/tcp_hpts.c @@ -184,9 +184,6 @@ static struct tcp_hptsi tcp_pace; -static int -tcp_hptsi_lock_inpinfo(struct inpcb *inp, - struct tcpcb **tp); static void tcp_wakehpts(struct tcp_hpts_entry *p); static void tcp_wakeinput(struct tcp_hpts_entry *p); static void tcp_input_data(struct tcp_hpts_entry *hpts, struct timeval *tv); @@ -498,59 +495,6 @@ 0, 0, sysctl_tcp_hpts_log, "A", "tcp hptsi log"); -/* - * Try to get the INP_INFO lock. - * - * This function always succeeds in getting the lock. It will clear - * *tpp and return (1) if something critical changed while the inpcb - * was unlocked. Otherwise, it will leave *tpp unchanged and return (0). - * - * This function relies on the fact that the hpts always holds a - * reference on the inpcb while the segment is on the hptsi wheel and - * in the input queue. - * - */ -static int -tcp_hptsi_lock_inpinfo(struct inpcb *inp, struct tcpcb **tpp) -{ - struct tcp_function_block *tfb; - struct tcpcb *tp; - void *ptr; - - /* Try the easy way. */ - if (INP_INFO_TRY_RLOCK(&V_tcbinfo)) - return (0); - - /* - * OK, let's try the hard way. We'll save the function pointer block - * to make sure that doesn't change while we aren't holding the - * lock. - */ - tp = *tpp; - tfb = tp->t_fb; - ptr = tp->t_fb_ptr; - INP_WUNLOCK(inp); - INP_INFO_RLOCK(&V_tcbinfo); - INP_WLOCK(inp); - /* If the session went away, return an error. */ - if ((inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) || - (inp->inp_flags2 & INP_FREED)) { - *tpp = NULL; - return (1); - } - /* - * If the function block or stack-specific data block changed, - * report an error. - */ - tp = intotcpcb(inp); - if ((tp->t_fb != tfb) && (tp->t_fb_ptr != ptr)) { - *tpp = NULL; - return (1); - } - return (0); -} - - static void tcp_wakehpts(struct tcp_hpts_entry *hpts) { @@ -1216,7 +1160,7 @@ inp->inp_in_input = 0; tp = intotcpcb(inp); mtx_unlock(&hpts->p_mtx); - CURVNET_SET(tp->t_vnet); + CURVNET_SET(inp->inp_vnet); if (drop_reason) { INP_INFO_RLOCK(&V_tcbinfo); ti_locked = TI_RLOCKED; @@ -1290,10 +1234,7 @@ (m->m_pkthdr.pace_lock == TI_RLOCKED || tp->t_state != TCPS_ESTABLISHED)) { ti_locked = TI_RLOCKED; - if (tcp_hptsi_lock_inpinfo(inp, &tp)) { - CURVNET_RESTORE(); - goto out; - } + INP_INFO_RLOCK(&V_tcbinfo); m = tp->t_in_pkt; } if (in_newts_every_tcb) { @@ -1360,7 +1301,6 @@ */ if ((inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) || (inp->inp_flags2 & INP_FREED)) { - out_free: while (m) { m_freem(m); m = n; @@ -1376,8 +1316,7 @@ if (ti_locked == TI_UNLOCKED && (tp->t_state != TCPS_ESTABLISHED)) { ti_locked = TI_RLOCKED; - if (tcp_hptsi_lock_inpinfo(inp, &tp)) - goto out_free; + INP_INFO_RLOCK(&V_tcbinfo); } } /** end while(m) */ } /** end if ((m != NULL) && (m == tp->t_in_pkt)) */ @@ -1589,7 +1528,7 @@ getmicrouptime(&sv); cts = tcp_tv_to_usectick(&sv); } - CURVNET_SET(tp->t_vnet); + CURVNET_SET(inp->inp_vnet); /* * There is a hole here, we get the refcnt on the * inp so it will still be preserved but to make Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -960,25 +960,10 @@ * * XXXRW: It may be time to rethink timewait locking. */ -relocked: if (inp->inp_flags & INP_TIMEWAIT) { if (ti_locked == TI_UNLOCKED) { - if (INP_INFO_TRY_RLOCK(&V_tcbinfo) == 0) { - in_pcbref(inp); - INP_WUNLOCK(inp); - INP_INFO_RLOCK(&V_tcbinfo); - ti_locked = TI_RLOCKED; - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) { - inp = NULL; - goto findpcb; - } else if (inp->inp_flags & INP_DROPPED) { - INP_WUNLOCK(inp); - inp = NULL; - goto findpcb; - } - } else - ti_locked = TI_RLOCKED; + INP_INFO_RLOCK(); + ti_locked = TI_RLOCKED; } INP_INFO_RLOCK_ASSERT(&V_tcbinfo); @@ -1026,23 +1011,8 @@ (tp->t_state == TCPS_LISTEN && (thflags & TH_SYN) && !IS_FASTOPEN(tp->t_flags)))) { if (ti_locked == TI_UNLOCKED) { - if (INP_INFO_TRY_RLOCK(&V_tcbinfo) == 0) { - in_pcbref(inp); - INP_WUNLOCK(inp); - INP_INFO_RLOCK(&V_tcbinfo); - ti_locked = TI_RLOCKED; - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) { - inp = NULL; - goto findpcb; - } else if (inp->inp_flags & INP_DROPPED) { - INP_WUNLOCK(inp); - inp = NULL; - goto findpcb; - } - goto relocked; - } else - ti_locked = TI_RLOCKED; + INP_INFO_RLOCK(); + ti_locked = TI_RLOCKED; } INP_INFO_RLOCK_ASSERT(&V_tcbinfo); } Index: sys/netinet/tcp_stacks/rack.c =================================================================== --- sys/netinet/tcp_stacks/rack.c +++ sys/netinet/tcp_stacks/rack.c @@ -6837,34 +6837,8 @@ * Initial input (ACK to SYN-ACK etc)lets go ahead and get * it processed */ - if (ti_locked != TI_RLOCKED && INP_INFO_TRY_RLOCK(&V_tcbinfo)) - ti_locked = TI_RLOCKED; - if (ti_locked != TI_RLOCKED) { - inp = tp->t_inpcb; - tfb = tp->t_fb; - in_pcbref(inp); - INP_WUNLOCK(inp); - INP_INFO_RLOCK(&V_tcbinfo); - ti_locked = TI_RLOCKED; - INP_WLOCK(inp); - if (in_pcbrele_wlocked(inp)) - inp = NULL; - if (inp == NULL || (inp->inp_flags2 & INP_FREED) || - (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED))) { - /* The TCPCB went away. Free the packet. */ - INP_INFO_RUNLOCK(&V_tcbinfo); - if (inp) - INP_WUNLOCK(inp); - m_freem(m); - return; - } - /* If the stack changed, call the correct stack. */ - if (tp->t_fb != tfb) { - tp->t_fb->tfb_tcp_do_segment(m, th, so, tp, - drop_hdrlen, tlen, iptos, ti_locked); - return; - } - } + INP_INFO_RLOCK(); + ti_locked = TI_RLOCKED; tcp_get_usecs(&tv); rack_hpts_do_segment(m, th, so, tp, drop_hdrlen, tlen, iptos, ti_locked, 0, &tv); Index: sys/netinet/tcp_timewait.c =================================================================== --- sys/netinet/tcp_timewait.c +++ sys/netinet/tcp_timewait.c @@ -707,54 +707,46 @@ in_pcbref(inp); TW_RUNLOCK(V_tw_lock); - if (INP_INFO_TRY_RLOCK(&V_tcbinfo)) { - - INP_WLOCK(inp); - tw = intotw(inp); - if (in_pcbrele_wlocked(inp)) { - if (__predict_true(tw == NULL)) { - INP_INFO_RUNLOCK(&V_tcbinfo); - continue; - } else { - /* This should not happen as in TIMEWAIT - * state the inp should not be destroyed - * before its tcptw. If INVARIANTS is - * defined panic. - */ -#ifdef INVARIANTS - panic("%s: Panic before an infinite " - "loop: INP_TIMEWAIT && (INP_FREED " - "|| inp last reference) && tw != " - "NULL", __func__); -#else - log(LOG_ERR, "%s: Avoid an infinite " - "loop: INP_TIMEWAIT && (INP_FREED " - "|| inp last reference) && tw != " - "NULL", __func__); -#endif - INP_INFO_RUNLOCK(&V_tcbinfo); - break; - } - } - - if (tw == NULL) { - /* tcp_twclose() has already been called */ - INP_WUNLOCK(inp); + INP_INFO_RLOCK(&V_tcbinfo); + INP_WLOCK(inp); + tw = intotw(inp); + if (in_pcbrele_wlocked(inp)) { + if (__predict_true(tw == NULL)) { INP_INFO_RUNLOCK(&V_tcbinfo); continue; + } else { + /* This should not happen as in TIMEWAIT + * state the inp should not be destroyed + * before its tcptw. If INVARIANTS is + * defined panic. + */ +#ifdef INVARIANTS + panic("%s: Panic before an infinite " + "loop: INP_TIMEWAIT && (INP_FREED " + "|| inp last reference) && tw != " + "NULL", __func__); +#else + log(LOG_ERR, "%s: Avoid an infinite " + "loop: INP_TIMEWAIT && (INP_FREED " + "|| inp last reference) && tw != " + "NULL", __func__); +#endif + INP_INFO_RUNLOCK(&V_tcbinfo); + break; } - - tcp_twclose(tw, reuse); - INP_INFO_RUNLOCK(&V_tcbinfo); - if (reuse) - return tw; - } else { - /* INP_INFO lock is busy, continue later. */ - INP_WLOCK(inp); - if (!in_pcbrele_wlocked(inp)) - INP_WUNLOCK(inp); - break; } + + if (tw == NULL) { + /* tcp_twclose() has already been called */ + INP_WUNLOCK(inp); + INP_INFO_RUNLOCK(&V_tcbinfo); + continue; + } + + tcp_twclose(tw, reuse); + INP_INFO_RUNLOCK(&V_tcbinfo); + if (reuse) + return tw; } return NULL; Index: sys/sys/cnv.h =================================================================== --- sys/sys/cnv.h +++ sys/sys/cnv.h @@ -52,8 +52,8 @@ /* * Functions which returns information about the given cookie. */ -const char *cnvlist_name(void *cookiep); -int cnvlist_type(void *cookiep); +const char *cnvlist_name(const void *cookie); +int cnvlist_type(const void *cookie); /* * The cnvlist_get functions returns value associated with the given cookie. @@ -61,18 +61,18 @@ * not be freed by the caller. */ -bool cnvlist_get_bool(void *cookiep); -uint64_t cnvlist_get_number(void *cookiep); -const char *cnvlist_get_string(void *cookiep); -const nvlist_t *cnvlist_get_nvlist(void *cookiep); -const void *cnvlist_get_binary(void *cookiep, size_t *sizep); -const bool *cnvlist_get_bool_array(void *cookiep, size_t *nitemsp); -const uint64_t *cnvlist_get_number_array(void *cookiep, size_t *nitemsp); -const char * const *cnvlist_get_string_array(void *cookiep, size_t *nitemsp); -const nvlist_t * const *cnvlist_get_nvlist_array(void *cookiep, size_t *nitemsp); +bool cnvlist_get_bool(const void *cookie); +uint64_t cnvlist_get_number(const void *cookie); +const char *cnvlist_get_string(const void *cookie); +const nvlist_t *cnvlist_get_nvlist(const void *cookie); +const void *cnvlist_get_binary(const void *cookie, size_t *sizep); +const bool *cnvlist_get_bool_array(const void *cookie, size_t *nitemsp); +const uint64_t *cnvlist_get_number_array(const void *cookie, size_t *nitemsp); +const char * const *cnvlist_get_string_array(const void *cookie, size_t *nitemsp); +const nvlist_t * const *cnvlist_get_nvlist_array(const void *cookie, size_t *nitemsp); #ifndef _KERNEL -int cnvlist_get_descriptor(void *cookiep); -const int *cnvlist_get_descriptor_array(void *cookiep, size_t *nitemsp); +int cnvlist_get_descriptor(const void *cookie); +const int *cnvlist_get_descriptor_array(const void *cookie, size_t *nitemsp); #endif @@ -82,18 +82,18 @@ * The caller is responsible for freeing received data. */ -bool cnvlist_take_bool(nvlist_t *nvl, void *cookiep); -uint64_t cnvlist_take_number(nvlist_t *nvl, void *cookiep); -char *cnvlist_take_string(nvlist_t *nvl, void *cookiep); -nvlist_t *cnvlist_take_nvlist(nvlist_t *nvl, void *cookiep); -void *cnvlist_take_binary(nvlist_t *nvl, void *cookiep, size_t *sizep); -bool *cnvlist_take_bool_array(nvlist_t *nvl, void *cookiep, size_t *nitemsp); -uint64_t *cnvlist_take_number_array(nvlist_t *nvl, void *cookiep, size_t *nitemsp); -char **cnvlist_take_string_array(nvlist_t *nvl, void *cookiep, size_t *nitemsp); -nvlist_t **cnvlist_take_nvlist_array(nvlist_t *nvl, void *cookiep, size_t *nitemsp); +bool cnvlist_take_bool(void *cookie); +uint64_t cnvlist_take_number(void *cookie); +char *cnvlist_take_string(void *cookie); +nvlist_t *cnvlist_take_nvlist(void *cookie); +void *cnvlist_take_binary(void *cookie, size_t *sizep); +bool *cnvlist_take_bool_array(void *cookie, size_t *nitemsp); +uint64_t *cnvlist_take_number_array(void *cookie, size_t *nitemsp); +char **cnvlist_take_string_array(void *cookie, size_t *nitemsp); +nvlist_t **cnvlist_take_nvlist_array(void *cookie, size_t *nitemsp); #ifndef _KERNEL -int cnvlist_take_descriptor(nvlist_t *nvl, void *cookiep); -int *cnvlist_take_descriptor_array(nvlist_t *nvl, void *cookiep, size_t *nitemsp); +int cnvlist_take_descriptor(void *cookie); +int *cnvlist_take_descriptor_array(void *cookie, size_t *nitemsp); #endif /* @@ -101,18 +101,18 @@ * and frees memory associated with it. */ -void cnvlist_free_bool(nvlist_t *nvl, void *cookiep); -void cnvlist_free_number(nvlist_t *nvl, void *cookiep); -void cnvlist_free_string(nvlist_t *nvl, void *cookiep); -void cnvlist_free_nvlist(nvlist_t *nvl, void *cookiep); -void cnvlist_free_binary(nvlist_t *nvl, void *cookiep); -void cnvlist_free_bool_array(nvlist_t *nvl, void *cookiep); -void cnvlist_free_number_array(nvlist_t *nvl, void *cookiep); -void cnvlist_free_string_array(nvlist_t *nvl, void *cookiep); -void cnvlist_free_nvlist_array(nvlist_t *nvl, void *cookiep); +void cnvlist_free_bool(void *cookie); +void cnvlist_free_number(void *cookie); +void cnvlist_free_string(void *cookie); +void cnvlist_free_nvlist(void *cookie); +void cnvlist_free_binary(void *cookie); +void cnvlist_free_bool_array(void *cookie); +void cnvlist_free_number_array(void *cookie); +void cnvlist_free_string_array(void *cookie); +void cnvlist_free_nvlist_array(void *cookie); #ifndef _KERNEL -void cnvlist_free_descriptor(nvlist_t *nvl, void *cookiep); -void cnvlist_free_descriptor_array(nvlist_t *nvl, void *cookiep); +void cnvlist_free_descriptor(void *cookie); +void cnvlist_free_descriptor_array(void *cookie); #endif __END_DECLS Index: sys/sys/nv.h =================================================================== --- sys/sys/nv.h +++ sys/sys/nv.h @@ -162,6 +162,14 @@ void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems); #endif +void nvlist_append_bool_array(nvlist_t *nvl, const char *name, const bool value); +void nvlist_append_number_array(nvlist_t *nvl, const char *name, const uint64_t value); +void nvlist_append_string_array(nvlist_t *nvl, const char *name, const char * const value); +void nvlist_append_nvlist_array(nvlist_t *nvl, const char *name, const nvlist_t * const value); +#ifndef _KERNEL +void nvlist_append_descriptor_array(nvlist_t *nvl, const char *name, int value); +#endif + /* * The nvlist_move functions add the given name/value pair. * The functions consumes provided buffer. Index: tests/sys/audit/Makefile =================================================================== --- tests/sys/audit/Makefile +++ tests/sys/audit/Makefile @@ -10,6 +10,7 @@ ATF_TESTS_C+= file-write ATF_TESTS_C+= file-read ATF_TESTS_C+= open +ATF_TESTS_C+= ioctl ATF_TESTS_C+= network ATF_TESTS_C+= inter-process ATF_TESTS_C+= administrative @@ -30,6 +31,8 @@ SRCS.file-read+= utils.c SRCS.open+= open.c SRCS.open+= utils.c +SRCS.ioctl+= ioctl.c +SRCS.ioctl+= utils.c SRCS.network+= network.c SRCS.network+= utils.c SRCS.inter-process+= inter-process.c Index: tests/sys/audit/administrative.c =================================================================== --- tests/sys/audit/administrative.c +++ tests/sys/audit/administrative.c @@ -39,7 +39,7 @@ static int filedesc; static mode_t mode = 0777; static struct pollfd fds[1]; -static char adregex[60]; +static char adregex[80]; static const char *auclass = "ad"; static const char *path = "fileforaudit"; @@ -200,6 +200,301 @@ } +ATF_TC_WITH_CLEANUP(getauid_success); +ATF_TC_HEAD(getauid_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "getauid(2) call"); +} + +ATF_TC_BODY(getauid_success, tc) +{ + au_id_t auid; + pid = getpid(); + snprintf(adregex, sizeof(adregex), "getauid.*%d.*return,success", pid); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, getauid(&auid)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getauid_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(getauid_failure); +ATF_TC_HEAD(getauid_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "getauid(2) call"); +} + +ATF_TC_BODY(getauid_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), "getauid.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, getauid(NULL)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getauid_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setauid_success); +ATF_TC_HEAD(setauid_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "setauid(2) call"); +} + +ATF_TC_BODY(setauid_success, tc) +{ + au_id_t auid; + pid = getpid(); + snprintf(adregex, sizeof(adregex), "setauid.*%d.*return,success", pid); + ATF_REQUIRE_EQ(0, getauid(&auid)); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, setauid(&auid)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setauid_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setauid_failure); +ATF_TC_HEAD(setauid_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "setauid(2) call"); +} + +ATF_TC_BODY(setauid_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), "setauid.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, setauid(NULL)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setauid_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(getaudit_success); +ATF_TC_HEAD(getaudit_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "getaudit(2) call"); +} + +ATF_TC_BODY(getaudit_success, tc) +{ + pid = getpid(); + auditinfo_t auditinfo; + snprintf(adregex, sizeof(adregex), "getaudit.*%d.*return,success", pid); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, getaudit(&auditinfo)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getaudit_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(getaudit_failure); +ATF_TC_HEAD(getaudit_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "getaudit(2) call"); +} + +ATF_TC_BODY(getaudit_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), "getaudit.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, getaudit(NULL)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getaudit_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setaudit_success); +ATF_TC_HEAD(setaudit_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "setaudit(2) call"); +} + +ATF_TC_BODY(setaudit_success, tc) +{ + pid = getpid(); + auditinfo_t auditinfo; + snprintf(adregex, sizeof(adregex), "setaudit.*%d.*return,success", pid); + ATF_REQUIRE_EQ(0, getaudit(&auditinfo)); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, setaudit(&auditinfo)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setaudit_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setaudit_failure); +ATF_TC_HEAD(setaudit_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "setaudit(2) call"); +} + +ATF_TC_BODY(setaudit_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), "setaudit.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, setaudit(NULL)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setaudit_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(getaudit_addr_success); +ATF_TC_HEAD(getaudit_addr_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "getaudit_addr(2) call"); +} + +ATF_TC_BODY(getaudit_addr_success, tc) +{ + pid = getpid(); + auditinfo_addr_t auditinfo; + snprintf(adregex, sizeof(adregex), + "getaudit_addr.*%d.*return,success", pid); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, getaudit_addr(&auditinfo, sizeof(auditinfo))); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getaudit_addr_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(getaudit_addr_failure); +ATF_TC_HEAD(getaudit_addr_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "getaudit_addr(2) call"); +} + +ATF_TC_BODY(getaudit_addr_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), + "getaudit_addr.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, getaudit_addr(NULL, 0)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(getaudit_addr_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setaudit_addr_success); +ATF_TC_HEAD(setaudit_addr_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "setaudit_addr(2) call"); +} + +ATF_TC_BODY(setaudit_addr_success, tc) +{ + pid = getpid(); + auditinfo_addr_t auditinfo; + snprintf(adregex, sizeof(adregex), + "setaudit_addr.*%d.*return,success", pid); + + ATF_REQUIRE_EQ(0, getaudit_addr(&auditinfo, sizeof(auditinfo))); + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(0, setaudit_addr(&auditinfo, sizeof(auditinfo))); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setaudit_addr_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(setaudit_addr_failure); +ATF_TC_HEAD(setaudit_addr_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "setaudit_addr(2) call"); +} + +ATF_TC_BODY(setaudit_addr_failure, tc) +{ + pid = getpid(); + snprintf(adregex, sizeof(adregex), + "setaudit_addr.*%d.*return,failure", pid); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Bad address */ + ATF_REQUIRE_EQ(-1, setaudit_addr(NULL, 0)); + check_audit(fds, adregex, pipefd); +} + +ATF_TC_CLEANUP(setaudit_addr_failure, tc) +{ + cleanup(); +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, settimeofday_success); @@ -210,5 +505,20 @@ ATF_TP_ADD_TC(tp, nfs_getfh_success); ATF_TP_ADD_TC(tp, nfs_getfh_failure); + ATF_TP_ADD_TC(tp, getauid_success); + ATF_TP_ADD_TC(tp, getauid_failure); + ATF_TP_ADD_TC(tp, setauid_success); + ATF_TP_ADD_TC(tp, setauid_failure); + + ATF_TP_ADD_TC(tp, getaudit_success); + ATF_TP_ADD_TC(tp, getaudit_failure); + ATF_TP_ADD_TC(tp, setaudit_success); + ATF_TP_ADD_TC(tp, setaudit_failure); + + ATF_TP_ADD_TC(tp, getaudit_addr_success); + ATF_TP_ADD_TC(tp, getaudit_addr_failure); + ATF_TP_ADD_TC(tp, setaudit_addr_success); + ATF_TP_ADD_TC(tp, setaudit_addr_failure); + return (atf_no_error()); } Index: tests/sys/audit/file-attribute-modify.c =================================================================== --- tests/sys/audit/file-attribute-modify.c +++ tests/sys/audit/file-attribute-modify.c @@ -25,6 +25,8 @@ * $FreeBSD$ */ +#include +#include #include #include @@ -37,11 +39,13 @@ static pid_t pid; static uid_t uid = -1; static gid_t gid = -1; -static int filedesc; +static int filedesc, retval; static struct pollfd fds[1]; static mode_t mode = 0777; static char extregex[80]; +static const char *buff = "ezio"; static const char *auclass = "fm"; +static const char *name = "authorname"; static const char *path = "fileforaudit"; static const char *errpath = "adirhasnoname/fileforaudit"; static const char *successreg = "fileforaudit.*return,success"; @@ -685,6 +689,333 @@ } +ATF_TC_WITH_CLEANUP(extattr_set_file_success); +ATF_TC_HEAD(extattr_set_file_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_set_file(2) call"); +} + +ATF_TC_BODY(extattr_set_file_success, tc) +{ + /* File needs to exist to call extattr_set_file(2) */ + ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1); + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_file.*%s.*%s.*return,success", path, name); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_file(path, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + check_audit(fds, extregex, pipefd); + close(filedesc); +} + +ATF_TC_CLEANUP(extattr_set_file_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_set_file_failure); +ATF_TC_HEAD(extattr_set_file_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_set_file(2) call"); +} + +ATF_TC_BODY(extattr_set_file_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_file.*%s.*%s.*failure", path, name); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: file does not exist */ + ATF_REQUIRE_EQ(-1, extattr_set_file(path, + EXTATTR_NAMESPACE_USER, name, NULL, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_set_file_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_set_fd_success); +ATF_TC_HEAD(extattr_set_fd_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_set_fd(2) call"); +} + +ATF_TC_BODY(extattr_set_fd_success, tc) +{ + /* File needs to exist to call extattr_set_fd(2) */ + ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1); + + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_fd.*%s.*return,success", name); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_fd(filedesc, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + check_audit(fds, extregex, pipefd); + close(filedesc); +} + +ATF_TC_CLEANUP(extattr_set_fd_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_set_fd_failure); +ATF_TC_HEAD(extattr_set_fd_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_set_fd(2) call"); +} + +ATF_TC_BODY(extattr_set_fd_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_fd.*%s.*return,failure : Bad file descriptor", name); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid file descriptor */ + ATF_REQUIRE_EQ(-1, extattr_set_fd(-1, + EXTATTR_NAMESPACE_USER, name, NULL, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_set_fd_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_set_link_success); +ATF_TC_HEAD(extattr_set_link_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_set_link(2) call"); +} + +ATF_TC_BODY(extattr_set_link_success, tc) +{ + /* Symbolic link needs to exist to call extattr_set_link(2) */ + ATF_REQUIRE_EQ(0, symlink("symlink", path)); + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_link.*%s.*%s.*return,success", path, name); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_link(path, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_set_link_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_set_link_failure); +ATF_TC_HEAD(extattr_set_link_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_set_link(2) call"); +} + +ATF_TC_BODY(extattr_set_link_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_set_link.*%s.*%s.*failure", path, name); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: symbolic link does not exist */ + ATF_REQUIRE_EQ(-1, extattr_set_link(path, + EXTATTR_NAMESPACE_USER, name, NULL, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_set_link_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_file_success); +ATF_TC_HEAD(extattr_delete_file_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_delete_file(2) call"); +} + +ATF_TC_BODY(extattr_delete_file_success, tc) +{ + /* File needs to exist to call extattr_delete_file(2) */ + ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_file(path, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((retval = extattr_delete_file(path, + EXTATTR_NAMESPACE_USER, name)) != -1); + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_file.*%s.*return,success,%d", path, retval); + check_audit(fds, extregex, pipefd); + close(filedesc); +} + +ATF_TC_CLEANUP(extattr_delete_file_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_file_failure); +ATF_TC_HEAD(extattr_delete_file_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_delete_file(2) call"); +} + +ATF_TC_BODY(extattr_delete_file_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_file.*%s.*return,failure", path); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: file does not exist */ + ATF_REQUIRE_EQ(-1, extattr_delete_file(path, + EXTATTR_NAMESPACE_USER, name)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_delete_file_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_fd_success); +ATF_TC_HEAD(extattr_delete_fd_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_delete_fd(2) call"); +} + +ATF_TC_BODY(extattr_delete_fd_success, tc) +{ + /* File needs to exist to call extattr_delete_fd(2) */ + ATF_REQUIRE((filedesc = open(path, O_CREAT, mode)) != -1); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_file(path, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((retval = extattr_delete_fd(filedesc, + EXTATTR_NAMESPACE_USER, name)) != -1); + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_fd.*return,success,%d", retval); + check_audit(fds, extregex, pipefd); + close(filedesc); +} + +ATF_TC_CLEANUP(extattr_delete_fd_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_fd_failure); +ATF_TC_HEAD(extattr_delete_fd_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_delete_fd(2) call"); +} + +ATF_TC_BODY(extattr_delete_fd_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_fd.*return,failure : Bad file descriptor"); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid file descriptor */ + ATF_REQUIRE_EQ(-1, extattr_delete_fd(-1, EXTATTR_NAMESPACE_USER, name)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_delete_fd_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_link_success); +ATF_TC_HEAD(extattr_delete_link_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "extattr_delete_link(2) call"); +} + +ATF_TC_BODY(extattr_delete_link_success, tc) +{ + /* Symbolic link needs to exist to call extattr_delete_link(2) */ + ATF_REQUIRE_EQ(0, symlink("symlink", path)); + ATF_REQUIRE_EQ(sizeof(buff), extattr_set_link(path, + EXTATTR_NAMESPACE_USER, name, buff, sizeof(buff))); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((retval = extattr_delete_link(path, + EXTATTR_NAMESPACE_USER, name)) != -1); + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_link.*%s.*return,success,%d", path, retval); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_delete_link_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(extattr_delete_link_failure); +ATF_TC_HEAD(extattr_delete_link_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "extattr_delete_link(2) call"); +} + +ATF_TC_BODY(extattr_delete_link_failure, tc) +{ + /* Prepare the regex to be checked in the audit record */ + snprintf(extregex, sizeof(extregex), + "extattr_delete_link.*%s.*failure", path); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: symbolic link does not exist */ + ATF_REQUIRE_EQ(-1, extattr_delete_link(path, + EXTATTR_NAMESPACE_USER, name)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(extattr_delete_link_failure, tc) +{ + cleanup(); +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, flock_success); @@ -719,5 +1050,19 @@ ATF_TP_ADD_TC(tp, lchflags_success); ATF_TP_ADD_TC(tp, lchflags_failure); + ATF_TP_ADD_TC(tp, extattr_set_file_success); + ATF_TP_ADD_TC(tp, extattr_set_file_failure); + ATF_TP_ADD_TC(tp, extattr_set_fd_success); + ATF_TP_ADD_TC(tp, extattr_set_fd_failure); + ATF_TP_ADD_TC(tp, extattr_set_link_success); + ATF_TP_ADD_TC(tp, extattr_set_link_failure); + + ATF_TP_ADD_TC(tp, extattr_delete_file_success); + ATF_TP_ADD_TC(tp, extattr_delete_file_failure); + ATF_TP_ADD_TC(tp, extattr_delete_fd_success); + ATF_TP_ADD_TC(tp, extattr_delete_fd_failure); + ATF_TP_ADD_TC(tp, extattr_delete_link_success); + ATF_TP_ADD_TC(tp, extattr_delete_link_failure); + return (atf_no_error()); } Index: tests/sys/audit/inter-process.c =================================================================== --- tests/sys/audit/inter-process.c +++ tests/sys/audit/inter-process.c @@ -460,7 +460,7 @@ /* Check for shared memory ID and process address in record */ snprintf(ipcregex, sizeof(ipcregex), "shmat.*Shared Memory " - "IPC.*%d.*return,success,%d", shmid, (int)addr); + "IPC.*%d.*return,success", shmid); check_audit(fds, ipcregex, pipefd); /* Destroy the shared memory with ID = shmid */ Index: tests/sys/audit/ioctl.c =================================================================== --- /dev/null +++ tests/sys/audit/ioctl.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2018 Aniket Pandey + * + * 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 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include + +#include +#include + +#include +#include +#include + +#include "utils.h" + +static int filedesc; +static char ioregex[80]; +static const char *auclass = "io"; +static struct pollfd fds[1]; +static unsigned long request = AUDITPIPE_FLUSH; + + +ATF_TC_WITH_CLEANUP(ioctl_success); +ATF_TC_HEAD(ioctl_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "ioctl(2) call"); +} + +ATF_TC_BODY(ioctl_success, tc) +{ + /* auditpipe(4) supports quite a few ioctls */ + ATF_REQUIRE((filedesc = open("/dev/auditpipe", O_RDONLY)) != -1); + /* Prepare the regex to be checked in the audit record */ + snprintf(ioregex, sizeof(ioregex), + "ioctl.*%#lx.*%#x.*return,success", request, filedesc); + + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE(ioctl(filedesc, request) != -1); + check_audit(fds, ioregex, pipefd); + close(filedesc); +} + +ATF_TC_CLEANUP(ioctl_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(ioctl_failure); +ATF_TC_HEAD(ioctl_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "ioctl(2) call"); +} + +ATF_TC_BODY(ioctl_failure, tc) +{ + snprintf(ioregex, sizeof(ioregex), + "ioctl.*%#lx.*return,failure : Bad file descriptor", request); + + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid file descriptor */ + ATF_REQUIRE_EQ(-1, ioctl(-1, request)); + check_audit(fds, ioregex, pipefd); +} + +ATF_TC_CLEANUP(ioctl_failure, tc) +{ + cleanup(); +} + + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, ioctl_success); + ATF_TP_ADD_TC(tp, ioctl_failure); + + return (atf_no_error()); +} Index: tests/sys/audit/network.c =================================================================== --- tests/sys/audit/network.c +++ tests/sys/audit/network.c @@ -32,16 +32,20 @@ #include #include #include -#include #include "utils.h" +#define MAX_DATA 1024 #define SERVER_PATH "server" -static int sockfd, sockfd2; -static socklen_t len; +static int sockfd, sockfd2, connectfd; +static ssize_t data_bytes; static struct pollfd fds[1]; +static struct sockaddr_un server; static char extregex[80]; +static char data[MAX_DATA]; +static socklen_t len = sizeof(struct sockaddr_un); +static char msgbuff[MAX_DATA] = "This message does not exist"; static const char *auclass = "nt"; static const char *nosupregex = "return,failure : Address family " "not supported by protocol family"; @@ -66,11 +70,11 @@ * Assign local filesystem address to a Unix domain socket */ static void -assign_address(struct sockaddr_un *server) +assign_address(struct sockaddr_un *serveraddr) { - memset(server, 0, sizeof(*server)); - server->sun_family = AF_UNIX; - strcpy(server->sun_path, SERVER_PATH); + memset(serveraddr, 0, sizeof(*serveraddr)); + serveraddr->sun_family = AF_UNIX; + strcpy(serveraddr->sun_path, SERVER_PATH); } @@ -203,12 +207,10 @@ ATF_TC_BODY(setsockopt_failure, tc) { - int tr = 1; snprintf(extregex, sizeof(extregex), "setsockopt.*%s", invalregex); FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid socket descriptor */ - ATF_REQUIRE_EQ(-1, setsockopt(-1, SOL_SOCKET, - SO_REUSEADDR, &tr, sizeof(int))); + ATF_REQUIRE_EQ(-1, setsockopt(-1, SOL_SOCKET, 0, NULL, 0)); check_audit(fds, extregex, pipefd); } @@ -227,10 +229,7 @@ ATF_TC_BODY(bind_success, tc) { - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - /* Preliminary socket setup */ ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); /* Check the presence of AF_UNIX address path in audit record */ @@ -258,10 +257,7 @@ ATF_TC_BODY(bind_failure, tc) { - /* Preliminary socket setup */ - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); /* Check the presence of AF_UNIX path in audit record */ snprintf(extregex, sizeof(extregex), "bind.*%s.*return,failure", SERVER_PATH); @@ -287,10 +283,7 @@ ATF_TC_BODY(bindat_success, tc) { - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - /* Preliminary socket setup */ ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); /* Check the presence of socket descriptor in audit record */ @@ -319,10 +312,7 @@ ATF_TC_BODY(bindat_failure, tc) { - /* Preliminary socket setup */ - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); snprintf(extregex, sizeof(extregex), "bindat.*%s", invalregex); FILE *pipefd = setup(fds, auclass); @@ -347,10 +337,7 @@ ATF_TC_BODY(listen_success, tc) { - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - /* Preliminary socket setup */ ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); @@ -401,14 +388,9 @@ ATF_TC_BODY(connect_success, tc) { - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - - /* Setup a non-blocking server socket */ - ATF_REQUIRE((sockfd = socket(PF_UNIX, - SOCK_STREAM | SOCK_NONBLOCK, 0)) != -1); - /* Bind to the specified address and wait for connection */ + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); ATF_REQUIRE_EQ(0, listen(sockfd, 1)); @@ -442,11 +424,7 @@ ATF_TC_BODY(connect_failure, tc) { - /* Preliminary socket setup */ - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - /* Audit record must contain AF_UNIX address path */ snprintf(extregex, sizeof(extregex), "connect.*%s.*return,failure", SERVER_PATH); @@ -472,14 +450,9 @@ ATF_TC_BODY(connectat_success, tc) { - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - - /* Setup a non-blocking server socket */ - ATF_REQUIRE((sockfd = socket(PF_UNIX, - SOCK_STREAM | SOCK_NONBLOCK, 0)) != -1); - /* Bind to the specified address and wait for connection */ + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); ATF_REQUIRE_EQ(0, listen(sockfd, 1)); @@ -514,10 +487,7 @@ ATF_TC_BODY(connectat_failure, tc) { - /* Preliminary socket setup */ - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); snprintf(extregex, sizeof(extregex), "connectat.*%s", invalregex); FILE *pipefd = setup(fds, auclass); @@ -542,15 +512,9 @@ ATF_TC_BODY(accept_success, tc) { - int clientfd; - struct sockaddr_un server; assign_address(&server); - len = sizeof(struct sockaddr_un); - - /* Setup a non-blocking server socket */ - ATF_REQUIRE((sockfd = socket(PF_UNIX, - SOCK_STREAM | SOCK_NONBLOCK, 0)) != -1); - /* Bind to the specified address and wait for connection */ + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); ATF_REQUIRE_EQ(0, listen(sockfd, 1)); @@ -559,15 +523,15 @@ ATF_REQUIRE_EQ(0, connect(sockfd2, (struct sockaddr *)&server, len)); FILE *pipefd = setup(fds, auclass); - ATF_REQUIRE((clientfd = accept(sockfd, NULL, &len)) != -1); + ATF_REQUIRE((connectfd = accept(sockfd, NULL, &len)) != -1); - /* Audit record must contain clientfd & sockfd */ + /* Audit record must contain connectfd & sockfd */ snprintf(extregex, sizeof(extregex), - "accept.*0x%x.*return,success,%d", sockfd, clientfd); + "accept.*0x%x.*return,success,%d", sockfd, connectfd); check_audit(fds, extregex, pipefd); /* Close all socket descriptors */ - close_sockets(3, sockfd, sockfd2, clientfd); + close_sockets(3, sockfd, sockfd2, connectfd); } ATF_TC_CLEANUP(accept_success, tc) @@ -585,14 +549,10 @@ ATF_TC_BODY(accept_failure, tc) { - /* Preliminary socket setup */ - struct sockaddr_un client; - len = sizeof(struct sockaddr_un); snprintf(extregex, sizeof(extregex), "accept.*%s", invalregex); - FILE *pipefd = setup(fds, auclass); /* Failure reason: Invalid socket descriptor */ - ATF_REQUIRE_EQ(-1, accept(-1, (struct sockaddr *)&client, &len)); + ATF_REQUIRE_EQ(-1, accept(-1, NULL, NULL)); check_audit(fds, extregex, pipefd); } @@ -602,6 +562,252 @@ } +ATF_TC_WITH_CLEANUP(send_success); +ATF_TC_HEAD(send_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "send(2) call"); +} + +ATF_TC_BODY(send_success, tc) +{ + assign_address(&server); + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); + ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); + ATF_REQUIRE_EQ(0, listen(sockfd, 1)); + + /* Set up "blocking" client and connect with non-blocking server */ + ATF_REQUIRE((sockfd2 = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); + ATF_REQUIRE_EQ(0, connect(sockfd2, (struct sockaddr *)&server, len)); + ATF_REQUIRE((connectfd = accept(sockfd, NULL, &len)) != -1); + + /* Send a sample message to the connected socket */ + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((data_bytes = + send(sockfd2, msgbuff, strlen(msgbuff), 0)) != -1); + + /* Audit record must contain sockfd2 and data_bytes */ + snprintf(extregex, sizeof(extregex), + "send.*0x%x.*return,success,%zd", sockfd2, data_bytes); + check_audit(fds, extregex, pipefd); + + /* Close all socket descriptors */ + close_sockets(3, sockfd, sockfd2, connectfd); +} + +ATF_TC_CLEANUP(send_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(send_failure); +ATF_TC_HEAD(send_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "send(2) call"); +} + +ATF_TC_BODY(send_failure, tc) +{ + snprintf(extregex, sizeof(extregex), "send.*%s", invalregex); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid socket descriptor */ + ATF_REQUIRE_EQ(-1, send(-1, NULL, 0, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(send_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(recv_success); +ATF_TC_HEAD(recv_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "recv(2) call"); +} + +ATF_TC_BODY(recv_success, tc) +{ + assign_address(&server); + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); + ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); + ATF_REQUIRE_EQ(0, listen(sockfd, 1)); + + /* Set up "blocking" client and connect with non-blocking server */ + ATF_REQUIRE((sockfd2 = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); + ATF_REQUIRE_EQ(0, connect(sockfd2, (struct sockaddr *)&server, len)); + ATF_REQUIRE((connectfd = accept(sockfd, NULL, &len)) != -1); + /* Send a sample message to the connected socket */ + ATF_REQUIRE(send(sockfd2, msgbuff, strlen(msgbuff), 0) != -1); + + /* Receive data once connectfd is ready for reading */ + FILE *pipefd = setup(fds, auclass); + //ATF_REQUIRE(check_readfs(connectfd) != 0); + ATF_REQUIRE((data_bytes = recv(connectfd, data, MAX_DATA, 0)) != 0); + + /* Audit record must contain connectfd and data_bytes */ + snprintf(extregex, sizeof(extregex), + "recv.*0x%x.*return,success,%zd", connectfd, data_bytes); + check_audit(fds, extregex, pipefd); + + /* Close all socket descriptors */ + close_sockets(3, sockfd, sockfd2, connectfd); +} + +ATF_TC_CLEANUP(recv_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(recv_failure); +ATF_TC_HEAD(recv_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "recv(2) call"); +} + +ATF_TC_BODY(recv_failure, tc) +{ + snprintf(extregex, sizeof(extregex), "recv.*%s", invalregex); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid socket descriptor */ + ATF_REQUIRE_EQ(-1, recv(-1, NULL, 0, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(recv_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(sendto_success); +ATF_TC_HEAD(sendto_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "sendto(2) call"); +} + +ATF_TC_BODY(sendto_success, tc) +{ + assign_address(&server); + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) != -1); + ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); + + /* Set up client socket to be used for sending the data */ + ATF_REQUIRE((sockfd2 = socket(PF_UNIX, SOCK_DGRAM, 0)) != -1); + + /* Send a sample message to server's address */ + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((data_bytes = sendto(sockfd2, msgbuff, + strlen(msgbuff), 0, (struct sockaddr *)&server, len)) != -1); + + /* Audit record must contain sockfd2 and data_bytes */ + snprintf(extregex, sizeof(extregex), + "sendto.*0x%x.*return,success,%zd", sockfd2, data_bytes); + check_audit(fds, extregex, pipefd); + + /* Close all socket descriptors */ + close_sockets(2, sockfd, sockfd2); +} + +ATF_TC_CLEANUP(sendto_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(sendto_failure); +ATF_TC_HEAD(sendto_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "sendto(2) call"); +} + +ATF_TC_BODY(sendto_failure, tc) +{ + snprintf(extregex, sizeof(extregex), "sendto.*%s", invalregex); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid socket descriptor */ + ATF_REQUIRE_EQ(-1, sendto(-1, NULL, 0, 0, NULL, 0)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(sendto_failure, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(recvfrom_success); +ATF_TC_HEAD(recvfrom_success, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " + "recvfrom(2) call"); +} + +ATF_TC_BODY(recvfrom_success, tc) +{ + assign_address(&server); + /* Setup a server socket and bind to the specified address */ + ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_DGRAM, 0)) != -1); + ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); + + /* Set up client socket to be used for sending the data */ + ATF_REQUIRE((sockfd2 = socket(PF_UNIX, SOCK_DGRAM, 0)) != -1); + ATF_REQUIRE(sendto(sockfd2, msgbuff, strlen(msgbuff), 0, + (struct sockaddr *)&server, len) != -1); + + /* Receive data once sockfd is ready for reading */ + FILE *pipefd = setup(fds, auclass); + ATF_REQUIRE((data_bytes = recvfrom(sockfd, data, + MAX_DATA, 0, NULL, &len)) != 0); + + /* Audit record must contain sockfd and data_bytes */ + snprintf(extregex, sizeof(extregex), + "recvfrom.*0x%x.*return,success,%zd", sockfd, data_bytes); + check_audit(fds, extregex, pipefd); + + /* Close all socket descriptors */ + close_sockets(2, sockfd, sockfd2); +} + +ATF_TC_CLEANUP(recvfrom_success, tc) +{ + cleanup(); +} + + +ATF_TC_WITH_CLEANUP(recvfrom_failure); +ATF_TC_HEAD(recvfrom_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " + "recvfrom(2) call"); +} + +ATF_TC_BODY(recvfrom_failure, tc) +{ + snprintf(extregex, sizeof(extregex), "recvfrom.*%s", invalregex); + FILE *pipefd = setup(fds, auclass); + /* Failure reason: Invalid socket descriptor */ + ATF_REQUIRE_EQ(-1, recvfrom(-1, NULL, 0, 0, NULL, NULL)); + check_audit(fds, extregex, pipefd); +} + +ATF_TC_CLEANUP(recvfrom_failure, tc) +{ + cleanup(); +} + + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, socket_success); @@ -625,5 +831,15 @@ ATF_TP_ADD_TC(tp, accept_success); ATF_TP_ADD_TC(tp, accept_failure); + ATF_TP_ADD_TC(tp, send_success); + ATF_TP_ADD_TC(tp, send_failure); + ATF_TP_ADD_TC(tp, recv_success); + ATF_TP_ADD_TC(tp, recv_failure); + + ATF_TP_ADD_TC(tp, sendto_success); + ATF_TP_ADD_TC(tp, sendto_failure); + ATF_TP_ADD_TC(tp, recvfrom_success); + ATF_TP_ADD_TC(tp, recvfrom_failure); + return (atf_no_error()); } Index: tools/boot/rootgen.sh =================================================================== --- tools/boot/rootgen.sh +++ tools/boot/rootgen.sh @@ -2,6 +2,8 @@ # $FreeBSD$ +do_boot1_efi=0 + # # Builds all the bat-shit crazy combinations we support booting from, # at least for amd64. It assume you have a ~sane kernel in /boot/kernel @@ -29,6 +31,29 @@ (cd $src ; tar cf - .) | (cd $dst; tar xf -) } +make_esp() +{ + local src dst md mntpt + src=$1 + dst=$2 + + if [ "${do_boot1_efi}" -eq 1 ]; then + cp ${src}/boot/boot1.efifat ${dst} + else + dd if=/dev/zero of=${dst} count=1 seek=$((100 * 1024 * 1024 / 512)) + md=$(mdconfig -f ${dst}) + newfs_msdos -a 32 /dev/${md} + mntpt=$(mktemp -d /tmp/stand-test.XXXXXX) + mount -t msdos /dev/${md} ${mntpt} +# mkdir -p ${mntpt}/efi/freebsd # not yet + mkdir -p ${mntpt}/efi/boot + cp ${src}/boot/loader.efi ${mntpt}/efi/boot/bootx64.efi + umount ${mntpt} + rmdir ${mntpt} + mdconfig -d -u ${md} + fi +} + mk_nogeli_gpt_ufs_legacy() { src=$1 img=$2 @@ -50,8 +75,7 @@ cat > ${src}/etc/fstab < ${src}/etc/fstab < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${src}/etc/fstab < ${src}/etc/fstab < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${mntpt}/boot/loader.conf <> ${mntpt}/boot/loader.conf < ${DESTDIR}/boot.config +cat > ${DESTDIR}/boot/loader.conf < ${DESTDIR}/etc/rc < Index: usr.bin/top/machine.h =================================================================== --- usr.bin/top/machine.h +++ usr.bin/top/machine.h @@ -78,7 +78,7 @@ /* routines defined by the machine dependent module */ -const char *format_header(const char *uname_field); +char *format_header(const char *uname_field); char *format_next_process(void* handle, char *(*get_userid)(int), int flags); void toggle_pcpustats(void); Index: usr.bin/top/machine.c =================================================================== --- usr.bin/top/machine.c +++ usr.bin/top/machine.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -49,8 +50,6 @@ #include "layout.h" #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) -#define SMPUNAMELEN 13 -#define UPUNAMELEN 15 extern struct timeval timeout; static int smpmode; @@ -59,8 +58,6 @@ /* TOP_JID_LEN based on max of 999999 */ #define TOP_JID_LEN 7 #define TOP_SWAP_LEN 6 -static int jidlength; -static int swaplength; static int cmdlengthdelta; /* get_process_info passes back a handle. This is what it looks like: */ @@ -87,29 +84,17 @@ */ static const char io_header[] = - " PID%*s %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; + " %s%*s %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; static const char io_Proc_format[] = "%5d%*s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s"; -/* XXX: build up header instead of statically defining them. - * This will also allow for a "format string" to be supplied - * as an argument to top(1) instead of having predefined options */ -static const char smp_header_thr_and_pid[] = - " %s%*s %-*.*s THR PRI NICE SIZE RES%*s STATE C TIME %7s COMMAND"; -static const char smp_header_id_only[] = - " %s%*s %-*.*s PRI NICE SIZE RES%*s STATE C TIME %7s COMMAND"; static const char smp_Proc_format[] = "%5d%*s %-*.*s %s%3d %4s%7s %6s%*.*s %-6.6s %2d%7s %6.2f%% %.*s"; -static char up_header_thr_and_pid[] = - " PID%*s %-*.*s THR PRI NICE SIZE RES%*s STATE TIME %7s COMMAND"; -static char up_header_id_only[] = - " %s%*s %-*.*s PRI NICE SIZE RES%*s STATE TIME %7s COMMAND"; static char up_Proc_format[] = "%5d%*s %-*.*s %s%3d %4s%7s %6s%*.*s %-6.6s%.0d%7s %6.2f%% %.*s"; - /* process state names for the "STATE" column of the display */ /* the extra nulls in the string "run" are for adding a slash and the processor number when needed */ @@ -325,12 +310,6 @@ NULL, 0) == 0 && carc_en == 1) carc_enabled = 1; - namelength = MAXLOGNAME; - if (smpmode && namelength > SMPUNAMELEN) - namelength = SMPUNAMELEN; - else if (namelength > UPUNAMELEN) - namelength = UPUNAMELEN; - kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); if (kd == NULL) return (-1); @@ -407,62 +386,46 @@ return (0); } -const char * +char * format_header(const char *uname_field) { - static char Header[128]; - const char *prehead; + static struct sbuf* header = NULL; - if (ps.jail) - jidlength = TOP_JID_LEN + 1; /* +1 for extra left space. */ - else - jidlength = 0; - - if (ps.swap) - swaplength = TOP_SWAP_LEN + 1; /* +1 for extra left space */ - else - swaplength = 0; + /* clean up from last time. */ + if (header != NULL) { + sbuf_delete(header); + } + header = sbuf_new_auto(); switch (displaymode) { - case DISP_CPU: - /* - * The logic of picking the right header is confusing, and - * depends on too much. We should instead have a struct of - * "header name", and "header format" which we build up. - * This would also fix the duplicate of effort into up vs smp - * mode. - */ - if (smpmode) { - prehead = ps.thread ? - smp_header_id_only : smp_header_thr_and_pid; - snprintf(Header, sizeof(Header), prehead, - ps.thread_id ? " THR" : "PID", - jidlength, ps.jail ? " JID" : "", - namelength, namelength, uname_field, - swaplength, ps.swap ? " SWAP" : "", - ps.wcpu ? "WCPU" : "CPU"); - } else { - prehead = ps.thread ? - up_header_id_only : up_header_thr_and_pid; - snprintf(Header, sizeof(Header), prehead, - ps.thread_id ? " THR" : "PID", - jidlength, ps.jail ? " JID" : "", - namelength, namelength, uname_field, - swaplength, ps.swap ? " SWAP" : "", - ps.wcpu ? "WCPU" : "CPU"); - } + case DISP_CPU: { + sbuf_printf(header, " %s", ps.thread_id ? " THR" : "PID"); + sbuf_printf(header, "%*s", ps.jail ? TOP_JID_LEN + 1 : 0, + ps.jail ? " JID" : ""); + sbuf_printf(header, " %-*.*s", namelength, namelength, uname_field); + sbuf_cat(header, " THR PRI NICE SIZE RES"); + sbuf_printf(header, "%*s", ps.swap ? TOP_SWAP_LEN + 1 : 0, + ps.swap ? " SWAP" : ""); + sbuf_printf(header, "%s", smpmode ? " STATE C " : " STATE "); + sbuf_cat(header, "TIME"); + sbuf_printf(header, " %7s", ps.wcpu ? "WCPU" : "CPU"); + sbuf_cat(header, " COMMAND"); + sbuf_finish(header); break; - case DISP_IO: - prehead = io_header; - snprintf(Header, sizeof(Header), prehead, - jidlength, ps.jail ? " JID" : "", + } + case DISP_IO: { + sbuf_printf(header, io_header, + ps.thread_id ? " THR" : "PID", + ps.jail ? TOP_JID_LEN + 1 : 0, ps.jail ? " JID" : "", namelength, namelength, uname_field); break; + } case DISP_MAX: assert("displaymode must not be set to DISP_MAX"); } - cmdlengthdelta = strlen(Header) - 7; - return (Header); + + cmdlengthdelta = sbuf_len(header) - 7; + return sbuf_data(header); } static int swappgsin = -1; @@ -1080,13 +1043,13 @@ jid_buf[0] = '\0'; else snprintf(jid_buf, sizeof(jid_buf), "%*d", - jidlength - 1, pp->ki_jid); + TOP_JID_LEN, pp->ki_jid); if (ps.swap == 0) swap_buf[0] = '\0'; else snprintf(swap_buf, sizeof(swap_buf), "%*s", - swaplength - 1, + TOP_SWAP_LEN, format_k(pagetok(ki_swap(pp)))); /* XXX */ if (displaymode == DISP_IO) { @@ -1108,7 +1071,7 @@ snprintf(fmt, sizeof(fmt), io_Proc_format, pp->ki_pid, - jidlength, jid_buf, + ps.jail ? TOP_JID_LEN + 1 : 0, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), rup->ru_nvcsw, rup->ru_nivcsw, @@ -1143,14 +1106,14 @@ snprintf(fmt, sizeof(fmt), proc_fmt, (ps.thread_id) ? pp->ki_tid : pp->ki_pid, - jidlength, jid_buf, + ps.jail ? TOP_JID_LEN + 1 : 0, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), thr_buf, pp->ki_pri.pri_level - PZERO, format_nice(pp), format_k(PROCSIZE(pp)), format_k(pagetok(pp->ki_rssize)), - swaplength, swaplength, swap_buf, + ps.swap ? TOP_SWAP_LEN + 1 : 0, ps.swap ? TOP_SWAP_LEN + 1 : 0, swap_buf, status, cpu, format_time(cputime), Index: usr.bin/top/top.c =================================================================== --- usr.bin/top/top.c +++ usr.bin/top/top.c @@ -50,10 +50,6 @@ /* The buffer that stdio will use */ static char stdoutbuf[Buffersize]; -/* build Signal masks */ -#define Smask(s) (1 << ((s) - 1)) - - static int fmt_flags = 0; int pcpu_stats = false; @@ -233,7 +229,7 @@ static char tempbuf1[50]; static char tempbuf2[50]; - int old_sigmask; /* only used for BSD-style signals */ + sigset_t old_sigmask, new_sigmask; int topn = Infinity; double delay = 2; int displays = 0; /* indicates unspecified */ @@ -591,13 +587,18 @@ } /* hold interrupt signals while setting up the screen and the handlers */ - old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); + + sigemptyset(&new_sigmask); + sigaddset(&new_sigmask, SIGINT); + sigaddset(&new_sigmask, SIGQUIT); + sigaddset(&new_sigmask, SIGTSTP); + sigprocmask(SIG_BLOCK, &new_sigmask, &old_sigmask); init_screen(); signal(SIGINT, leave); signal(SIGQUIT, leave); signal(SIGTSTP, tstop); signal(SIGWINCH, top_winch); - sigsetmask(old_sigmask); + sigprocmask(SIG_SETMASK, &old_sigmask, NULL); if (warnings) { fputs("....", stderr); Index: usr.sbin/syslogd/syslogd.c =================================================================== --- usr.sbin/syslogd/syslogd.c +++ usr.sbin/syslogd/syslogd.c @@ -1613,8 +1613,8 @@ struct iovec *last; size_t diff; - while (size > il->totalsize) { - diff = size - il->totalsize; + while (il->totalsize > size) { + diff = il->totalsize - size; last = &il->iov[il->iovcnt - 1]; if (diff >= last->iov_len) { /* Remove the last iovec entirely. */