summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
m---------freebsd-org0
-rw-r--r--freebsd/contrib/libxo/libxo/libxo.c672
-rw-r--r--freebsd/contrib/libxo/libxo/xo.h2
-rw-r--r--freebsd/contrib/libxo/libxo/xo_buf.h2
-rw-r--r--freebsd/contrib/libxo/libxo/xo_encoder.c8
-rw-r--r--freebsd/contrib/libxo/libxo/xo_encoder.h5
-rw-r--r--freebsd/lib/libc/include/libc_private.h12
-rw-r--r--freebsd/lib/libc/net/nsdispatch.c9
-rw-r--r--freebsd/lib/libc/rpc/getnetconfig.c4
-rw-r--r--freebsd/lib/libc/rpc/rpc_generic.c8
-rw-r--r--freebsd/lib/libc/rpc/rpcb_clnt.c3
-rw-r--r--freebsd/lib/libc/rpc/rpcb_prot.c17
-rw-r--r--freebsd/lib/libc/rpc/rpcb_st_xdr.c9
-rw-r--r--freebsd/lib/libc/stdio/fgetln.c26
-rw-r--r--freebsd/lib/libc/stdio/local.h34
-rw-r--r--freebsd/lib/libc/xdr/xdr.c30
-rw-r--r--freebsd/sbin/sysctl/sysctl.c52
-rw-r--r--freebsd/sys/arm/ti/ti_sdhci.c33
-rw-r--r--freebsd/sys/cam/cam.h4
-rw-r--r--freebsd/sys/cam/cam_ccb.h128
-rw-r--r--freebsd/sys/cam/cam_xpt.h2
-rw-r--r--freebsd/sys/cam/mmc/mmc.h94
-rw-r--r--freebsd/sys/cam/mmc/mmc_all.h70
-rw-r--r--freebsd/sys/cam/mmc/mmc_bus.h5
-rw-r--r--freebsd/sys/cam/mmc/mmc_sdio.h64
-rw-r--r--freebsd/sys/cam/scsi/scsi_all.c4
-rw-r--r--freebsd/sys/dev/e1000/if_em.c219
-rw-r--r--freebsd/sys/dev/e1000/if_em.h24
-rw-r--r--freebsd/sys/dev/evdev/cdev.c19
-rw-r--r--freebsd/sys/dev/evdev/evdev.c24
-rw-r--r--freebsd/sys/dev/evdev/evdev_mt.c22
-rw-r--r--freebsd/sys/dev/evdev/evdev_private.h17
-rw-r--r--freebsd/sys/dev/evdev/evdev_utils.c11
-rw-r--r--freebsd/sys/dev/evdev/input-event-codes.h2
-rw-r--r--freebsd/sys/dev/evdev/input.h4
-rw-r--r--freebsd/sys/dev/evdev/uinput.c19
-rw-r--r--freebsd/sys/dev/evdev/uinput.h2
-rw-r--r--freebsd/sys/dev/ffec/if_ffec.c122
-rw-r--r--freebsd/sys/dev/mii/mii_fdt.c202
-rw-r--r--freebsd/sys/dev/mii/mii_fdt.h75
-rw-r--r--freebsd/sys/dev/mii/miivar.h36
-rw-r--r--freebsd/sys/dev/mmc/bridge.h8
-rw-r--r--freebsd/sys/dev/mmc/mmc.c848
-rw-r--r--freebsd/sys/dev/mmc/mmc_ioctl.h2
-rw-r--r--freebsd/sys/dev/mmc/mmc_private.h11
-rw-r--r--freebsd/sys/dev/mmc/mmc_subr.c20
-rw-r--r--freebsd/sys/dev/mmc/mmcbrvar.h16
-rw-r--r--freebsd/sys/dev/mmc/mmcreg.h119
-rw-r--r--freebsd/sys/dev/mmc/mmcsd.c298
-rw-r--r--freebsd/sys/dev/nvme/nvme.h30
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwn_rx.c22
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwnreg.h54
-rw-r--r--freebsd/sys/dev/rtwn/if_rtwnvar.h2
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c3
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c28
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h2
-rw-r--r--freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h5
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c28
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h43
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h2
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c2
-rw-r--r--freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c2
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h6
-rw-r--r--freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c2
-rw-r--r--freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c2
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c57
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c11
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c191
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c3
-rw-r--r--freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h14
-rw-r--r--freebsd/sys/dev/sdhci/sdhci.c1021
-rw-r--r--freebsd/sys/dev/sdhci/sdhci.h44
-rw-r--r--freebsd/sys/dev/tsec/if_tsec.c1
-rw-r--r--freebsd/sys/dev/usb/controller/saf1761_otg.c13
-rw-r--r--freebsd/sys/dev/usb/wlan/if_rsu.c24
-rw-r--r--freebsd/sys/dev/usb/wlan/if_zyd.c10
-rw-r--r--freebsd/sys/kern/init_main.c3
-rw-r--r--freebsd/sys/kern/kern_event.c185
-rw-r--r--freebsd/sys/kern/kern_linker.c8
-rw-r--r--freebsd/sys/kern/kern_uuid.c9
-rw-r--r--freebsd/sys/kern/subr_blist.c658
-rw-r--r--freebsd/sys/kern/subr_prf.c54
-rw-r--r--freebsd/sys/kern/subr_sbuf.c2
-rw-r--r--freebsd/sys/kern/subr_taskqueue.c25
-rw-r--r--freebsd/sys/kern/subr_uio.c47
-rw-r--r--freebsd/sys/kern/sys_socket.c78
-rw-r--r--freebsd/sys/kern/uipc_accf.c111
-rw-r--r--freebsd/sys/kern/uipc_mbuf.c2
-rw-r--r--freebsd/sys/kern/uipc_sockbuf.c82
-rw-r--r--freebsd/sys/kern/uipc_socket.c939
-rw-r--r--freebsd/sys/kern/uipc_syscalls.c65
-rw-r--r--freebsd/sys/kern/uipc_usrreq.c199
-rw-r--r--freebsd/sys/net/bpf.c14
-rw-r--r--freebsd/sys/net/ethernet.h6
-rw-r--r--freebsd/sys/net/if_enc.c2
-rw-r--r--freebsd/sys/net/if_enc.h1
-rw-r--r--freebsd/sys/net/if_ethersubr.c7
-rw-r--r--freebsd/sys/net/if_lagg.c5
-rw-r--r--freebsd/sys/net/if_stf.c7
-rw-r--r--freebsd/sys/net/iflib.h3
-rw-r--r--freebsd/sys/net/route.c106
-rw-r--r--freebsd/sys/net/route.h2
-rw-r--r--freebsd/sys/net80211/ieee80211_amrr.c3
-rw-r--r--freebsd/sys/net80211/ieee80211_output.c6
-rw-r--r--freebsd/sys/net80211/ieee80211_rssadapt.c5
-rw-r--r--freebsd/sys/netinet/cc/cc_newreno.c26
-rw-r--r--freebsd/sys/netinet/ip_output.c6
-rw-r--r--freebsd/sys/netinet/sctp_asconf.c16
-rw-r--r--freebsd/sys/netinet/sctp_auth.c115
-rw-r--r--freebsd/sys/netinet/sctp_constants.h2
-rw-r--r--freebsd/sys/netinet/sctp_indata.c388
-rw-r--r--freebsd/sys/netinet/sctp_input.c78
-rw-r--r--freebsd/sys/netinet/sctp_os_bsd.h4
-rw-r--r--freebsd/sys/netinet/sctp_output.c136
-rw-r--r--freebsd/sys/netinet/sctp_output.h5
-rw-r--r--freebsd/sys/netinet/sctp_pcb.c215
-rw-r--r--freebsd/sys/netinet/sctp_sysctl.c12
-rw-r--r--freebsd/sys/netinet/sctp_usrreq.c13
-rw-r--r--freebsd/sys/netinet/sctputil.c33
-rw-r--r--freebsd/sys/netinet/sctputil.h2
-rw-r--r--freebsd/sys/netinet/tcp_input.c41
-rw-r--r--freebsd/sys/netinet/tcp_output.c16
-rw-r--r--freebsd/sys/netinet/tcp_subr.c216
-rw-r--r--freebsd/sys/netinet/tcp_syncache.c11
-rw-r--r--freebsd/sys/netinet/tcp_syncache.h2
-rw-r--r--freebsd/sys/netinet/tcp_timewait.c2
-rw-r--r--freebsd/sys/netinet/tcp_var.h9
-rw-r--r--freebsd/sys/netinet6/ip6_output.c8
-rw-r--r--freebsd/sys/netinet6/sctp6_usrreq.c2
-rw-r--r--freebsd/sys/netipsec/ipsec.h3
-rw-r--r--freebsd/sys/netipsec/ipsec_input.c8
-rw-r--r--freebsd/sys/netipsec/ipsec_output.c24
-rw-r--r--freebsd/sys/netipsec/key_debug.c6
-rw-r--r--freebsd/sys/netpfil/pf/pf.c9
-rw-r--r--freebsd/sys/sys/_pctrie.h10
-rw-r--r--freebsd/sys/sys/ata.h4
-rw-r--r--freebsd/sys/sys/blist.h24
-rw-r--r--freebsd/sys/sys/buf.h1
-rw-r--r--freebsd/sys/sys/bus_dma.h82
-rw-r--r--freebsd/sys/sys/jail.h34
-rw-r--r--freebsd/sys/sys/module.h14
-rw-r--r--freebsd/sys/sys/proc.h7
-rw-r--r--freebsd/sys/sys/refcount.h16
-rw-r--r--freebsd/sys/sys/sockbuf.h11
-rw-r--r--freebsd/sys/sys/socketvar.h202
-rw-r--r--freebsd/sys/sys/sockopt.h4
-rw-r--r--freebsd/sys/sys/sysproto.h40
-rw-r--r--freebsd/sys/sys/systm.h2
-rw-r--r--freebsd/sys/sys/taskqueue.h3
-rw-r--r--freebsd/sys/sys/unpcb.h6
-rw-r--r--freebsd/sys/sys/uuid.h1
-rw-r--r--freebsd/sys/sys/vnode.h20
-rw-r--r--freebsd/sys/vm/uma_core.c199
-rw-r--r--freebsd/sys/vm/vm.h1
-rw-r--r--freebsd/usr.bin/netstat/flowtable.c100
-rw-r--r--freebsd/usr.bin/netstat/inet.c15
-rw-r--r--freebsd/usr.bin/netstat/main.c1
-rw-r--r--freebsd/usr.bin/netstat/netstat.h1
-rw-r--r--freebsd/usr.bin/netstat/rtems-bsd-netstat-data.h1
-rw-r--r--freebsd/usr.bin/netstat/rtems-bsd-netstat-namespace.h2
-rw-r--r--libbsd.py51
-rw-r--r--rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h26
-rw-r--r--rtemsbsd/include/rtems/bsd/local/miidevs.h4
-rw-r--r--rtemsbsd/include/rtems/bsd/local/mmcbr_if.h24
-rw-r--r--rtemsbsd/include/rtems/bsd/local/mmcbus_if.h26
-rw-r--r--rtemsbsd/include/rtems/bsd/local/opt_mmccam.h0
-rw-r--r--rtemsbsd/local/mmcbr_if.c24
-rw-r--r--rtemsbsd/local/mmcbus_if.c8
-rw-r--r--rtemsbsd/rtems/rtems-kernel-bus-dma.c4
169 files changed, 6822 insertions, 3227 deletions
diff --git a/freebsd-org b/freebsd-org
-Subproject dfb26efac4ce9101dda240e94d9ab53f80a9e13
+Subproject f5002f5e5f78cae9f0269d812dc0aedb0339312
diff --git a/freebsd/contrib/libxo/libxo/libxo.c b/freebsd/contrib/libxo/libxo/libxo.c
index f36e7480..d922ba0b 100644
--- a/freebsd/contrib/libxo/libxo/libxo.c
+++ b/freebsd/contrib/libxo/libxo/libxo.c
@@ -97,6 +97,14 @@
#include <libintl.h>
#endif /* HAVE_GETTEXT */
+/* Rather lame that we can't count on these... */
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
/*
* Three styles of specifying thread-local variables are supported.
* configure.ac has the brains to run each possibility through the
@@ -205,6 +213,7 @@ typedef struct xo_stack_s {
* XO_COL_* ("colors") refers to fancy ansi codes, while X__EFF_*
* ("effects") are bits since we need to maintain state.
*/
+typedef uint8_t xo_color_t;
#define XO_COL_DEFAULT 0
#define XO_COL_BLACK 1
#define XO_COL_RED 2
@@ -240,7 +249,6 @@ typedef struct xo_stack_s {
#define XO_EFF_CLEAR_BITS XO_EFF_RESET /* Reset gets reset, surprisingly */
typedef uint8_t xo_effect_t;
-typedef uint8_t xo_color_t;
typedef struct xo_colors_s {
xo_effect_t xoc_effects; /* Current effect set */
xo_color_t xoc_col_fg; /* Foreground color */
@@ -281,8 +289,10 @@ struct xo_handle_s {
ssize_t xo_anchor_min_width; /* Desired width of anchored text */
ssize_t xo_units_offset; /* Start of units insertion point */
ssize_t xo_columns; /* Columns emitted during this xo_emit call */
+#ifndef LIBXO_TEXT_ONLY
uint8_t xo_color_map_fg[XO_NUM_COLORS]; /* Foreground color mappings */
uint8_t xo_color_map_bg[XO_NUM_COLORS]; /* Background color mappings */
+#endif /* LIBXO_TEXT_ONLY */
xo_colors_t xo_colors; /* Current color and effect values */
xo_buffer_t xo_color_buf; /* HTML: buffer of colors and effects */
char *xo_version; /* Version string */
@@ -463,10 +473,17 @@ static ssize_t
xo_transition (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name,
xo_state_t new_state);
+static int
+xo_set_options_simple (xo_handle_t *xop, const char *input);
+
+static int
+xo_color_find (const char *str);
+
static void
xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
const char *name, ssize_t nlen,
const char *value, ssize_t vlen,
+ const char *fmt, ssize_t flen,
const char *encoding, ssize_t elen);
static void
@@ -630,13 +647,6 @@ xo_init_handle (xo_handle_t *xop)
XOF_SET(xop, XOF_FLUSH_LINE);
/*
- * We only want to do color output on terminals, but we only want
- * to do this if the user has asked for color.
- */
- if (XOF_ISSET(xop, XOF_COLOR_ALLOWED) && isatty(1))
- XOF_SET(xop, XOF_COLOR);
-
- /*
* We need to initialize the locale, which isn't really pretty.
* Libraries should depend on their caller to set up the
* environment. But we really can't count on the caller to do
@@ -669,15 +679,6 @@ xo_init_handle (xo_handle_t *xop)
xop->xo_indent_by = XO_INDENT_BY;
xo_depth_check(xop, XO_DEPTH);
-#if !defined(NO_LIBXO_OPTIONS)
- if (!XOF_ISSET(xop, XOF_NO_ENV)) {
- char *env = getenv("LIBXO_OPTIONS");
- if (env)
- xo_set_options(xop, env);
-
- }
-#endif /* NO_GETENV */
-
XOIF_CLEAR(xop, XOIF_INIT_IN_PROGRESS);
}
@@ -691,6 +692,16 @@ xo_default_init (void)
xo_init_handle(xop);
+#if !defined(NO_LIBXO_OPTIONS)
+ if (!XOF_ISSET(xop, XOF_NO_ENV)) {
+ char *env = getenv("LIBXO_OPTIONS");
+
+ if (env)
+ xo_set_options_simple(xop, env);
+
+ }
+#endif /* NO_LIBXO_OPTIONS */
+
xo_default_inited = 1;
}
@@ -1043,32 +1054,36 @@ xo_printf (xo_handle_t *xop, const char *fmt, ...)
* These next few function are make The Essential UTF-8 Ginsu Knife.
* Identify an input and output character, and convert it.
*/
-static uint8_t xo_utf8_bits[7] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+static uint8_t xo_utf8_data_bits[5] = { 0, 0x7f, 0x1f, 0x0f, 0x07 };
+static uint8_t xo_utf8_len_bits[5] = { 0, 0x00, 0xc0, 0xe0, 0xf0 };
+/*
+ * If the byte has a high-bit set, it's UTF-8, not ASCII.
+ */
static int
xo_is_utf8 (char ch)
{
return (ch & 0x80);
}
+/*
+ * Look at the high bits of the first byte to determine the length
+ * of the UTF-8 character.
+ */
static inline ssize_t
xo_utf8_to_wc_len (const char *buf)
{
- unsigned b = (unsigned char) *buf;
+ uint8_t bval = (uint8_t) *buf;
ssize_t len;
- if ((b & 0x80) == 0x0)
+ if ((bval & 0x80) == 0x0)
len = 1;
- else if ((b & 0xe0) == 0xc0)
+ else if ((bval & 0xe0) == 0xc0)
len = 2;
- else if ((b & 0xf0) == 0xe0)
+ else if ((bval & 0xf0) == 0xe0)
len = 3;
- else if ((b & 0xf8) == 0xf0)
+ else if ((bval & 0xf8) == 0xf0)
len = 4;
- else if ((b & 0xfc) == 0xf8)
- len = 5;
- else if ((b & 0xfe) == 0xfc)
- len = 6;
else
len = -1;
@@ -1078,12 +1093,11 @@ xo_utf8_to_wc_len (const char *buf)
static ssize_t
xo_buf_utf8_len (xo_handle_t *xop, const char *buf, ssize_t bufsiz)
{
-
unsigned b = (unsigned char) *buf;
ssize_t len, i;
len = xo_utf8_to_wc_len(buf);
- if (len == -1) {
+ if (len < 0) {
xo_failure(xop, "invalid UTF-8 data: %02hhx", b);
return -1;
}
@@ -1121,9 +1135,9 @@ xo_utf8_char (const char *buf, ssize_t len)
wchar_t wc;
const unsigned char *cp = (const unsigned char *) buf;
- wc = *cp & xo_utf8_bits[len];
+ wc = *cp & xo_utf8_data_bits[len];
for (i = 1; i < len; i++) {
- wc <<= 6;
+ wc <<= 6; /* Low six bits have data */
wc |= cp[i] & 0x3f;
if ((cp[i] & 0xc0) != 0x80)
return (wchar_t) -1;
@@ -1140,22 +1154,23 @@ xo_utf8_emit_len (wchar_t wc)
{
ssize_t len;
- if ((wc & ((1<<7) - 1)) == wc) /* Simple case */
+ if ((wc & ((1 << 7) - 1)) == wc) /* Simple case */
len = 1;
- else if ((wc & ((1<<11) - 1)) == wc)
+ else if ((wc & ((1 << 11) - 1)) == wc)
len = 2;
- else if ((wc & ((1<<16) - 1)) == wc)
+ else if ((wc & ((1 << 16) - 1)) == wc)
len = 3;
- else if ((wc & ((1<<21) - 1)) == wc)
+ else if ((wc & ((1 << 21) - 1)) == wc)
len = 4;
- else if ((wc & ((1<<26) - 1)) == wc)
- len = 5;
else
- len = 6;
+ len = -1; /* Invalid */
return len;
}
+/*
+ * Emit one wide character into the given buffer
+ */
static void
xo_utf8_emit_char (char *buf, ssize_t len, wchar_t wc)
{
@@ -1166,15 +1181,22 @@ xo_utf8_emit_char (char *buf, ssize_t len, wchar_t wc)
return;
}
+ /* Start with the low bits and insert them, six bits at a time */
for (i = len - 1; i >= 0; i--) {
buf[i] = 0x80 | (wc & 0x3f);
- wc >>= 6;
+ wc >>= 6; /* Drop the low six bits */
}
- buf[0] &= xo_utf8_bits[len];
- buf[0] |= ~xo_utf8_bits[len] << 1;
+ /* Finish off the first byte with the length bits */
+ buf[0] &= xo_utf8_data_bits[len]; /* Clear out the length bits */
+ buf[0] |= xo_utf8_len_bits[len]; /* Drop in new length bits */
}
+/*
+ * Append a single UTF-8 character to a buffer, converting it to locale
+ * encoding. Returns the number of columns consumed by that character,
+ * as best we can determine it.
+ */
static ssize_t
xo_buf_append_locale_from_utf8 (xo_handle_t *xop, xo_buffer_t *xbp,
const char *ibuf, ssize_t ilen)
@@ -1189,7 +1211,7 @@ xo_buf_append_locale_from_utf8 (xo_handle_t *xop, xo_buffer_t *xbp,
*/
wc = xo_utf8_char(ibuf, ilen);
if (wc == (wchar_t) -1) {
- xo_failure(xop, "invalid utf-8 byte sequence");
+ xo_failure(xop, "invalid UTF-8 byte sequence");
return 0;
}
@@ -1218,6 +1240,9 @@ xo_buf_append_locale_from_utf8 (xo_handle_t *xop, xo_buffer_t *xbp,
return xo_wcwidth(wc);
}
+/*
+ * Append a UTF-8 string to a buffer, converting it into locale encoding
+ */
static void
xo_buf_append_locale (xo_handle_t *xop, xo_buffer_t *xbp,
const char *cp, ssize_t len)
@@ -1504,6 +1529,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
newfmt[plen++] = ':';
newfmt[plen++] = ' ';
}
+
memcpy(newfmt + plen, fmt, len);
newfmt[len + plen] = '\0';
@@ -1523,6 +1549,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
ssize_t left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
ssize_t rc = vsnprintf(xbp->xb_curp, left, newfmt, vap);
+
if (rc >= left) {
if (!xo_buf_has_room(xbp, rc)) {
va_end(va_local);
@@ -1535,6 +1562,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
rc = vsnprintf(xbp->xb_curp, left, fmt, vap);
}
+
va_end(va_local);
rc = xo_escape_xml(xbp, rc, 1);
@@ -1545,6 +1573,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
if (code >= 0) {
const char *msg = strerror(code);
+
if (msg) {
xo_buf_append(xbp, ": ", 2);
xo_buf_append(xbp, msg, strlen(msg));
@@ -1558,6 +1587,7 @@ xo_warn_hcv (xo_handle_t *xop, int code, int check_warn,
vfprintf(stderr, newfmt, vap);
if (code >= 0) {
const char *msg = strerror(code);
+
if (msg)
fprintf(stderr, ": %s", msg);
}
@@ -1674,6 +1704,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
va_copy(va_local, vap);
ssize_t left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
+
rc = vsnprintf(xbp->xb_curp, left, fmt, vap);
if (rc >= left) {
if (!xo_buf_has_room(xbp, rc)) {
@@ -1687,6 +1718,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
left = xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
rc = vsnprintf(xbp->xb_curp, left, fmt, vap);
}
+
va_end(va_local);
rc = xo_escape_xml(xbp, rc, 0);
@@ -1694,6 +1726,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
if (need_nl && code > 0) {
const char *msg = strerror(code);
+
if (msg) {
xo_buf_append(xbp, ": ", 2);
xo_buf_append(xbp, msg, strlen(msg));
@@ -1727,6 +1760,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
va_copy(va_local, vap);
rc = vsnprintf(bp, bufsiz, fmt, va_local);
}
+
va_end(va_local);
cp = bp + rc;
@@ -1738,7 +1772,8 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
rc += rc2;
}
- xo_buf_append_div(xop, "message", 0, NULL, 0, bp, rc, NULL, 0);
+ xo_buf_append_div(xop, "message", 0, NULL, 0, bp, rc,
+ NULL, 0, NULL, 0);
}
break;
@@ -1762,6 +1797,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
if (need_nl && code > 0) {
const char *msg = strerror(code);
+
if (msg) {
xo_printf(xop, ": %s", msg);
}
@@ -1776,6 +1812,7 @@ xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap)
case XO_STYLE_HTML:
if (XOIF_ISSET(xop, XOIF_DIV_OPEN)) {
static char div_close[] = "</div>";
+
XOIF_CLEAR(xop, XOIF_DIV_OPEN);
xo_data_append(xop, div_close, sizeof(div_close) - 1);
@@ -1848,8 +1885,10 @@ xo_failure (xo_handle_t *xop, const char *fmt, ...)
* Note: normal use of libxo does not require a distinct handle, since
* the default handle (used when NULL is passed) generates text on stdout.
*
- * @style Style of output desired (XO_STYLE_* value)
- * @flags Set of XOF_* flags in use with this handle
+ * @param style Style of output desired (XO_STYLE_* value)
+ * @param flags Set of XOF_* flags in use with this handle
+ * @return Newly allocated handle
+ * @see xo_destroy
*/
xo_handle_t *
xo_create (xo_style_t style, xo_xof_flags_t flags)
@@ -1871,9 +1910,12 @@ xo_create (xo_style_t style, xo_xof_flags_t flags)
/**
* Create a handle that will write to the given file. Use
* the XOF_CLOSE_FP flag to have the file closed on xo_destroy().
- * @fp FILE pointer to use
- * @style Style of output desired (XO_STYLE_* value)
- * @flags Set of XOF_* flags to use with this handle
+ *
+ * @param fp FILE pointer to use
+ * @param style Style of output desired (XO_STYLE_* value)
+ * @param flags Set of XOF_* flags to use with this handle
+ * @return Newly allocated handle
+ * @see xo_destroy
*/
xo_handle_t *
xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags)
@@ -1892,8 +1934,10 @@ xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags)
/**
* Set the default handler to output to a file.
- * @xop libxo handle
- * @fp FILE pointer to use
+ *
+ * @param xop libxo handle
+ * @param fp FILE pointer to use
+ * @return 0 on success, non-zero on failure
*/
int
xo_set_file_h (xo_handle_t *xop, FILE *fp)
@@ -1915,7 +1959,9 @@ xo_set_file_h (xo_handle_t *xop, FILE *fp)
/**
* Set the default handler to output to a file.
- * @fp FILE pointer to use
+ *
+ * @param fp FILE pointer to use
+ * @return 0 on success, non-zero on failure
*/
int
xo_set_file (FILE *fp)
@@ -1925,7 +1971,8 @@ xo_set_file (FILE *fp)
/**
* Release any resources held by the handle.
- * @xop XO handle to alter (or NULL for default handle)
+ *
+ * @param xop XO handle to alter (or NULL for default handle)
*/
void
xo_destroy (xo_handle_t *xop_arg)
@@ -1958,8 +2005,8 @@ xo_destroy (xo_handle_t *xop_arg)
* Record a new output style to use for the given handle (or default if
* handle is NULL). This output style will be used for any future output.
*
- * @xop XO handle to alter (or NULL for default handle)
- * @style new output style (XO_STYLE_*)
+ * @param xop XO handle to alter (or NULL for default handle)
+ * @param style new output style (XO_STYLE_*)
*/
void
xo_set_style (xo_handle_t *xop, xo_style_t style)
@@ -1968,6 +2015,12 @@ xo_set_style (xo_handle_t *xop, xo_style_t style)
xop->xo_style = style;
}
+/**
+ * Return the current style of a handle
+ *
+ * @param xop XO handle to access
+ * @return The handle's current style
+ */
xo_style_t
xo_get_style (xo_handle_t *xop)
{
@@ -1975,6 +2028,12 @@ xo_get_style (xo_handle_t *xop)
return xo_style(xop);
}
+/**
+ * Return the XO_STYLE_* value matching a given name
+ *
+ * @param name String name of a style
+ * @return XO_STYLE_* value
+ */
static int
xo_name_to_style (const char *name)
{
@@ -2010,8 +2069,8 @@ xo_style_is_encoding (xo_handle_t *xop)
/* Simple name-value mapping */
typedef struct xo_mapping_s {
- xo_xff_flags_t xm_value;
- const char *xm_name;
+ xo_xff_flags_t xm_value; /* Flag value */
+ const char *xm_name; /* String name */
} xo_mapping_t;
static xo_xff_flags_t
@@ -2058,6 +2117,7 @@ xo_value_lookup (xo_mapping_t *map, xo_xff_flags_t value)
static xo_mapping_t xo_xof_names[] = {
{ XOF_COLOR_ALLOWED, "color" },
+ { XOF_COLOR, "color-force" },
{ XOF_COLUMNS, "columns" },
{ XOF_DTRT, "dtrt" },
{ XOF_FLUSH, "flush" },
@@ -2082,6 +2142,21 @@ static xo_mapping_t xo_xof_names[] = {
{ 0, NULL }
};
+/* Options available via the environment variable ($LIBXO_OPTIONS) */
+static xo_mapping_t xo_xof_simple_names[] = {
+ { XOF_COLOR_ALLOWED, "color" },
+ { XOF_FLUSH, "flush" },
+ { XOF_FLUSH_LINE, "flush-line" },
+ { XOF_NO_HUMANIZE, "no-humanize" },
+ { XOF_NO_LOCALE, "no-locale" },
+ { XOF_RETAIN_NONE, "no-retain" },
+ { XOF_PRETTY, "pretty" },
+ { XOF_RETAIN_ALL, "retain" },
+ { XOF_UNDERSCORES, "underscores" },
+ { XOF_WARN, "warn" },
+ { 0, NULL }
+};
+
/*
* Convert string name to XOF_* flag value.
* Not all are useful. Or safe. Or sane.
@@ -2092,6 +2167,13 @@ xo_name_to_flag (const char *name)
return (unsigned) xo_name_lookup(xo_xof_names, name, -1);
}
+/**
+ * Set the style of an libxo handle based on a string name
+ *
+ * @param xop XO handle
+ * @param name String value of name
+ * @return 0 on success, non-zero on failure
+ */
int
xo_set_style_name (xo_handle_t *xop, const char *name)
{
@@ -2099,6 +2181,7 @@ xo_set_style_name (xo_handle_t *xop, const char *name)
return -1;
int style = xo_name_to_style(name);
+
if (style < 0)
return -1;
@@ -2107,9 +2190,95 @@ xo_set_style_name (xo_handle_t *xop, const char *name)
}
/*
+ * Fill in the color map, based on the input string; currently unimplemented
+ * Look for something like "colors=red/blue+green/yellow" as fg/bg pairs.
+ */
+static void
+xo_set_color_map (xo_handle_t *xop, char *value)
+{
+#ifdef LIBXO_TEXT_ONLY
+ return;
+#endif /* LIBXO_TEXT_ONLY */
+
+ char *cp, *ep, *vp, *np;
+ ssize_t len = value ? strlen(value) + 1 : 0;
+ int num = 1, fg, bg;
+
+ for (cp = value, ep = cp + len - 1; cp && *cp && cp < ep; cp = np) {
+ np = strchr(cp, '+');
+ if (np)
+ *np++ = '\0';
+
+ vp = strchr(cp, '/');
+ if (vp)
+ *vp++ = '\0';
+
+ fg = *cp ? xo_color_find(cp) : -1;
+ bg = (vp && *vp) ? xo_color_find(vp) : -1;
+
+ xop->xo_color_map_fg[num] = (fg < 0) ? num : fg;
+ xop->xo_color_map_bg[num] = (bg < 0) ? num : bg;
+ if (++num > XO_NUM_COLORS)
+ break;
+ }
+
+ /* If no color initialization happened, then we don't need the map */
+ if (num > 0)
+ XOF_SET(xop, XOF_COLOR_MAP);
+ else
+ XOF_CLEAR(xop, XOF_COLOR_MAP);
+
+ /* Fill in the rest of the colors with the defaults */
+ for ( ; num < XO_NUM_COLORS; num++)
+ xop->xo_color_map_fg[num] = xop->xo_color_map_bg[num] = num;
+}
+
+static int
+xo_set_options_simple (xo_handle_t *xop, const char *input)
+{
+ xo_xof_flags_t new_flag;
+ char *cp, *ep, *vp, *np, *bp;
+ ssize_t len = strlen(input) + 1;
+
+ bp = alloca(len);
+ memcpy(bp, input, len);
+
+ for (cp = bp, ep = cp + len - 1; cp && cp < ep; cp = np) {
+ np = strchr(cp, ',');
+ if (np)
+ *np++ = '\0';
+
+ vp = strchr(cp, '=');
+ if (vp)
+ *vp++ = '\0';
+
+ if (strcmp("colors", cp) == 0) {
+ xo_set_color_map(xop, vp);
+ continue;
+ }
+
+ new_flag = xo_name_lookup(xo_xof_simple_names, cp, -1);
+ if (new_flag != 0) {
+ XOF_SET(xop, new_flag);
+ } else if (strcmp(cp, "no-color") == 0) {
+ XOF_CLEAR(xop, XOF_COLOR_ALLOWED);
+ } else {
+ xo_failure(xop, "unknown simple option: %s", cp);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
* Set the options for a handle using a string of options
* passed in. The input is a comma-separated set of names
* and optional values: "xml,pretty,indent=4"
+ *
+ * @param xop XO handle
+ * @param input Comma-separated set of option values
+ * @return 0 on success, non-zero on failure
*/
int
xo_set_options (xo_handle_t *xop, const char *input)
@@ -2229,7 +2398,7 @@ xo_set_options (xo_handle_t *xop, const char *input)
*vp++ = '\0';
if (strcmp("colors", cp) == 0) {
- /* XXX Look for colors=red-blue+green-yellow */
+ xo_set_color_map(xop, vp);
continue;
}
@@ -2247,28 +2416,26 @@ xo_set_options (xo_handle_t *xop, const char *input)
new_flag = xo_name_to_flag(cp);
if (new_flag != 0)
XOF_SET(xop, new_flag);
- else {
- if (strcmp(cp, "no-color") == 0) {
- XOF_CLEAR(xop, XOF_COLOR_ALLOWED);
- } else if (strcmp(cp, "indent") == 0) {
- if (vp)
- xop->xo_indent_by = atoi(vp);
- else
- xo_failure(xop, "missing value for indent option");
- } else if (strcmp(cp, "encoder") == 0) {
- if (vp == NULL)
- xo_failure(xop, "missing value for encoder option");
- else {
- if (xo_encoder_init(xop, vp)) {
- xo_failure(xop, "encoder not found: %s", vp);
- rc = -1;
- }
+ else if (strcmp(cp, "no-color") == 0)
+ XOF_CLEAR(xop, XOF_COLOR_ALLOWED);
+ else if (strcmp(cp, "indent") == 0) {
+ if (vp)
+ xop->xo_indent_by = atoi(vp);
+ else
+ xo_failure(xop, "missing value for indent option");
+ } else if (strcmp(cp, "encoder") == 0) {
+ if (vp == NULL)
+ xo_failure(xop, "missing value for encoder option");
+ else {
+ if (xo_encoder_init(xop, vp)) {
+ xo_failure(xop, "encoder not found: %s", vp);
+ rc = -1;
}
-
- } else {
- xo_warnx("unknown libxo option value: '%s'", cp);
- rc = -1;
}
+
+ } else {
+ xo_warnx("unknown libxo option value: '%s'", cp);
+ rc = -1;
}
}
}
@@ -2283,8 +2450,8 @@ xo_set_options (xo_handle_t *xop, const char *input)
* Set one or more flags for a given handle (or default if handle is NULL).
* These flags will affect future output.
*
- * @xop XO handle to alter (or NULL for default handle)
- * @flags Flags to be set (XOF_*)
+ * @param xop XO handle to alter (or NULL for default handle)
+ * @param flags Flags to be set (XOF_*)
*/
void
xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags)
@@ -2294,6 +2461,11 @@ xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags)
XOF_SET(xop, flags);
}
+/**
+ * Accessor to return the current set of flags for a handle
+ * @param xop XO handle
+ * @return Current set of flags
+ */
xo_xof_flags_t
xo_get_flags (xo_handle_t *xop)
{
@@ -2302,8 +2474,8 @@ xo_get_flags (xo_handle_t *xop)
return xop->xo_flags;
}
-/*
- * strndup with a twist: len < 0 means strlen
+/**
+ * strndup with a twist: len < 0 means len = strlen(str)
*/
static char *
xo_strndup (const char *str, ssize_t len)
@@ -2325,8 +2497,8 @@ xo_strndup (const char *str, ssize_t len)
* generated data to be placed within an XML hierarchy but still have
* accurate XPath expressions.
*
- * @xop XO handle to alter (or NULL for default handle)
- * @path The XPath expression
+ * @param xop XO handle to alter (or NULL for default handle)
+ * @param path The XPath expression
*/
void
xo_set_leading_xpath (xo_handle_t *xop, const char *path)
@@ -2347,9 +2519,9 @@ xo_set_leading_xpath (xo_handle_t *xop, const char *path)
/**
* Record the info data for a set of tags
*
- * @xop XO handle to alter (or NULL for default handle)
- * @info Info data (xo_info_t) to be recorded (or NULL) (MUST BE SORTED)
- * @count Number of entries in info (or -1 to count them ourselves)
+ * @param xop XO handle to alter (or NULL for default handle)
+ * @param info Info data (xo_info_t) to be recorded (or NULL) (MUST BE SORTED)
+ * @pararm count Number of entries in info (or -1 to count them ourselves)
*/
void
xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count)
@@ -2386,8 +2558,8 @@ xo_set_formatter (xo_handle_t *xop, xo_formatter_t func,
* Clear one or more flags for a given handle (or default if handle is NULL).
* These flags will affect future output.
*
- * @xop XO handle to alter (or NULL for default handle)
- * @flags Flags to be cleared (XOF_*)
+ * @param xop XO handle to alter (or NULL for default handle)
+ * @param flags Flags to be cleared (XOF_*)
*/
void
xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags)
@@ -2543,6 +2715,8 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
if ((flags & XFF_UNESCAPE) && (*cp == '\\' || *cp == '%')) {
cp += 1;
len -= 1;
+ if (len == 0 || *cp == '\0')
+ break;
}
}
@@ -3079,6 +3253,11 @@ xo_data_append_content (xo_handle_t *xop, const char *str, ssize_t len,
xop->xo_anchor_columns += cols;
}
+/**
+ * Bump one of the 'width' values in a format strings (e.g. "%40.50.60s").
+ * @param xfp Formatting instructions
+ * @param digit Single digit (0-9) of input
+ */
static void
xo_bump_width (xo_format_t *xfp, int digit)
{
@@ -3325,7 +3504,8 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp,
rc = xo_trim_ws(xbp, rc);
} else {
- ssize_t columns = rc = xo_vsnprintf(xop, xbp, newfmt, xop->xo_vap);
+ ssize_t columns = rc = xo_vsnprintf(xop, xbp, newfmt,
+ xop->xo_vap);
/*
* For XML and HTML, we need "&<>" processing; for JSON,
@@ -3478,6 +3658,10 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp,
return 0;
}
+/*
+ * Remove any numeric precision/width format from the format string by
+ * inserting the "%" after the [0-9]+, returning the substring.
+ */
static char *
xo_fix_encoding (xo_handle_t *xop UNUSED, char *encoding)
{
@@ -3491,8 +3675,7 @@ xo_fix_encoding (xo_handle_t *xop UNUSED, char *encoding)
break;
}
- cp -= 1;
- *cp = '%';
+ *--cp = '%'; /* Back off and insert the '%' */
return cp;
}
@@ -3611,10 +3794,35 @@ xo_format_humanize (xo_handle_t *xop, xo_buffer_t *xbp,
}
}
+/*
+ * Convenience function that either append a fixed value (if one is
+ * given) or formats a field using a format string. If it's
+ * encode_only, then we can't skip formatting the field, since it may
+ * be pulling arguments off the stack.
+ */
+static inline void
+xo_simple_field (xo_handle_t *xop, unsigned encode_only,
+ const char *value, ssize_t vlen,
+ const char *fmt, ssize_t flen, xo_xff_flags_t flags)
+{
+ if (encode_only)
+ flags |= XFF_NO_OUTPUT;
+
+ if (vlen == 0)
+ xo_do_format_field(xop, NULL, fmt, flen, flags);
+ else if (!encode_only)
+ xo_data_append_content(xop, value, vlen, flags);
+}
+
+/*
+ * Html mode: append a <div> to the output buffer contain a field
+ * along with all the supporting information indicated by the flags.
+ */
static void
xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
const char *name, ssize_t nlen,
const char *value, ssize_t vlen,
+ const char *fmt, ssize_t flen,
const char *encoding, ssize_t elen)
{
static char div_start[] = "<div class=\"";
@@ -3625,10 +3833,10 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
static char div_close[] = "</div>";
/* The encoding format defaults to the normal format */
- if (encoding == NULL) {
- char *enc = alloca(vlen + 1);
- memcpy(enc, value, vlen);
- enc[vlen] = '\0';
+ if (encoding == NULL && fmt != NULL) {
+ char *enc = alloca(flen + 1);
+ memcpy(enc, fmt, flen);
+ enc[flen] = '\0';
encoding = xo_fix_encoding(xop, enc);
elen = strlen(encoding);
}
@@ -3695,10 +3903,10 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
/*
* Even if this is encode-only, we need to go through the
* work of formatting it to make sure the args are cleared
- * from xo_vap.
+ * from xo_vap. This is not true when vlen is zero, since
+ * that means our "value" isn't on the stack.
*/
- xo_do_format_field(xop, NULL, encoding, elen,
- flags | XFF_NO_OUTPUT);
+ xo_simple_field(xop, TRUE, NULL, 0, encoding, elen, flags);
return;
}
@@ -3806,7 +4014,7 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
save.xhs_columns = xop->xo_columns;
save.xhs_anchor_columns = xop->xo_anchor_columns;
- xo_do_format_field(xop, NULL, value, vlen, flags);
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
if (flags & XFF_HUMANIZE) {
/*
@@ -3857,14 +4065,14 @@ xo_format_text (xo_handle_t *xop, const char *str, ssize_t len)
break;
case XO_STYLE_HTML:
- xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0);
+ xo_buf_append_div(xop, "text", 0, NULL, 0, str, len, NULL, 0, NULL, 0);
break;
}
}
static void
xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
const char *fmt = xfip->xfi_format;
ssize_t flen = xfip->xfi_flen;
@@ -3888,8 +4096,7 @@ xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip,
* Even though we don't care about text, we need to do
* enough parsing work to skip over the right bits of xo_vap.
*/
- if (len == 0)
- xo_do_format_field(xop, NULL, fmt, flen, flags | XFF_NO_OUTPUT);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
return;
}
@@ -3908,17 +4115,17 @@ xo_format_title (xo_handle_t *xop, xo_field_info_t *xfip,
}
start = xbp->xb_curp - xbp->xb_bufp; /* Reset start */
- if (len) {
+ if (vlen) {
char *newfmt = alloca(flen + 1);
memcpy(newfmt, fmt, flen);
newfmt[flen] = '\0';
/* If len is non-zero, the format string apply to the name */
- char *newstr = alloca(len + 1);
- memcpy(newstr, str, len);
- newstr[len] = '\0';
+ char *newstr = alloca(vlen + 1);
+ memcpy(newstr, value, vlen);
+ newstr[vlen] = '\0';
- if (newstr[len - 1] == 's') {
+ if (newstr[vlen - 1] == 's') {
char *bp;
rc = snprintf(NULL, 0, newfmt, newstr);
@@ -4000,8 +4207,9 @@ xo_arg (xo_handle_t *xop)
static void
xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
- const char *format, ssize_t flen,
- const char *encoding, ssize_t elen, xo_xff_flags_t flags)
+ const char *value, ssize_t vlen,
+ const char *fmt, ssize_t flen,
+ const char *encoding, ssize_t elen, xo_xff_flags_t flags)
{
int pretty = XOF_ISSET(xop, XOF_PRETTY);
int quote;
@@ -4087,7 +4295,7 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
save.xhs_columns = xop->xo_columns;
save.xhs_anchor_columns = xop->xo_anchor_columns;
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
if (flags & XFF_HUMANIZE)
xo_format_humanize(xop, xbp, &save, flags);
@@ -4097,8 +4305,8 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
if (flags & XFF_ENCODE_ONLY)
flags |= XFF_NO_OUTPUT;
- xo_buf_append_div(xop, "data", flags, name, nlen,
- format, flen, encoding, elen);
+ xo_buf_append_div(xop, "data", flags, name, nlen, value, vlen,
+ fmt, flen, encoding, elen);
break;
case XO_STYLE_XML:
@@ -4107,25 +4315,24 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
* let the formatting code handle the va_arg popping.
*/
if (flags & XFF_DISPLAY_ONLY) {
- flags |= XFF_NO_OUTPUT;
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
break;
}
if (encoding) {
- format = encoding;
+ fmt = encoding;
flen = elen;
} else {
char *enc = alloca(flen + 1);
- memcpy(enc, format, flen);
+ memcpy(enc, fmt, flen);
enc[flen] = '\0';
- format = xo_fix_encoding(xop, enc);
- flen = strlen(format);
+ fmt = xo_fix_encoding(xop, enc);
+ flen = strlen(fmt);
}
if (nlen == 0) {
static char missing[] = "missing-field-name";
- xo_failure(xop, "missing field name: %s", format);
+ xo_failure(xop, "missing field name: %s", fmt);
name = missing;
nlen = sizeof(missing) - 1;
}
@@ -4161,7 +4368,9 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
}
xo_data_append(xop, ">", 1);
- xo_do_format_field(xop, NULL, format, flen, flags);
+
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
+
xo_data_append(xop, "</", 2);
xo_data_escape(xop, name, nlen);
xo_data_append(xop, ">", 1);
@@ -4171,20 +4380,19 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
case XO_STYLE_JSON:
if (flags & XFF_DISPLAY_ONLY) {
- flags |= XFF_NO_OUTPUT;
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
break;
}
if (encoding) {
- format = encoding;
+ fmt = encoding;
flen = elen;
} else {
char *enc = alloca(flen + 1);
- memcpy(enc, format, flen);
+ memcpy(enc, fmt, flen);
enc[flen] = '\0';
- format = xo_fix_encoding(xop, enc);
- flen = strlen(format);
+ fmt = xo_fix_encoding(xop, enc);
+ flen = strlen(fmt);
}
int first = (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
@@ -4196,18 +4404,20 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
quote = 1;
else if (flags & XFF_NOQUOTE)
quote = 0;
+ else if (vlen != 0)
+ quote = 1;
else if (flen == 0) {
quote = 0;
- format = "true"; /* JSON encodes empty tags as a boolean true */
+ fmt = "true"; /* JSON encodes empty tags as a boolean true */
flen = 4;
- } else if (strchr("diouDOUeEfFgG", format[flen - 1]) == NULL)
+ } else if (strchr("diouDOUeEfFgG", fmt[flen - 1]) == NULL)
quote = 1;
else
quote = 0;
if (nlen == 0) {
static char missing[] = "missing-field-name";
- xo_failure(xop, "missing field name: %s", format);
+ xo_failure(xop, "missing field name: %s", fmt);
name = missing;
nlen = sizeof(missing) - 1;
}
@@ -4241,7 +4451,7 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
if (quote)
xo_data_append(xop, "\"", 1);
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
if (quote)
xo_data_append(xop, "\"", 1);
@@ -4249,39 +4459,39 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
case XO_STYLE_SDPARAMS:
if (flags & XFF_DISPLAY_ONLY) {
- flags |= XFF_NO_OUTPUT;
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
break;
}
if (encoding) {
- format = encoding;
+ fmt = encoding;
flen = elen;
} else {
char *enc = alloca(flen + 1);
- memcpy(enc, format, flen);
+ memcpy(enc, fmt, flen);
enc[flen] = '\0';
- format = xo_fix_encoding(xop, enc);
- flen = strlen(format);
+ fmt = xo_fix_encoding(xop, enc);
+ flen = strlen(fmt);
}
if (nlen == 0) {
static char missing[] = "missing-field-name";
- xo_failure(xop, "missing field name: %s", format);
+ xo_failure(xop, "missing field name: %s", fmt);
name = missing;
nlen = sizeof(missing) - 1;
}
xo_data_escape(xop, name, nlen);
xo_data_append(xop, "=\"", 2);
- xo_do_format_field(xop, NULL, format, flen, flags);
+
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
+
xo_data_append(xop, "\" ", 2);
break;
case XO_STYLE_ENCODER:
if (flags & XFF_DISPLAY_ONLY) {
- flags |= XFF_NO_OUTPUT;
- xo_do_format_field(xop, NULL, format, flen, flags);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
break;
}
@@ -4291,27 +4501,27 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
quote = 0;
else if (flen == 0) {
quote = 0;
- format = "true"; /* JSON encodes empty tags as a boolean true */
+ fmt = "true"; /* JSON encodes empty tags as a boolean true */
flen = 4;
- } else if (strchr("diouxXDOUeEfFgGaAcCp", format[flen - 1]) == NULL)
+ } else if (strchr("diouxXDOUeEfFgGaAcCp", fmt[flen - 1]) == NULL)
quote = 1;
else
quote = 0;
if (encoding) {
- format = encoding;
+ fmt = encoding;
flen = elen;
} else {
char *enc = alloca(flen + 1);
- memcpy(enc, format, flen);
+ memcpy(enc, fmt, flen);
enc[flen] = '\0';
- format = xo_fix_encoding(xop, enc);
- flen = strlen(format);
+ fmt = xo_fix_encoding(xop, enc);
+ flen = strlen(fmt);
}
if (nlen == 0) {
static char missing[] = "missing-field-name";
- xo_failure(xop, "missing field name: %s", format);
+ xo_failure(xop, "missing field name: %s", fmt);
name = missing;
nlen = sizeof(missing) - 1;
}
@@ -4321,12 +4531,14 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
xo_data_append(xop, "", 1);
ssize_t value_offset = xo_buf_offset(&xop->xo_data);
- xo_do_format_field(xop, NULL, format, flen, flags);
+
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
+
xo_data_append(xop, "", 1);
xo_encoder_handle(xop, quote ? XO_OP_STRING : XO_OP_CONTENT,
xo_buf_data(&xop->xo_data, name_offset),
- xo_buf_data(&xop->xo_data, value_offset));
+ xo_buf_data(&xop->xo_data, value_offset), flags);
xo_buf_reset(&xop->xo_data);
break;
}
@@ -4370,37 +4582,27 @@ xo_set_gettext_domain (xo_handle_t *xop, xo_field_info_t *xfip,
static void
xo_format_content (xo_handle_t *xop, const char *class_name,
const char *tag_name,
- const char *str, ssize_t len, const char *fmt, ssize_t flen,
+ const char *value, ssize_t vlen,
+ const char *fmt, ssize_t flen,
xo_xff_flags_t flags)
{
switch (xo_style(xop)) {
case XO_STYLE_TEXT:
- if (len)
- xo_data_append_content(xop, str, len, flags);
- else
- xo_do_format_field(xop, NULL, fmt, flen, flags);
+ xo_simple_field(xop, FALSE, value, vlen, fmt, flen, flags);
break;
case XO_STYLE_HTML:
- if (len == 0) {
- str = fmt;
- len = flen;
- }
-
- xo_buf_append_div(xop, class_name, flags, NULL, 0, str, len, NULL, 0);
+ xo_buf_append_div(xop, class_name, flags, NULL, 0,
+ value, vlen, fmt, flen, NULL, 0);
break;
case XO_STYLE_XML:
case XO_STYLE_JSON:
case XO_STYLE_SDPARAMS:
if (tag_name) {
- if (len == 0) {
- str = fmt;
- len = flen;
- }
-
xo_open_container_h(xop, tag_name);
- xo_format_value(xop, "message", 7, str, len, NULL, 0, flags);
+ xo_format_value(xop, "message", 7, value, vlen,
+ fmt, flen, NULL, 0, flags);
xo_close_container_h(xop, tag_name);
} else {
@@ -4408,16 +4610,12 @@ xo_format_content (xo_handle_t *xop, const char *class_name,
* Even though we don't care about labels, we need to do
* enough parsing work to skip over the right bits of xo_vap.
*/
- if (len == 0)
- xo_do_format_field(xop, NULL, fmt, flen,
- flags | XFF_NO_OUTPUT);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
}
break;
case XO_STYLE_ENCODER:
- if (len == 0)
- xo_do_format_field(xop, NULL, fmt, flen,
- flags | XFF_NO_OUTPUT);
+ xo_simple_field(xop, TRUE, value, vlen, fmt, flen, flags);
break;
}
}
@@ -4583,6 +4781,28 @@ xo_colors_enabled (xo_handle_t *xop UNUSED)
#endif /* LIBXO_TEXT_ONLY */
}
+/*
+ * If the color map is in use (--libxo colors=xxxx), then update
+ * the incoming foreground and background colors from the map.
+ */
+static void
+xo_colors_update (xo_handle_t *xop, xo_colors_t *newp)
+{
+#ifdef LIBXO_TEXT_ONLY
+ return;
+#endif /* LIBXO_TEXT_ONLY */
+
+ xo_color_t fg = newp->xoc_col_fg;
+ if (XOF_ISSET(xop, XOF_COLOR_MAP) && fg < XO_NUM_COLORS)
+ fg = xop->xo_color_map_fg[fg]; /* Fetch from color map */
+ newp->xoc_col_fg = fg;
+
+ xo_color_t bg = newp->xoc_col_bg;
+ if (XOF_ISSET(xop, XOF_COLOR_MAP) && bg < XO_NUM_COLORS)
+ bg = xop->xo_color_map_bg[bg]; /* Fetch from color map */
+ newp->xoc_col_bg = bg;
+}
+
static void
xo_colors_handle_text (xo_handle_t *xop, xo_colors_t *newp)
{
@@ -4629,16 +4849,16 @@ xo_colors_handle_text (xo_handle_t *xop, xo_colors_t *newp)
}
}
- if (newp->xoc_col_fg != oldp->xoc_col_fg) {
+ xo_color_t fg = newp->xoc_col_fg;
+ if (fg != oldp->xoc_col_fg) {
cp += snprintf(cp, ep - cp, ";3%u",
- (newp->xoc_col_fg != XO_COL_DEFAULT)
- ? newp->xoc_col_fg - 1 : 9);
+ (fg != XO_COL_DEFAULT) ? fg - 1 : 9);
}
- if (newp->xoc_col_bg != oldp->xoc_col_bg) {
+ xo_color_t bg = newp->xoc_col_bg;
+ if (bg != oldp->xoc_col_bg) {
cp += snprintf(cp, ep - cp, ";4%u",
- (newp->xoc_col_bg != XO_COL_DEFAULT)
- ? newp->xoc_col_bg - 1 : 9);
+ (bg != XO_COL_DEFAULT) ? bg - 1 : 9);
}
if (cp - buf != 1 && cp < ep - 3) {
@@ -4710,7 +4930,7 @@ xo_colors_handle_html (xo_handle_t *xop, xo_colors_t *newp)
static void
xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
const char *fmt = xfip->xfi_format;
ssize_t flen = xfip->xfi_flen;
@@ -4718,13 +4938,13 @@ xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip,
xo_buffer_t xb;
/* If the string is static and we've in an encoding style, bail */
- if (len != 0 && xo_style_is_encoding(xop))
+ if (vlen != 0 && xo_style_is_encoding(xop))
return;
xo_buf_init(&xb);
- if (len)
- xo_buf_append(&xb, str, len);
+ if (vlen)
+ xo_buf_append(&xb, value, vlen);
else if (flen)
xo_do_format_field(xop, &xb, fmt, flen, 0);
else
@@ -4738,6 +4958,7 @@ xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip,
xo_colors_t xoc = xop->xo_colors;
xo_colors_parse(xop, &xoc, xb.xb_bufp);
+ xo_colors_update(xop, &xoc);
if (xo_style(xop) == XO_STYLE_TEXT) {
/*
@@ -4783,7 +5004,7 @@ xo_format_colors (xo_handle_t *xop, xo_field_info_t *xfip,
static void
xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
const char *fmt = xfip->xfi_format;
ssize_t flen = xfip->xfi_flen;
@@ -4793,7 +5014,7 @@ xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip,
static char units_start_html[] = " data-units=\"";
if (!XOIF_ISSET(xop, XOIF_UNITS_PENDING)) {
- xo_format_content(xop, "units", NULL, str, len, fmt, flen, flags);
+ xo_format_content(xop, "units", NULL, value, vlen, fmt, flen, flags);
return;
}
@@ -4808,8 +5029,8 @@ xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip,
else
return;
- if (len)
- xo_data_escape(xop, str, len);
+ if (vlen)
+ xo_data_escape(xop, value, vlen);
else
xo_do_format_field(xop, NULL, fmt, flen, flags);
@@ -4837,7 +5058,7 @@ xo_format_units (xo_handle_t *xop, xo_field_info_t *xfip,
static ssize_t
xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
const char *fmt = xfip->xfi_format;
ssize_t flen = xfip->xfi_flen;
@@ -4846,10 +5067,10 @@ xo_find_width (xo_handle_t *xop, xo_field_info_t *xfip,
char *bp;
char *cp;
- if (len) {
- bp = alloca(len + 1); /* Make local NUL-terminated copy of str */
- memcpy(bp, str, len);
- bp[len] = '\0';
+ if (vlen) {
+ bp = alloca(vlen + 1); /* Make local NUL-terminated copy of value */
+ memcpy(bp, value, vlen);
+ bp[vlen] = '\0';
width = strtol(bp, &cp, 0);
if (width == LONG_MIN || width == LONG_MAX
@@ -4886,7 +5107,7 @@ xo_anchor_clear (xo_handle_t *xop)
*/
static void
xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
return;
@@ -4903,12 +5124,12 @@ xo_anchor_start (xo_handle_t *xop, xo_field_info_t *xfip,
* Now we find the width, if possible. If it's not there,
* we'll get it on the end anchor.
*/
- xop->xo_anchor_min_width = xo_find_width(xop, xfip, str, len);
+ xop->xo_anchor_min_width = xo_find_width(xop, xfip, value, vlen);
}
static void
xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip,
- const char *str, ssize_t len)
+ const char *value, ssize_t vlen)
{
if (xo_style(xop) != XO_STYLE_TEXT && xo_style(xop) != XO_STYLE_HTML)
return;
@@ -4920,7 +5141,7 @@ xo_anchor_stop (xo_handle_t *xop, xo_field_info_t *xfip,
XOIF_CLEAR(xop, XOIF_UNITS_PENDING);
- ssize_t width = xo_find_width(xop, xfip, str, len);
+ ssize_t width = xo_find_width(xop, xfip, value, vlen);
if (width == 0)
width = xop->xo_anchor_min_width;
@@ -5839,12 +6060,12 @@ xo_gettext_build_format (xo_handle_t *xop,
if (gtfmt == NULL || gtfmt == fmt || strcmp(gtfmt, fmt) == 0)
goto bail2;
- xo_buf_cleanup(&xb);
-
char *new_fmt = xo_strndup(gtfmt, -1);
if (new_fmt == NULL)
goto bail2;
+ xo_buf_cleanup(&xb);
+
*new_fmtp = new_fmt;
return new_fmt;
@@ -5977,7 +6198,7 @@ xo_do_emit_fields (xo_handle_t *xop, xo_field_info_t *fields,
ssize_t fend[flimit];
bzero(fend, flimit * sizeof(fend[0]));
- for (xfip = fields, field = 0; xfip->xfi_ftype && field < max_fields;
+ for (xfip = fields, field = 0; field < max_fields && xfip->xfi_ftype;
xfip++, field++) {
ftype = xfip->xfi_ftype;
flags = xfip->xfi_flags;
@@ -6024,12 +6245,12 @@ xo_do_emit_fields (xo_handle_t *xop, xo_field_info_t *fields,
if (flags & XFF_WS) {
xo_format_content(xop, "padding", NULL, " ", 1,
NULL, 0, flags);
- flags &= ~XFF_WS; /* Block later handling of this */
+ flags &= ~XFF_WS; /* Prevent later handling of this flag */
}
}
if (ftype == 'V')
- xo_format_value(xop, content, clen,
+ xo_format_value(xop, content, clen, NULL, 0,
xfip->xfi_format, xfip->xfi_flen,
xfip->xfi_encoding, xfip->xfi_elen, flags);
else if (ftype == '[')
@@ -6460,7 +6681,7 @@ xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
*xbp->xb_curp = '\0';
rc = xo_encoder_handle(xop, XO_OP_ATTRIBUTE,
xo_buf_data(xbp, name_offset),
- xo_buf_data(xbp, value_offset));
+ xo_buf_data(xbp, value_offset), 0);
}
}
@@ -6538,7 +6759,7 @@ xo_depth_change (xo_handle_t *xop, const char *name,
xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
if (XOF_ISSET(xop, XOF_WARN)) {
const char *top = xsp->xs_name;
- if (top && strcmp(name, top) != 0) {
+ if (top != NULL && name != NULL && strcmp(name, top) != 0) {
xo_failure(xop, "incorrect close: '%s' .vs. '%s'",
name, top);
return;
@@ -6650,7 +6871,7 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
break;
case XO_STYLE_ENCODER:
- rc = xo_encoder_handle(xop, XO_OP_OPEN_CONTAINER, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_CONTAINER, name, NULL, flags);
break;
}
@@ -6740,7 +6961,7 @@ xo_do_close_container (xo_handle_t *xop, const char *name)
case XO_STYLE_ENCODER:
xo_depth_change(xop, name, -1, 0, XSS_CLOSE_CONTAINER, 0);
- rc = xo_encoder_handle(xop, XO_OP_CLOSE_CONTAINER, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_CONTAINER, name, NULL, 0);
break;
}
@@ -6806,7 +7027,7 @@ xo_do_open_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
break;
case XO_STYLE_ENCODER:
- rc = xo_encoder_handle(xop, XO_OP_OPEN_LIST, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_LIST, name, NULL, flags);
break;
}
@@ -6881,7 +7102,7 @@ xo_do_close_list (xo_handle_t *xop, const char *name)
case XO_STYLE_ENCODER:
xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LIST, XSF_LIST);
- rc = xo_encoder_handle(xop, XO_OP_CLOSE_LIST, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_LIST, name, NULL, 0);
break;
default:
@@ -6955,7 +7176,7 @@ xo_do_open_leaf_list (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
break;
case XO_STYLE_ENCODER:
- rc = xo_encoder_handle(xop, XO_OP_OPEN_LEAF_LIST, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_LEAF_LIST, name, NULL, flags);
break;
}
@@ -6999,7 +7220,7 @@ xo_do_close_leaf_list (xo_handle_t *xop, const char *name)
break;
case XO_STYLE_ENCODER:
- rc = xo_encoder_handle(xop, XO_OP_CLOSE_LEAF_LIST, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_LEAF_LIST, name, NULL, 0);
/* FALLTHRU */
default:
@@ -7056,7 +7277,7 @@ xo_do_open_instance (xo_handle_t *xop, xo_xsf_flags_t flags, const char *name)
break;
case XO_STYLE_ENCODER:
- rc = xo_encoder_handle(xop, XO_OP_OPEN_INSTANCE, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_OPEN_INSTANCE, name, NULL, flags);
break;
}
@@ -7144,7 +7365,7 @@ xo_do_close_instance (xo_handle_t *xop, const char *name)
case XO_STYLE_ENCODER:
xo_depth_change(xop, name, -1, 0, XSS_CLOSE_INSTANCE, 0);
- rc = xo_encoder_handle(xop, XO_OP_CLOSE_INSTANCE, name, NULL);
+ rc = xo_encoder_handle(xop, XO_OP_CLOSE_INSTANCE, name, NULL, 0);
break;
}
@@ -7620,7 +7841,7 @@ xo_flush_h (xo_handle_t *xop)
switch (xo_style(xop)) {
case XO_STYLE_ENCODER:
- xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL);
+ xo_encoder_handle(xop, XO_OP_FLUSH, NULL, NULL, 0);
}
rc = xo_write(xop);
@@ -7658,7 +7879,7 @@ xo_finish_h (xo_handle_t *xop)
break;
case XO_STYLE_ENCODER:
- xo_encoder_handle(xop, XO_OP_FINISH, NULL, NULL);
+ xo_encoder_handle(xop, XO_OP_FINISH, NULL, NULL, 0);
break;
}
@@ -7710,7 +7931,8 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
case XO_STYLE_HTML:
va_copy(xop->xo_vap, vap);
- xo_buf_append_div(xop, "error", 0, NULL, 0, fmt, strlen(fmt), NULL, 0);
+ xo_buf_append_div(xop, "error", 0, NULL, 0, NULL, 0,
+ fmt, strlen(fmt), NULL, 0);
if (XOIF_ISSET(xop, XOIF_DIV_OPEN))
xo_line_close(xop);
@@ -7726,7 +7948,8 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
va_copy(xop->xo_vap, vap);
xo_open_container_h(xop, "error");
- xo_format_value(xop, "message", 7, fmt, strlen(fmt), NULL, 0, 0);
+ xo_format_value(xop, "message", 7, NULL, 0,
+ fmt, strlen(fmt), NULL, 0, 0);
xo_close_container_h(xop, "error");
va_end(xop->xo_vap);
@@ -7781,6 +8004,8 @@ xo_parse_args (int argc, char **argv)
if (cp)
xo_program = cp + 1;
+ xo_handle_t *xop = xo_default(NULL);
+
for (save = i = 1; i < argc; i++) {
if (argv[i] == NULL
|| strncmp(argv[i], libxo_opt, sizeof(libxo_opt) - 1) != 0) {
@@ -7798,14 +8023,14 @@ xo_parse_args (int argc, char **argv)
return -1;
}
- if (xo_set_options(NULL, cp) < 0)
+ if (xo_set_options(xop, cp) < 0)
return -1;
} else if (*cp == ':') {
- if (xo_set_options(NULL, cp) < 0)
+ if (xo_set_options(xop, cp) < 0)
return -1;
} else if (*cp == '=') {
- if (xo_set_options(NULL, ++cp) < 0)
+ if (xo_set_options(xop, ++cp) < 0)
return -1;
} else if (*cp == '-') {
@@ -7823,6 +8048,13 @@ xo_parse_args (int argc, char **argv)
}
}
+ /*
+ * We only want to do color output on terminals, but we only want
+ * to do this if the user has asked for color.
+ */
+ if (XOF_ISSET(xop, XOF_COLOR_ALLOWED) && isatty(1))
+ XOF_SET(xop, XOF_COLOR);
+
argv[save] = NULL;
return save;
}
@@ -7884,7 +8116,7 @@ xo_set_version_h (xo_handle_t *xop, const char *version)
break;
case XO_STYLE_ENCODER:
- xo_encoder_handle(xop, XO_OP_VERSION, NULL, version);
+ xo_encoder_handle(xop, XO_OP_VERSION, NULL, version, 0);
break;
}
}
@@ -7934,7 +8166,7 @@ xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code,
xo_buffer_t *src = &temp.xo_data;
xo_format_value(xop, "message", 7, src->xb_bufp,
- src->xb_curp - src->xb_bufp, NULL, 0, 0);
+ src->xb_curp - src->xb_bufp, NULL, 0, NULL, 0, 0);
xo_free(temp.xo_stack);
xo_buf_cleanup(src);
diff --git a/freebsd/contrib/libxo/libxo/xo.h b/freebsd/contrib/libxo/libxo/xo.h
index 13023d38..c39fa47e 100644
--- a/freebsd/contrib/libxo/libxo/xo.h
+++ b/freebsd/contrib/libxo/libxo/xo.h
@@ -101,6 +101,8 @@ typedef unsigned long long xo_xof_flags_t;
#define XOF_RETAIN_ALL XOF_BIT(30) /** Force use of XOEF_RETAIN */
#define XOF_RETAIN_NONE XOF_BIT(31) /** Prevent use of XOEF_RETAIN */
+#define XOF_COLOR_MAP XOF_BIT(32) /** Color map has been initialized */
+
typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */
#define XOEF_RETAIN (1<<0) /* Retain parsed formatting information */
diff --git a/freebsd/contrib/libxo/libxo/xo_buf.h b/freebsd/contrib/libxo/libxo/xo_buf.h
index 3bb5628a..d6a05005 100644
--- a/freebsd/contrib/libxo/libxo/xo_buf.h
+++ b/freebsd/contrib/libxo/libxo/xo_buf.h
@@ -133,7 +133,7 @@ xo_buf_has_room (xo_buffer_t *xbp, ssize_t len)
static inline void
xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len)
{
- if (!xo_buf_has_room(xbp, len))
+ if (str == NULL || len == 0 || !xo_buf_has_room(xbp, len))
return;
memcpy(xbp->xb_curp, str, len);
diff --git a/freebsd/contrib/libxo/libxo/xo_encoder.c b/freebsd/contrib/libxo/libxo/xo_encoder.c
index 436e57f5..b114ea78 100644
--- a/freebsd/contrib/libxo/libxo/xo_encoder.c
+++ b/freebsd/contrib/libxo/libxo/xo_encoder.c
@@ -311,7 +311,7 @@ xo_encoder_init (xo_handle_t *xop, const char *name)
xo_set_encoder(xop, xep->xe_handler);
- return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL);
+ return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL, 0);
}
/*
@@ -337,7 +337,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags)
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
- const char *name, const char *value)
+ const char *name, const char *value, xo_xof_flags_t flags)
{
void *private = xo_get_private(xop);
xo_encoder_func_t func = xo_get_encoder(xop);
@@ -345,7 +345,7 @@ xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
if (func == NULL)
return -1;
- return func(xop, op, name, value, private);
+ return func(xop, op, name, value, private, flags);
}
const char *
@@ -416,7 +416,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags)
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
- const char *name, const char *value)
+ const char *name, const char *value, xo_xof_flags_t flags)
{
return -1;
}
diff --git a/freebsd/contrib/libxo/libxo/xo_encoder.h b/freebsd/contrib/libxo/libxo/xo_encoder.h
index f73552b1..0e20e72a 100644
--- a/freebsd/contrib/libxo/libxo/xo_encoder.h
+++ b/freebsd/contrib/libxo/libxo/xo_encoder.h
@@ -50,7 +50,8 @@ typedef unsigned xo_encoder_op_t;
xo_encoder_op_t op __attribute__ ((__unused__)), \
const char *name __attribute__ ((__unused__)), \
const char *value __attribute__ ((__unused__)), \
- void *private __attribute__ ((__unused__))
+ void *private __attribute__ ((__unused__)), \
+ xo_xof_flags_t flags __attribute__ ((__unused__))
typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS);
@@ -105,7 +106,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags);
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
- const char *name, const char *value);
+ const char *name, const char *value, xo_xof_flags_t flags);
void
xo_encoders_clean (void);
diff --git a/freebsd/lib/libc/include/libc_private.h b/freebsd/lib/libc/include/libc_private.h
index 6ef99342..91f832a0 100644
--- a/freebsd/lib/libc/include/libc_private.h
+++ b/freebsd/lib/libc/include/libc_private.h
@@ -315,6 +315,7 @@ struct rusage;
struct sigaction;
struct sockaddr;
struct stat;
+struct statfs;
struct timespec;
struct timeval;
struct timezone;
@@ -331,13 +332,16 @@ int __sys_clock_nanosleep(__clockid_t, int,
const struct timespec *, struct timespec *);
int __sys_close(int);
int __sys_connect(int, const struct sockaddr *, __socklen_t);
-__ssize_t __sys_getdirentries(int, char *, __size_t, __off_t *);
int __sys_fcntl(int, int, ...);
int __sys_fdatasync(int);
+int __sys_fstat(int fd, struct stat *);
+int __sys_fstatfs(int fd, struct statfs *);
int __sys_fstatat(int, const char *, struct stat *, int);
int __sys_fsync(int);
__pid_t __sys_fork(void);
int __sys_ftruncate(int, __off_t);
+__ssize_t __sys_getdirentries(int, char *, __size_t, __off_t *);
+int __sys_getfsstat(struct statfs *, long, int);
int __sys_gettimeofday(struct timeval *, struct timezone *);
int __sys_kevent(int, const struct kevent *, int, struct kevent *,
int, const struct timespec *);
@@ -376,6 +380,7 @@ int __sys_sigtimedwait(const __sigset_t *, struct __siginfo *,
const struct timespec *);
int __sys_sigwait(const __sigset_t *, int *);
int __sys_sigwaitinfo(const __sigset_t *, struct __siginfo *);
+int __sys_statfs(const char *, struct statfs *);
int __sys_swapcontext(struct __ucontext *,
const struct __ucontext *);
int __sys_thr_kill(long, int);
@@ -414,6 +419,11 @@ void __libc_map_stacks_exec(void);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);
+struct _pthread_cleanup_info;
+void ___pthread_cleanup_push_imp(void (*)(void *), void *,
+ struct _pthread_cleanup_info *);
+void ___pthread_cleanup_pop_imp(int);
+
void __throw_constraint_handler_s(const char * restrict msg, int error);
#endif /* _LIBC_PRIVATE_H_ */
diff --git a/freebsd/lib/libc/net/nsdispatch.c b/freebsd/lib/libc/net/nsdispatch.c
index f097375d..c739bf6a 100644
--- a/freebsd/lib/libc/net/nsdispatch.c
+++ b/freebsd/lib/libc/net/nsdispatch.c
@@ -544,7 +544,7 @@ fin:
vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare);
}
-
+static int exiting = 0;
static void
ns_mod_free(ns_mod *mod)
@@ -555,12 +555,10 @@ ns_mod_free(ns_mod *mod)
return;
if (mod->unregister != NULL)
mod->unregister(mod->mtab, mod->mtabsize);
- if (mod->handle != nss_builtin_handle)
+ if (mod->handle != nss_builtin_handle && !exiting)
(void)dlclose(mod->handle);
}
-
-
/*
* Cleanup
*/
@@ -569,6 +567,7 @@ nss_atexit(void)
{
int isthreaded;
+ exiting = 1;
isthreaded = __isthreaded;
if (isthreaded)
(void)_pthread_rwlock_wrlock(&nss_lock);
@@ -617,8 +616,6 @@ rtems_nss_register_module(const char *source, ns_mtab *mtab,
}
#endif /* __rtems__ */
-
-
/*
* Finally, the actual implementation.
*/
diff --git a/freebsd/lib/libc/rpc/getnetconfig.c b/freebsd/lib/libc/rpc/getnetconfig.c
index 5e500834..dd3fa87e 100644
--- a/freebsd/lib/libc/rpc/getnetconfig.c
+++ b/freebsd/lib/libc/rpc/getnetconfig.c
@@ -694,7 +694,7 @@ static struct netconfig *
dup_ncp(struct netconfig *ncp)
{
struct netconfig *p;
- char *tmp, *tmp2;
+ char *tmp;
u_int i;
if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
@@ -703,7 +703,6 @@ dup_ncp(struct netconfig *ncp)
free(tmp);
return(NULL);
}
- tmp2 = tmp;
/*
* First we dup all the data from matched netconfig buffer. Then we
* adjust some of the member pointer to a pre-allocated buffer where
@@ -725,7 +724,6 @@ dup_ncp(struct netconfig *ncp)
if (p->nc_lookups == NULL) {
free(p->nc_netid);
free(p);
- free(tmp2);
return(NULL);
}
for (i=0; i < p->nc_nlookups; i++) {
diff --git a/freebsd/lib/libc/rpc/rpc_generic.c b/freebsd/lib/libc/rpc/rpc_generic.c
index bb8c606b..5bd983c4 100644
--- a/freebsd/lib/libc/rpc/rpc_generic.c
+++ b/freebsd/lib/libc/rpc/rpc_generic.c
@@ -611,6 +611,8 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
switch (af) {
case AF_INET:
+ if (nbuf->len < sizeof(*sin))
+ return NULL;
sin = nbuf->buf;
if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
== NULL)
@@ -622,6 +624,8 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
break;
#ifdef INET6
case AF_INET6:
+ if (nbuf->len < sizeof(*sin6))
+ return NULL;
sin6 = nbuf->buf;
if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
== NULL)
@@ -660,6 +664,10 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr)
port = 0;
sin = NULL;
+
+ if (uaddr == NULL)
+ return NULL;
+
addrstr = strdup(uaddr);
if (addrstr == NULL)
return NULL;
diff --git a/freebsd/lib/libc/rpc/rpcb_clnt.c b/freebsd/lib/libc/rpc/rpcb_clnt.c
index 669c9bec..16cdf20d 100644
--- a/freebsd/lib/libc/rpc/rpcb_clnt.c
+++ b/freebsd/lib/libc/rpc/rpcb_clnt.c
@@ -500,14 +500,15 @@ try_nconf:
hostname = IN6_LOCALHOST_STRING;
}
}
- endnetconfig(nc_handle);
if (tmpnconf == NULL) {
+ endnetconfig(nc_handle);
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
mutex_unlock(&loopnconf_lock);
return (NULL);
}
loopnconf = getnetconfigent(tmpnconf->nc_netid);
/* loopnconf is never freed */
+ endnetconfig(nc_handle);
}
mutex_unlock(&loopnconf_lock);
client = getclnthandle(hostname, loopnconf, NULL);
diff --git a/freebsd/lib/libc/rpc/rpcb_prot.c b/freebsd/lib/libc/rpc/rpcb_prot.c
index 95072371..ede13565 100644
--- a/freebsd/lib/libc/rpc/rpcb_prot.c
+++ b/freebsd/lib/libc/rpc/rpcb_prot.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/rpcb_prot.h>
+#include <rpc/rpc_com.h>
#include "un-namespace.h"
bool_t
@@ -64,13 +65,13 @@ xdr_rpcb(XDR *xdrs, RPCB *objp)
if (!xdr_rpcvers(xdrs, &objp->r_vers)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_addr, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_addr, RPC_MAXDATASIZE)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_owner, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_owner, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
@@ -164,19 +165,19 @@ xdr_rpcblist(XDR *xdrs, RPCBLIST **rp)
bool_t
xdr_rpcb_entry(XDR *xdrs, rpcb_entry *objp)
{
- if (!xdr_string(xdrs, &objp->r_maddr, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_maddr, RPC_MAXDATASIZE)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_nc_netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_nc_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_nc_protofmly, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_nc_protofmly, RPC_MAXDATASIZE)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->r_nc_proto, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->r_nc_proto, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
@@ -291,7 +292,7 @@ xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *p)
bool_t dummy;
struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p;
- if (!xdr_string(xdrs, &objp->addr, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->addr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_u_int(xdrs, &objp->results.results_len)) {
diff --git a/freebsd/lib/libc/rpc/rpcb_st_xdr.c b/freebsd/lib/libc/rpc/rpcb_st_xdr.c
index 6b8711ea..dc5be588 100644
--- a/freebsd/lib/libc/rpc/rpcb_st_xdr.c
+++ b/freebsd/lib/libc/rpc/rpcb_st_xdr.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "namespace.h"
#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
#include "un-namespace.h"
/* Link list of all the stats about getport and getaddr */
@@ -65,7 +66,7 @@ xdr_rpcbs_addrlist(XDR *xdrs, rpcbs_addrlist *objp)
if (!xdr_int(xdrs, &objp->failure)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
@@ -117,7 +118,7 @@ xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
IXDR_PUT_INT32(buf, objp->failure);
IXDR_PUT_INT32(buf, objp->indirect);
}
- if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
pnext = &objp->next;
@@ -156,7 +157,7 @@ xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
objp->failure = (int)IXDR_GET_INT32(buf);
objp->indirect = (int)IXDR_GET_INT32(buf);
}
- if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_pointer(xdrs, (char **) pnext,
@@ -184,7 +185,7 @@ xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
if (!xdr_int(xdrs, &objp->indirect)) {
return (FALSE);
}
- if (!xdr_string(xdrs, &objp->netid, (u_int)~0)) {
+ if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_pointer(xdrs, (char **) pnext,
diff --git a/freebsd/lib/libc/stdio/fgetln.c b/freebsd/lib/libc/stdio/fgetln.c
index 8d1235c5..7f5e18b3 100644
--- a/freebsd/lib/libc/stdio/fgetln.c
+++ b/freebsd/lib/libc/stdio/fgetln.c
@@ -87,22 +87,25 @@ char *
fgetln(FILE *fp, size_t *lenp)
{
unsigned char *p;
+ char *ret;
size_t len;
size_t off;
+#ifndef __rtems__
+ FLOCKFILE_CANCELSAFE(fp);
+#else /* __rtems__ */
FLOCKFILE(fp);
+#endif /* __rtems__ */
ORIENT(fp, -1);
/* make sure there is input */
if (fp->_r <= 0 && __srefill(fp)) {
*lenp = 0;
- FUNLOCKFILE(fp);
- return (NULL);
+ ret = NULL;
+ goto end;
}
/* look for a newline in the input */
if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) {
- char *ret;
-
/*
* Found one. Flag buffer as modified to keep fseek from
* `optimising' a backward seek, in case the user stomps on
@@ -116,8 +119,7 @@ fgetln(FILE *fp, size_t *lenp)
#endif /* __rtems__ */
fp->_r -= len;
fp->_p = p;
- FUNLOCKFILE(fp);
- return (ret);
+ goto end;
}
/*
@@ -167,12 +169,18 @@ fgetln(FILE *fp, size_t *lenp)
#ifdef notdef
fp->_lb._base[len] = '\0';
#endif
+ ret = (char *)fp->_lb._base;
+end:
+#ifndef __rtems__
+ FUNLOCKFILE_CANCELSAFE();
+#else /* __rtems__ */
FUNLOCKFILE(fp);
- return ((char *)fp->_lb._base);
+#endif /* __rtems__ */
+ return (ret);
error:
*lenp = 0; /* ??? */
fp->_flags |= __SERR;
- FUNLOCKFILE(fp);
- return (NULL); /* ??? */
+ ret = NULL;
+ goto end;
}
diff --git a/freebsd/lib/libc/stdio/local.h b/freebsd/lib/libc/stdio/local.h
index 5a7fd577..26a4afe9 100644
--- a/freebsd/lib/libc/stdio/local.h
+++ b/freebsd/lib/libc/stdio/local.h
@@ -38,6 +38,9 @@
* $FreeBSD$
*/
+#ifndef _STDIO_LOCAL_H
+#define _STDIO_LOCAL_H
+
#include <sys/types.h> /* for off_t */
#include <pthread.h>
#include <string.h>
@@ -65,7 +68,7 @@ extern FILE *__sfp(void);
extern int __slbexpand(FILE *, size_t);
#ifndef __rtems__
extern int __srefill(FILE *);
-#else
+#else /* __rtems__ */
/*
* __srefill is used by fgetln(). The method is in newlib but the
* prototype is in a private .h which is not installed.
@@ -74,7 +77,7 @@ extern int __srefill(FILE *);
extern int __srefill_r(struct _reent *,FILE *);
#define __srefill(_x) __srefill_r(__getreent(), _x)
-#endif
+#endif /* __rtems__ */
extern int __sread(void *, char *, int);
extern int __swrite(void *, char const *, int);
extern fpos_t __sseek(void *, fpos_t, int);
@@ -155,9 +158,32 @@ __fgetwc(FILE *fp, locale_t locale)
*/
#ifdef __rtems__
#define ORIENT(fp, o)
-#else
+#else /* __rtems__ */
#define ORIENT(fp, o) do { \
if ((fp)->_orientation == 0) \
(fp)->_orientation = (o); \
} while (0)
-#endif
+
+void __stdio_cancel_cleanup(void *);
+#define FLOCKFILE_CANCELSAFE(fp) \
+ { \
+ struct _pthread_cleanup_info __cleanup_info__; \
+ if (__isthreaded) { \
+ _FLOCKFILE(fp); \
+ ___pthread_cleanup_push_imp( \
+ __stdio_cancel_cleanup, (fp), \
+ &__cleanup_info__); \
+ } else { \
+ ___pthread_cleanup_push_imp( \
+ __stdio_cancel_cleanup, NULL, \
+ &__cleanup_info__); \
+ } \
+ {
+#define FUNLOCKFILE_CANCELSAFE() \
+ (void)0; \
+ } \
+ ___pthread_cleanup_pop_imp(1); \
+ }
+
+#endif /* __rtems__ */
+#endif /* _STDIO_LOCAL_H */
diff --git a/freebsd/lib/libc/xdr/xdr.c b/freebsd/lib/libc/xdr/xdr.c
index c529bb95..877f2efa 100644
--- a/freebsd/lib/libc/xdr/xdr.c
+++ b/freebsd/lib/libc/xdr/xdr.c
@@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
@@ -66,7 +68,6 @@ typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */
*/
#define XDR_FALSE ((long) 0)
#define XDR_TRUE ((long) 1)
-#define LASTUNSIGNED ((u_int) 0-1)
/*
* for unit alignment
@@ -561,6 +562,7 @@ xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
{
char *sp = *cpp; /* sp is the actual string pointer */
u_int nodesize;
+ bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr bytes are counted
@@ -584,6 +586,7 @@ xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
}
if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
+ allocated = TRUE;
}
if (sp == NULL) {
warnx("xdr_bytes: out of memory");
@@ -592,7 +595,14 @@ xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
/* FALLTHROUGH */
case XDR_ENCODE:
- return (xdr_opaque(xdrs, sp, nodesize));
+ ret = xdr_opaque(xdrs, sp, nodesize);
+ if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+ if (allocated == TRUE) {
+ free(sp);
+ *cpp = NULL;
+ }
+ }
+ return (ret);
case XDR_FREE:
if (sp != NULL) {
@@ -683,6 +693,7 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
char *sp = *cpp; /* sp is the actual string pointer */
u_int size;
u_int nodesize;
+ bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr strings are counted-strings
@@ -716,8 +727,10 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
if (nodesize == 0) {
return (TRUE);
}
- if (sp == NULL)
+ if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
+ allocated = TRUE;
+ }
if (sp == NULL) {
warnx("xdr_string: out of memory");
return (FALSE);
@@ -726,7 +739,14 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
/* FALLTHROUGH */
case XDR_ENCODE:
- return (xdr_opaque(xdrs, sp, size));
+ ret = xdr_opaque(xdrs, sp, size);
+ if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+ if (allocated == TRUE) {
+ free(sp);
+ *cpp = NULL;
+ }
+ }
+ return (ret);
case XDR_FREE:
mem_free(sp, nodesize);
@@ -744,7 +764,7 @@ xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
bool_t
xdr_wrapstring(XDR *xdrs, char **cpp)
{
- return xdr_string(xdrs, cpp, LASTUNSIGNED);
+ return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
}
/*
diff --git a/freebsd/sbin/sysctl/sysctl.c b/freebsd/sbin/sysctl/sysctl.c
index 8de24190..c6907afe 100644
--- a/freebsd/sbin/sysctl/sysctl.c
+++ b/freebsd/sbin/sysctl/sysctl.c
@@ -974,6 +974,36 @@ show_var(int *oid, int nlen)
printf("%s", buf);
return (0);
}
+
+ /* don't fetch opaques that we don't know how to print */
+ if (ctltype == CTLTYPE_OPAQUE) {
+ if (strcmp(fmt, "S,clockinfo") == 0)
+#ifndef __rtems__
+ func = S_clockinfo;
+#else /* __rtems__ */
+ func = NULL;
+#endif /* __rtems__ */
+ else if (strcmp(fmt, "S,timeval") == 0)
+ func = S_timeval;
+ else if (strcmp(fmt, "S,loadavg") == 0)
+ func = S_loadavg;
+ else if (strcmp(fmt, "S,vmtotal") == 0)
+ func = S_vmtotal;
+#ifdef __amd64__
+ else if (strcmp(fmt, "S,efi_map_header") == 0)
+ func = S_efi_map;
+#endif
+#if defined(__amd64__) || defined(__i386__)
+ else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
+ func = S_bios_smap_xattr;
+#endif
+ else {
+ func = NULL;
+ if (!bflag && !oflag && !xflag)
+ return (1);
+ }
+ }
+
/* find an estimate of how much we need for this var */
if (Bflag)
j = Bflag;
@@ -1094,28 +1124,6 @@ show_var(int *oid, int nlen)
case CTLTYPE_OPAQUE:
i = 0;
- if (strcmp(fmt, "S,clockinfo") == 0)
-#ifndef __rtems__
- func = S_clockinfo;
-#else /* __rtems__ */
- func = NULL;
-#endif /* __rtems__ */
- else if (strcmp(fmt, "S,timeval") == 0)
- func = S_timeval;
- else if (strcmp(fmt, "S,loadavg") == 0)
- func = S_loadavg;
- else if (strcmp(fmt, "S,vmtotal") == 0)
- func = S_vmtotal;
-#ifdef __amd64__
- else if (strcmp(fmt, "S,efi_map_header") == 0)
- func = S_efi_map;
-#endif
-#if defined(__amd64__) || defined(__i386__)
- else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
- func = S_bios_smap_xattr;
-#endif
- else
- func = NULL;
if (func) {
if (!nflag)
printf("%s%s", name, sep);
diff --git a/freebsd/sys/arm/ti/ti_sdhci.c b/freebsd/sys/arm/ti/ti_sdhci.c
index 94096fd6..76e4b750 100644
--- a/freebsd/sys/arm/ti/ti_sdhci.c
+++ b/freebsd/sys/arm/ti/ti_sdhci.c
@@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -62,6 +64,8 @@ __FBSDID("$FreeBSD$");
#include <arm/ti/ti_hwmods.h>
#include <rtems/bsd/local/gpio_if.h>
+#include <rtems/bsd/local/opt_mmccam.h>
+
struct ti_sdhci_softc {
device_t dev;
struct sdhci_fdt_gpio * gpio;
@@ -124,6 +128,11 @@ static struct ofw_compat_data compat_data[] = {
#define MMCHS_SD_CAPA_VS30 (1 << 25)
#define MMCHS_SD_CAPA_VS33 (1 << 24)
+/* Forward declarations, CAM-relataed */
+// static void ti_sdhci_cam_poll(struct cam_sim *);
+// static void ti_sdhci_cam_action(struct cam_sim *, union ccb *);
+// static int ti_sdhci_cam_settran_settings(struct ti_sdhci_softc *sc, union ccb *);
+
static inline uint32_t
ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off)
{
@@ -243,6 +252,22 @@ ti_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
struct ti_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32;
+#ifdef MMCCAM
+ uint32_t newval32;
+ if (off == SDHCI_HOST_CONTROL) {
+ val32 = ti_mmchs_read_4(sc, MMCHS_CON);
+ newval32 = val32;
+ if (val & SDHCI_CTRL_8BITBUS) {
+ device_printf(dev, "Custom-enabling 8-bit bus\n");
+ newval32 |= MMCHS_CON_DW8;
+ } else {
+ device_printf(dev, "Custom-disabling 8-bit bus\n");
+ newval32 &= ~MMCHS_CON_DW8;
+ }
+ if (newval32 != val32)
+ ti_mmchs_write_4(sc, MMCHS_CON, newval32);
+ }
+#endif
val32 = RD4(sc, off & ~3);
val32 &= ~(0xff << (off & 3) * 8);
val32 |= (val << (off & 3) * 8);
@@ -660,8 +685,11 @@ ti_sdhci_attach(device_t dev)
bus_generic_probe(dev);
bus_generic_attach(dev);
+#ifdef MMCCAM
+ sdhci_cam_start_slot(&sc->slot);
+#else
sdhci_start_slot(&sc->slot);
-
+#endif
return (0);
fail:
@@ -732,4 +760,7 @@ static driver_t ti_sdhci_driver = {
DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL,
NULL);
MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1);
+
+#ifndef MMCCAM
MMC_DECLARE_BRIDGE(sdhci_ti);
+#endif
diff --git a/freebsd/sys/cam/cam.h b/freebsd/sys/cam/cam.h
index 23feb508..4bd569be 100644
--- a/freebsd/sys/cam/cam.h
+++ b/freebsd/sys/cam/cam.h
@@ -32,11 +32,7 @@
#define _CAM_CAM_H 1
#ifdef _KERNEL
-#ifndef __rtems__
-#include <opt_cam.h>
-#else /* __rtems__ */
#include <rtems/bsd/local/opt_cam.h>
-#endif /* __rtems__ */
#endif
#include <sys/cdefs.h>
diff --git a/freebsd/sys/cam/cam_ccb.h b/freebsd/sys/cam/cam_ccb.h
index 99249f43..92d76d6a 100644
--- a/freebsd/sys/cam/cam_ccb.h
+++ b/freebsd/sys/cam/cam_ccb.h
@@ -42,6 +42,7 @@
#include <cam/scsi/scsi_all.h>
#include <cam/ata/ata_all.h>
#include <cam/nvme/nvme_all.h>
+#include <cam/mmc/mmc_all.h>
#ifdef __rtems__
#include <rtems/blkdev.h>
#endif /* __rtems__ */
@@ -209,15 +210,18 @@ typedef enum {
/* Serial Management Protocol */
XPT_NVME_IO = 0x1c | XPT_FC_DEV_QUEUED,
- /* Execiute the requestred NVMe I/O operation */
+ /* Execute the requested NVMe I/O operation */
- XPT_MMCSD_IO = 0x1d | XPT_FC_DEV_QUEUED,
+ XPT_MMC_IO = 0x1d | XPT_FC_DEV_QUEUED,
/* Placeholder for MMC / SD / SDIO I/O stuff */
- XPT_SCAN_TGT = 0x1E | XPT_FC_QUEUED | XPT_FC_USER_CCB
+ XPT_SCAN_TGT = 0x1e | XPT_FC_QUEUED | XPT_FC_USER_CCB
| XPT_FC_XPT_ONLY,
/* Scan Target */
+ XPT_NVME_ADMIN = 0x1f | XPT_FC_DEV_QUEUED,
+ /* Execute the requested NVMe Admin operation */
+
/* HBA engine commands 0x20->0x2F */
XPT_ENG_INQ = 0x20 | XPT_FC_XPT_ONLY,
/* HBA engine feature inquiry */
@@ -270,6 +274,7 @@ typedef enum {
PROTO_SATAPM, /* SATA Port Multiplier */
PROTO_SEMB, /* SATA Enclosure Management Bridge */
PROTO_NVME, /* NVME */
+ PROTO_MMCSD, /* MMC, SD, SDIO */
} cam_proto;
typedef enum {
@@ -286,6 +291,7 @@ typedef enum {
XPORT_ISCSI, /* iSCSI */
XPORT_SRP, /* SCSI RDMA Protocol */
XPORT_NVME, /* NVMe over PCIe */
+ XPORT_MMCSD, /* MMC, SD, SDIO card */
} cam_xport;
#define XPORT_IS_NVME(t) ((t) == XPORT_NVME)
@@ -334,8 +340,8 @@ typedef struct {
struct ccb_hdr {
#ifndef __rtems__
cam_pinfo pinfo; /* Info for priority scheduling */
- camq_entry xpt_links; /* For chaining in the XPT layer */
- camq_entry sim_links; /* For chaining in the SIM layer */
+ camq_entry xpt_links; /* For chaining in the XPT layer */
+ camq_entry sim_links; /* For chaining in the SIM layer */
camq_entry periph_links; /* For chaining in the type driver */
#else /* __rtems__ */
struct cam_sim *sim;
@@ -380,7 +386,7 @@ struct ccb_getdev {
/* Device Statistics CCB */
struct ccb_getdevstats {
struct ccb_hdr ccb_h;
- int dev_openings; /* Space left for more work on device*/
+ int dev_openings; /* Space left for more work on device*/
int dev_active; /* Transactions running on the device */
int allocated; /* CCBs allocated for the device */
int queued; /* CCBs queued to be sent to the device */
@@ -454,7 +460,7 @@ struct device_match_pattern {
union {
struct scsi_static_inquiry_pattern inq_pat;
struct device_id_match_pattern devid_pat;
- } data;
+ } data;
};
typedef enum {
@@ -512,6 +518,7 @@ struct device_match_result {
struct scsi_inquiry_data inq_data;
struct ata_params ident_data;
dev_result_flags flags;
+ struct mmc_params mmc_ident_data;
};
struct bus_match_result {
@@ -554,7 +561,7 @@ typedef enum {
struct ccb_dm_cookie {
void *bus;
- void *target;
+ void *target;
void *device;
void *periph;
void *pdrv;
@@ -737,7 +744,7 @@ struct ccb_scsiio {
u_int8_t *req_map; /* Ptr to mapping info */
u_int8_t *data_ptr; /* Ptr to the data buf/SG list */
u_int32_t dxfer_len; /* Data transfer length */
- /* Autosense storage */
+ /* Autosense storage */
struct scsi_sense_data sense_data;
u_int8_t sense_len; /* Number of bytes to autosense */
u_int8_t cdb_len; /* Number of bytes for the CDB */
@@ -792,6 +799,16 @@ struct ccb_ataio {
uint32_t unused;
};
+/*
+ * MMC I/O Request CCB used for the XPT_MMC_IO function code.
+ */
+struct ccb_mmcio {
+ struct ccb_hdr ccb_h;
+ union ccb *next_ccb; /* Ptr for next CCB for action */
+ struct mmc_command cmd;
+ struct mmc_command stop;
+};
+
struct ccb_accept_tio {
struct ccb_hdr ccb_h;
cdb_t cdb_io; /* Union for CDB bytes/pointer */
@@ -824,7 +841,7 @@ struct ccb_relsim {
};
/*
- * NVMe I/O Request CCB used for the XPT_NVME_IO function code.
+ * NVMe I/O Request CCB used for the XPT_NVME_IO and XPT_NVME_ADMIN function codes.
*/
struct ccb_nvmeio {
struct ccb_hdr ccb_h;
@@ -886,7 +903,7 @@ struct ac_device_changed {
/* Set Asynchronous Callback CCB */
struct ccb_setasync {
struct ccb_hdr ccb_h;
- u_int32_t event_enable; /* Async Event enables */
+ u_int32_t event_enable; /* Async Event enables */
ac_callback_t *callback;
void *callback_arg;
};
@@ -1028,7 +1045,28 @@ struct ccb_trans_settings_nvme
u_int max_xfer; /* Max transfer size (0 -> unlimited */
u_int caps;
};
-
+
+#include <cam/mmc/mmc_bus.h>
+struct ccb_trans_settings_mmc {
+ struct mmc_ios ios;
+#define MMC_CLK (1 << 1)
+#define MMC_VDD (1 << 2)
+#define MMC_CS (1 << 3)
+#define MMC_BW (1 << 4)
+#define MMC_PM (1 << 5)
+#define MMC_BT (1 << 6)
+#define MMC_BM (1 << 7)
+ uint32_t ios_valid;
+/* The folowing is used only for GET_TRAN_SETTINGS */
+ uint32_t host_ocr;
+ int host_f_min;
+ int host_f_max;
+#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can do 4-bit data transfers */
+#define MMC_CAP_8_BIT_DATA (1 << 1) /* Can do 8-bit data transfers */
+#define MMC_CAP_HSPEED (1 << 2) /* Can do High Speed transfers */
+ uint32_t host_caps;
+};
+
/* Get/Set transfer rate/width/disconnection/tag queueing settings */
struct ccb_trans_settings {
struct ccb_hdr ccb_h;
@@ -1042,6 +1080,7 @@ struct ccb_trans_settings {
struct ccb_trans_settings_ata ata;
struct ccb_trans_settings_scsi scsi;
struct ccb_trans_settings_nvme nvme;
+ struct ccb_trans_settings_mmc mmc;
} proto_specific;
union {
u_int valid; /* Which fields to honor */
@@ -1063,7 +1102,7 @@ struct ccb_calc_geometry {
struct ccb_hdr ccb_h;
u_int32_t block_size;
u_int64_t volume_size;
- u_int32_t cylinders;
+ u_int32_t cylinders;
u_int8_t heads;
u_int8_t secs_per_track;
};
@@ -1285,8 +1324,8 @@ union ccb {
struct ccb_getdevstats cgds;
struct ccb_dev_match cdm;
struct ccb_trans_settings cts;
- struct ccb_calc_geometry ccg;
- struct ccb_sim_knob knob;
+ struct ccb_calc_geometry ccg;
+ struct ccb_sim_knob knob;
struct ccb_abort cab;
struct ccb_resetbus crb;
struct ccb_resetdev crd;
@@ -1307,6 +1346,7 @@ union ccb {
struct ccb_dev_advinfo cdai;
struct ccb_async casync;
struct ccb_nvmeio nvmeio;
+ struct ccb_mmcio mmcio;
};
#define CCB_CLEAR_ALL_EXCEPT_HDR(ccbp) \
@@ -1343,13 +1383,20 @@ cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
u_int32_t timeout);
static __inline void
-cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
+cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
uint8_t *smp_request, int smp_request_len,
uint8_t *smp_response, int smp_response_len,
uint32_t timeout);
static __inline void
+cam_fill_mmcio(struct ccb_mmcio *mmcio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint32_t mmc_opcode, uint32_t mmc_arg, uint32_t mmc_flags,
+ struct mmc_data *mmc_d,
+ uint32_t timeout);
+
+static __inline void
cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *),
u_int32_t flags, u_int8_t tag_action,
@@ -1360,7 +1407,7 @@ cam_fill_csio(struct ccb_scsiio *csio, u_int32_t retries,
csio->ccb_h.func_code = XPT_SCSI_IO;
csio->ccb_h.flags = flags;
csio->ccb_h.xflags = 0;
- csio->ccb_h.retry_count = retries;
+ csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
csio->data_ptr = data_ptr;
@@ -1383,7 +1430,7 @@ cam_fill_ctio(struct ccb_scsiio *csio, u_int32_t retries,
csio->ccb_h.func_code = XPT_CONT_TARGET_IO;
csio->ccb_h.flags = flags;
csio->ccb_h.xflags = 0;
- csio->ccb_h.retry_count = retries;
+ csio->ccb_h.retry_count = retries;
csio->ccb_h.cbfcnp = cbfcnp;
csio->ccb_h.timeout = timeout;
csio->data_ptr = data_ptr;
@@ -1412,7 +1459,7 @@ cam_fill_ataio(struct ccb_ataio *ataio, u_int32_t retries,
}
static __inline void
-cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
+cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
uint8_t *smp_request, int smp_request_len,
uint8_t *smp_response, int smp_response_len,
@@ -1438,6 +1485,34 @@ cam_fill_smpio(struct ccb_smpio *smpio, uint32_t retries,
}
static __inline void
+cam_fill_mmcio(struct ccb_mmcio *mmcio, uint32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *), uint32_t flags,
+ uint32_t mmc_opcode, uint32_t mmc_arg, uint32_t mmc_flags,
+ struct mmc_data *mmc_d,
+ uint32_t timeout)
+{
+ mmcio->ccb_h.func_code = XPT_MMC_IO;
+ mmcio->ccb_h.flags = flags;
+ mmcio->ccb_h.retry_count = retries;
+ mmcio->ccb_h.cbfcnp = cbfcnp;
+ mmcio->ccb_h.timeout = timeout;
+ mmcio->cmd.opcode = mmc_opcode;
+ mmcio->cmd.arg = mmc_arg;
+ mmcio->cmd.flags = mmc_flags;
+ mmcio->stop.opcode = 0;
+ mmcio->stop.arg = 0;
+ mmcio->stop.flags = 0;
+ if (mmc_d != NULL) {
+ mmcio->cmd.data = mmc_d;
+ } else
+ mmcio->cmd.data = NULL;
+ mmcio->cmd.resp[0] = 0;
+ mmcio->cmd.resp[1] = 0;
+ mmcio->cmd.resp[2] = 0;
+ mmcio->cmd.resp[3] = 0;
+}
+
+static __inline void
cam_set_ccbstatus(union ccb *ccb, cam_status status)
{
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
@@ -1466,6 +1541,21 @@ cam_fill_nvmeio(struct ccb_nvmeio *nvmeio, u_int32_t retries,
nvmeio->data_ptr = data_ptr;
nvmeio->dxfer_len = dxfer_len;
}
+
+static __inline void
+cam_fill_nvmeadmin(struct ccb_nvmeio *nvmeio, u_int32_t retries,
+ void (*cbfcnp)(struct cam_periph *, union ccb *),
+ u_int32_t flags, u_int8_t *data_ptr, u_int32_t dxfer_len,
+ u_int32_t timeout)
+{
+ nvmeio->ccb_h.func_code = XPT_NVME_ADMIN;
+ nvmeio->ccb_h.flags = flags;
+ nvmeio->ccb_h.retry_count = retries;
+ nvmeio->ccb_h.cbfcnp = cbfcnp;
+ nvmeio->ccb_h.timeout = timeout;
+ nvmeio->data_ptr = data_ptr;
+ nvmeio->dxfer_len = dxfer_len;
+}
__END_DECLS
#endif /* _CAM_CAM_CCB_H */
diff --git a/freebsd/sys/cam/cam_xpt.h b/freebsd/sys/cam/cam_xpt.h
index 8e6027e5..47fdbd74 100644
--- a/freebsd/sys/cam/cam_xpt.h
+++ b/freebsd/sys/cam/cam_xpt.h
@@ -141,6 +141,8 @@ void xpt_copy_path(struct cam_path *new_path,
void xpt_release_path(struct cam_path *path);
+const char * xpt_action_name(uint32_t action);
+
#endif /* _KERNEL */
#endif /* _CAM_CAM_XPT_H */
diff --git a/freebsd/sys/cam/mmc/mmc.h b/freebsd/sys/cam/mmc/mmc.h
new file mode 100644
index 00000000..9fae837e
--- /dev/null
+++ b/freebsd/sys/cam/mmc/mmc.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2014-2016 Ilya Bakulin. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * Inspired coded in sys/dev/mmc. Thanks to Warner Losh <imp@FreeBSD.org>,
+ * Bernd Walter <tisco@FreeBSD.org>, and other authors.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef CAM_MMC_H
+#define CAM_MMC_H
+
+#include <dev/mmc/mmcreg.h>
+/*
+ * This structure describes an MMC/SD card
+ */
+struct mmc_params {
+ u_int8_t model[40]; /* Card model */
+
+ /* Card OCR */
+ uint32_t card_ocr;
+
+ /* OCR of the IO portion of the card */
+ uint32_t io_ocr;
+
+ /* Card CID -- raw and parsed */
+ uint32_t card_cid[4];
+ struct mmc_cid cid;
+
+ /* Card CSD -- raw */
+ uint32_t card_csd[4];
+
+ /* Card RCA */
+ uint16_t card_rca;
+
+ /* What kind of card is it */
+ uint32_t card_features;
+#define CARD_FEATURE_MEMORY 0x1
+#define CARD_FEATURE_SDHC 0x1 << 1
+#define CARD_FEATURE_SDIO 0x1 << 2
+#define CARD_FEATURE_SD20 0x1 << 3
+#define CARD_FEATURE_MMC 0x1 << 4
+
+ uint8_t sdio_func_count;
+} __packed;
+
+#endif
diff --git a/freebsd/sys/cam/mmc/mmc_all.h b/freebsd/sys/cam/mmc/mmc_all.h
new file mode 100644
index 00000000..c2494894
--- /dev/null
+++ b/freebsd/sys/cam/mmc/mmc_all.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2014-2016 Ilya Bakulin. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * MMC function that should be visible to the CAM subsystem
+ * and are somehow useful should be declared here
+ *
+ * Like in other *_all.h, it's also a nice place to include
+ * some other transport-specific headers.
+ */
+
+#ifndef CAM_MMC_ALL_H
+#define CAM_MMC_ALL_H
+
+#include <cam/mmc/mmc.h>
+#include <dev/mmc/mmcreg.h>
+
+void mmc_print_ident(struct mmc_params *ident_data);
+
+#endif
diff --git a/freebsd/sys/cam/mmc/mmc_bus.h b/freebsd/sys/cam/mmc/mmc_bus.h
new file mode 100644
index 00000000..db77da51
--- /dev/null
+++ b/freebsd/sys/cam/mmc/mmc_bus.h
@@ -0,0 +1,5 @@
+/*
+ * This file is in the public domain.
+ * $FreeBSD$
+ */
+#include <dev/mmc/bridge.h>
diff --git a/freebsd/sys/cam/mmc/mmc_sdio.h b/freebsd/sys/cam/mmc/mmc_sdio.h
new file mode 100644
index 00000000..6d22ffc0
--- /dev/null
+++ b/freebsd/sys/cam/mmc/mmc_sdio.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2014 Ilya Bakulin. 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification. The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Various SDIO-related stuff
+ */
+
+#ifndef CAM_MMC_SDIO_H
+#define CAM_MMC_SDIO_H
+
+void sdio_print_stupid_message(struct cam_periph *periph);
+void sdio_fill_mmcio_rw_direct(union ccb *ccb, uint8_t f, uint8_t wr, uint32_t adr, uint8_t *data);
+uint8_t sdio_parse_mmcio_rw_direct(union ccb *ccb, uint8_t *data);
+#endif
diff --git a/freebsd/sys/cam/scsi/scsi_all.c b/freebsd/sys/cam/scsi/scsi_all.c
index 99f6c37d..85e95cb6 100644
--- a/freebsd/sys/cam/scsi/scsi_all.c
+++ b/freebsd/sys/cam/scsi/scsi_all.c
@@ -37,11 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/stdint.h>
#ifdef _KERNEL
-#ifndef __rtems__
-#include <opt_scsi.h>
-#else /* __rtems__ */
#include <rtems/bsd/local/opt_scsi.h>
-#endif /* __rtems__ */
#include <sys/systm.h>
#include <sys/libkern.h>
diff --git a/freebsd/sys/dev/e1000/if_em.c b/freebsd/sys/dev/e1000/if_em.c
index 69381438..f5a0b94e 100644
--- a/freebsd/sys/dev/e1000/if_em.c
+++ b/freebsd/sys/dev/e1000/if_em.c
@@ -205,7 +205,7 @@ static pci_vendor_info_t igb_vendor_info_array[] =
PVID(0x8086, E1000_DEV_ID_I210_COPPER_OEM1, "Intel(R) PRO/1000 PCI-Express Network Driver"),
PVID(0x8086, E1000_DEV_ID_I210_COPPER_FLASHLESS, "Intel(R) PRO/1000 PCI-Express Network Driver"),
PVID(0x8086, E1000_DEV_ID_I210_SERDES_FLASHLESS, "Intel(R) PRO/1000 PCI-Express Network Driver"),
- PVID(0x8086, E1000_DEV_ID_I210_FIBER, "Intel(R) PRO/1000 PCI-Express Network Driver"),
+ PVID(0x8086, E1000_DEV_ID_I210_FIBER, "Intel(R) PRO/1000 PCI-Express Network Driver"),
PVID(0x8086, E1000_DEV_ID_I210_SERDES, "Intel(R) PRO/1000 PCI-Express Network Driver"),
PVID(0x8086, E1000_DEV_ID_I210_SGMII, "Intel(R) PRO/1000 PCI-Express Network Driver"),
PVID(0x8086, E1000_DEV_ID_I211_COPPER, "Intel(R) PRO/1000 PCI-Express Network Driver"),
@@ -233,8 +233,8 @@ static int em_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs
static void em_if_queues_free(if_ctx_t ctx);
static uint64_t em_if_get_counter(if_ctx_t, ift_counter);
-static void em_if_init(if_ctx_t ctx);
-static void em_if_stop(if_ctx_t ctx);
+static void em_if_init(if_ctx_t ctx);
+static void em_if_stop(if_ctx_t ctx);
static void em_if_media_status(if_ctx_t, struct ifmediareq *);
static int em_if_media_change(if_ctx_t ctx);
static int em_if_mtu_set(if_ctx_t ctx, uint32_t mtu);
@@ -359,11 +359,11 @@ static device_method_t em_if_methods[] = {
DEVMETHOD(ifdi_detach, em_if_detach),
DEVMETHOD(ifdi_shutdown, em_if_shutdown),
DEVMETHOD(ifdi_suspend, em_if_suspend),
- DEVMETHOD(ifdi_resume, em_if_resume),
+ DEVMETHOD(ifdi_resume, em_if_resume),
DEVMETHOD(ifdi_init, em_if_init),
DEVMETHOD(ifdi_stop, em_if_stop),
DEVMETHOD(ifdi_msix_intr_assign, em_if_msix_intr_assign),
- DEVMETHOD(ifdi_intr_enable, em_if_enable_intr),
+ DEVMETHOD(ifdi_intr_enable, em_if_enable_intr),
DEVMETHOD(ifdi_intr_disable, em_if_disable_intr),
DEVMETHOD(ifdi_tx_queues_alloc, em_if_tx_queues_alloc),
DEVMETHOD(ifdi_rx_queues_alloc, em_if_rx_queues_alloc),
@@ -1027,7 +1027,7 @@ em_if_attach_post(if_ctx_t ctx)
/* Non-AMT based hardware can now take control from firmware */
if (adapter->has_manage && !adapter->has_amt)
em_get_hw_control(adapter);
-
+
INIT_DEBUGOUT("em_if_attach_post: end");
return (error);
@@ -1403,7 +1403,7 @@ em_msix_link(void *arg)
u32 reg_icr;
++adapter->link_irq;
- MPASS(adapter->hw.back != NULL);
+ MPASS(adapter->hw.back != NULL);
reg_icr = E1000_READ_REG(&adapter->hw, E1000_ICR);
if (reg_icr & E1000_ICR_RXO)
@@ -1665,9 +1665,7 @@ em_if_timer(if_ctx_t ctx, uint16_t qid)
if (qid != 0)
return;
- em_if_update_admin_status(ctx);
- em_update_stats_counters(adapter);
-
+ iflib_admin_intr_deferred(ctx);
/* Reset LAA into RAR[0] on 82571 */
if ((adapter->hw.mac.type == e1000_82571) &&
e1000_get_laa_state_82571(&adapter->hw))
@@ -1693,8 +1691,9 @@ em_if_update_admin_status(if_ctx_t ctx)
struct e1000_hw *hw = &adapter->hw;
struct ifnet *ifp = iflib_get_ifp(ctx);
device_t dev = iflib_get_dev(ctx);
- u32 link_check = 0;
+ u32 link_check, thstat, ctrl;
+ link_check = thstat = ctrl = 0;
/* Get the cached link value or read phy for real */
switch (hw->phy.media_type) {
case e1000_media_type_copper:
@@ -1719,11 +1718,21 @@ em_if_update_admin_status(if_ctx_t ctx)
e1000_check_for_link(hw);
link_check = adapter->hw.mac.serdes_has_link;
break;
- default:
+ /* VF device is type_unknown */
case e1000_media_type_unknown:
+ e1000_check_for_link(hw);
+ link_check = !hw->mac.get_link_status;
+ /* FALLTHROUGH */
+ default:
break;
}
+ /* Check for thermal downshift or shutdown */
+ if (hw->mac.type == e1000_i350) {
+ thstat = E1000_READ_REG(hw, E1000_THSTAT);
+ ctrl = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ }
+
/* Now check for a transition */
if (link_check && (adapter->link_active == 0)) {
e1000_get_speed_and_duplex(hw, &adapter->link_speed,
@@ -1745,6 +1754,21 @@ em_if_update_admin_status(if_ctx_t ctx)
adapter->link_active = 1;
adapter->smartspeed = 0;
if_setbaudrate(ifp, adapter->link_speed * 1000000);
+ if ((ctrl & E1000_CTRL_EXT_LINK_MODE_GMII) &&
+ (thstat & E1000_THSTAT_LINK_THROTTLE))
+ device_printf(dev, "Link: thermal downshift\n");
+ /* Delay Link Up for Phy update */
+ if (((hw->mac.type == e1000_i210) ||
+ (hw->mac.type == e1000_i211)) &&
+ (hw->phy.id == I210_I_PHY_ID))
+ msec_delay(I210_LINK_DELAY);
+ /* Reset if the media type changed. */
+ if ((hw->dev_spec._82575.media_changed) &&
+ (adapter->hw.mac.type >= igb_mac_min)) {
+ hw->dev_spec._82575.media_changed = false;
+ adapter->flags |= IGB_MEDIA_RESET;
+ em_reset(ctx);
+ }
iflib_link_state_change(ctx, LINK_STATE_UP, ifp->if_baudrate);
printf("Link state changed to up\n");
} else if (!link_check && (adapter->link_active == 1)) {
@@ -1757,6 +1781,7 @@ em_if_update_admin_status(if_ctx_t ctx)
iflib_link_state_change(ctx, LINK_STATE_DOWN, ifp->if_baudrate);
printf("link state changed to down\n");
}
+ em_update_stats_counters(adapter);
E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK | E1000_IMS_LSC);
}
@@ -2212,6 +2237,114 @@ lem_smartspeed(struct adapter *adapter)
adapter->smartspeed = 0;
}
+/*********************************************************************
+ *
+ * Initialize the DMA Coalescing feature
+ *
+ **********************************************************************/
+static void
+igb_init_dmac(struct adapter *adapter, u32 pba)
+{
+ device_t dev = adapter->dev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 dmac, reg = ~E1000_DMACR_DMAC_EN;
+ u16 hwm;
+ u16 max_frame_size;
+
+ if (hw->mac.type == e1000_i211)
+ return;
+
+ max_frame_size = adapter->shared->isc_max_frame_size;
+ if (hw->mac.type > e1000_82580) {
+
+ if (adapter->dmac == 0) { /* Disabling it */
+ E1000_WRITE_REG(hw, E1000_DMACR, reg);
+ return;
+ } else
+ device_printf(dev, "DMA Coalescing enabled\n");
+
+ /* Set starting threshold */
+ E1000_WRITE_REG(hw, E1000_DMCTXTH, 0);
+
+ hwm = 64 * pba - max_frame_size / 16;
+ if (hwm < 64 * (pba - 6))
+ hwm = 64 * (pba - 6);
+ reg = E1000_READ_REG(hw, E1000_FCRTC);
+ reg &= ~E1000_FCRTC_RTH_COAL_MASK;
+ reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
+ & E1000_FCRTC_RTH_COAL_MASK);
+ E1000_WRITE_REG(hw, E1000_FCRTC, reg);
+
+
+ dmac = pba - max_frame_size / 512;
+ if (dmac < pba - 10)
+ dmac = pba - 10;
+ reg = E1000_READ_REG(hw, E1000_DMACR);
+ reg &= ~E1000_DMACR_DMACTHR_MASK;
+ reg = ((dmac << E1000_DMACR_DMACTHR_SHIFT)
+ & E1000_DMACR_DMACTHR_MASK);
+
+ /* transition to L0x or L1 if available..*/
+ reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
+
+ /* Check if status is 2.5Gb backplane connection
+ * before configuration of watchdog timer, which is
+ * in msec values in 12.8usec intervals
+ * watchdog timer= msec values in 32usec intervals
+ * for non 2.5Gb connection
+ */
+ if (hw->mac.type == e1000_i354) {
+ int status = E1000_READ_REG(hw, E1000_STATUS);
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ (!(status & E1000_STATUS_2P5_SKU_OVER)))
+ reg |= ((adapter->dmac * 5) >> 6);
+ else
+ reg |= (adapter->dmac >> 5);
+ } else {
+ reg |= (adapter->dmac >> 5);
+ }
+
+ E1000_WRITE_REG(hw, E1000_DMACR, reg);
+
+ E1000_WRITE_REG(hw, E1000_DMCRTRH, 0);
+
+ /* Set the interval before transition */
+ reg = E1000_READ_REG(hw, E1000_DMCTLX);
+ if (hw->mac.type == e1000_i350)
+ reg |= IGB_DMCTLX_DCFLUSH_DIS;
+ /*
+ ** in 2.5Gb connection, TTLX unit is 0.4 usec
+ ** which is 0x4*2 = 0xA. But delay is still 4 usec
+ */
+ if (hw->mac.type == e1000_i354) {
+ int status = E1000_READ_REG(hw, E1000_STATUS);
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ (!(status & E1000_STATUS_2P5_SKU_OVER)))
+ reg |= 0xA;
+ else
+ reg |= 0x4;
+ } else {
+ reg |= 0x4;
+ }
+
+ E1000_WRITE_REG(hw, E1000_DMCTLX, reg);
+
+ /* free space in tx packet buffer to wake from DMA coal */
+ E1000_WRITE_REG(hw, E1000_DMCTXTH, (IGB_TXPBSIZE -
+ (2 * max_frame_size)) >> 6);
+
+ /* make low power state decision controlled by DMA coal */
+ reg = E1000_READ_REG(hw, E1000_PCIEMISC);
+ reg &= ~E1000_PCIEMISC_LX_DECISION;
+ E1000_WRITE_REG(hw, E1000_PCIEMISC, reg);
+
+ } else if (hw->mac.type == e1000_82580) {
+ u32 reg = E1000_READ_REG(hw, E1000_PCIEMISC);
+ E1000_WRITE_REG(hw, E1000_PCIEMISC,
+ reg & ~E1000_PCIEMISC_LX_DECISION);
+ E1000_WRITE_REG(hw, E1000_DMACR, 0);
+ }
+}
static void
em_reset(if_ctx_t ctx)
@@ -2224,6 +2357,8 @@ em_reset(if_ctx_t ctx)
u32 pba;
INIT_DEBUGOUT("em_reset: begin");
+ /* Let the firmware know the OS is in control */
+ em_get_hw_control(adapter);
/* Set up smart power down as default off on newer adapters. */
if (!em_smart_pwr_down && (hw->mac.type == e1000_82571 ||
@@ -2402,15 +2537,15 @@ em_reset(if_ctx_t ctx)
case e1000_vfadapt_i350:
/* 16-byte granularity */
hw->fc.low_water = hw->fc.high_water - 16;
- break;
- case e1000_ich9lan:
- case e1000_ich10lan:
+ break;
+ case e1000_ich9lan:
+ case e1000_ich10lan:
if (if_getmtu(ifp) > ETHERMTU) {
hw->fc.high_water = 0x2800;
hw->fc.low_water = hw->fc.high_water - 8;
break;
}
- /* else fall thru */
+ /* FALLTHROUGH */
default:
if (hw->mac.type == e1000_80003es2lan)
hw->fc.pause_time = 0xFFFF;
@@ -2419,13 +2554,24 @@ em_reset(if_ctx_t ctx)
/* Issue a global reset */
e1000_reset_hw(hw);
- E1000_WRITE_REG(hw, E1000_WUFC, 0);
- em_disable_aspm(adapter);
+ if (adapter->hw.mac.type >= igb_mac_min) {
+ E1000_WRITE_REG(hw, E1000_WUC, 0);
+ } else {
+ E1000_WRITE_REG(hw, E1000_WUFC, 0);
+ em_disable_aspm(adapter);
+ }
+ if (adapter->flags & IGB_MEDIA_RESET) {
+ e1000_setup_init_funcs(hw, TRUE);
+ e1000_get_bus_info(hw);
+ adapter->flags &= ~IGB_MEDIA_RESET;
+ }
/* and a re-init */
if (e1000_init_hw(hw) < 0) {
device_printf(dev, "Hardware Initialization Failed\n");
return;
}
+ if (adapter->hw.mac.type >= igb_mac_min)
+ igb_init_dmac(adapter, pba);
E1000_WRITE_REG(hw, E1000_VET, ETHERTYPE_VLAN);
e1000_get_phy_info(hw);
@@ -2466,7 +2612,7 @@ em_initialize_rss_mapping(struct adapter *adapter)
for (i = 0; i < 32; ++i)
E1000_WRITE_REG(hw, E1000_RETA(i), reta);
- E1000_WRITE_REG(hw, E1000_MRQC, E1000_MRQC_RSS_ENABLE_2Q |
+ E1000_WRITE_REG(hw, E1000_MRQC, E1000_MRQC_RSS_ENABLE_2Q |
E1000_MRQC_RSS_FIELD_IPV4_TCP |
E1000_MRQC_RSS_FIELD_IPV4 |
E1000_MRQC_RSS_FIELD_IPV6_TCP_EX |
@@ -2553,8 +2699,7 @@ igb_initialize_rss_mapping(struct adapter *adapter)
arc4rand(&rss_key, sizeof(rss_key), 0);
#endif
for (i = 0; i < 10; i++)
- E1000_WRITE_REG_ARRAY(hw,
- E1000_RSSRK(0), i, rss_key[i]);
+ E1000_WRITE_REG_ARRAY(hw, E1000_RSSRK(0), i, rss_key[i]);
/*
* Configure the RSS fields to hash upon.
@@ -2621,7 +2766,7 @@ em_setup_interface(if_ctx_t ctx)
/* Enable only WOL MAGIC by default */
if (adapter->wol) {
if_setcapenablebit(ifp, IFCAP_WOL_MAGIC,
- IFCAP_WOL_MCAST| IFCAP_WOL_UCAST);
+ IFCAP_WOL_MCAST| IFCAP_WOL_UCAST);
} else {
if_setcapenablebit(ifp, 0, IFCAP_WOL_MAGIC |
IFCAP_WOL_MCAST| IFCAP_WOL_UCAST);
@@ -2693,7 +2838,7 @@ em_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs
txr->tx_base = (struct e1000_tx_desc *)vaddrs[i*ntxqs];
txr->tx_paddr = paddrs[i*ntxqs];
}
-
+
device_printf(iflib_get_dev(ctx), "allocated for %d tx_queues\n", adapter->tx_num_queues);
return (0);
fail:
@@ -2718,7 +2863,7 @@ em_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs
adapter->rx_num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) {
device_printf(iflib_get_dev(ctx), "Unable to allocate queue memory\n");
error = ENOMEM;
- goto fail;
+ goto fail;
}
for (i = 0, que = adapter->rx_queues; i < nrxqsets; i++, que++) {
@@ -2758,7 +2903,7 @@ em_if_queues_free(if_ctx_t ctx)
txr->tx_rsq = NULL;
}
free(adapter->tx_queues, M_DEVBUF);
- adapter->tx_queues = NULL;
+ adapter->tx_queues = NULL;
}
if (rx_que != NULL) {
@@ -3033,7 +3178,7 @@ em_initialize_receive_unit(if_ctx_t ctx)
u64 bus_addr = rxr->rx_paddr;
#if 0
u32 rdt = adapter->rx_num_queues -1; /* default */
-#endif
+#endif
E1000_WRITE_REG(hw, E1000_RDLEN(i),
scctx->isc_nrxd[0] * sizeof(union e1000_rx_desc_extended));
@@ -3088,7 +3233,7 @@ em_initialize_receive_unit(if_ctx_t ctx)
srrctl |= 2048 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
rctl |= E1000_RCTL_SZ_2048;
}
-
+
/*
* If TX flow control is disabled and there's >1 queue defined,
* enable DROP.
@@ -3126,7 +3271,7 @@ em_initialize_receive_unit(if_ctx_t ctx)
rxdctl &= 0xFFF00000;
rxdctl |= IGB_RX_PTHRESH;
rxdctl |= IGB_RX_HTHRESH << 8;
- rxdctl |= IGB_RX_WTHRESH << 16;
+ rxdctl |= IGB_RX_WTHRESH << 16;
E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
}
} else if (adapter->hw.mac.type >= e1000_pch2lan) {
@@ -3255,7 +3400,7 @@ em_if_disable_intr(if_ctx_t ctx)
/*
* Bit of a misnomer, what this really means is
* to enable OS management of the system... aka
- * to disable special hardware management features
+ * to disable special hardware management features
*/
static void
em_init_manageability(struct adapter *adapter)
@@ -3309,6 +3454,9 @@ em_get_hw_control(struct adapter *adapter)
{
u32 ctrl_ext, swsm;
+ if (adapter->vf_ifp)
+ return;
+
if (adapter->hw.mac.type == e1000_82573) {
swsm = E1000_READ_REG(&adapter->hw, E1000_SWSM);
E1000_WRITE_REG(&adapter->hw, E1000_SWSM,
@@ -3319,7 +3467,6 @@ em_get_hw_control(struct adapter *adapter)
ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT);
E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT,
ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
- return;
}
/*
@@ -3639,7 +3786,7 @@ static void
em_if_led_func(if_ctx_t ctx, int onoff)
{
struct adapter *adapter = iflib_get_softc(ctx);
-
+
if (onoff) {
e1000_setup_led(&adapter->hw);
e1000_led_on(&adapter->hw);
@@ -3785,7 +3932,7 @@ static uint64_t
em_if_get_counter(if_ctx_t ctx, ift_counter cnt)
{
struct adapter *adapter = iflib_get_softc(ctx);
- struct ifnet *ifp = iflib_get_ifp(ctx);
+ struct ifnet *ifp = iflib_get_ifp(ctx);
switch (cnt) {
case IFCOUNTER_COLLISIONS:
@@ -3822,7 +3969,7 @@ static void
em_add_hw_stats(struct adapter *adapter)
{
device_t dev = iflib_get_dev(adapter->ctx);
- struct em_tx_queue *tx_que = adapter->tx_queues;
+ struct em_tx_queue *tx_que = adapter->tx_queues;
struct em_rx_queue *rx_que = adapter->rx_queues;
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
@@ -4067,7 +4214,7 @@ em_add_hw_stats(struct adapter *adapter)
/* Interrupt Stats */
- int_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "interrupts",
+ int_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "interrupts",
CTLFLAG_RD, NULL, "Interrupt Statistics");
int_list = SYSCTL_CHILDREN(int_node);
@@ -4244,7 +4391,7 @@ em_set_flowcntl(SYSCTL_HANDLER_ARGS)
case e1000_fc_none:
adapter->hw.fc.requested_mode = input;
adapter->fc = input;
- break;
+ break;
default:
/* Do nothing */
return (error);
@@ -4292,7 +4439,7 @@ em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
if (result == 1) {
adapter = (struct adapter *) arg1;
em_print_debug_info(adapter);
- }
+ }
return (error);
}
diff --git a/freebsd/sys/dev/e1000/if_em.h b/freebsd/sys/dev/e1000/if_em.h
index 79af551c..67d97e17 100644
--- a/freebsd/sys/dev/e1000/if_em.h
+++ b/freebsd/sys/dev/e1000/if_em.h
@@ -235,6 +235,27 @@
#define EM_EEPROM_APME 0x400;
#define EM_82544_APME 0x0004;
+
+/* Support AutoMediaDetect for Marvell M88 PHY in i354 */
+#define IGB_MEDIA_RESET (1 << 0)
+
+/* Define the starting Interrupt rate per Queue */
+#define IGB_INTS_PER_SEC 8000
+#define IGB_DEFAULT_ITR ((1000000/IGB_INTS_PER_SEC) << 2)
+
+#define IGB_LINK_ITR 2000
+#define I210_LINK_DELAY 1000
+
+#define IGB_MAX_SCATTER 40
+#define IGB_VFTA_SIZE 128
+#define IGB_BR_SIZE 4096 /* ring buf size */
+#define IGB_TSO_SIZE (65535 + sizeof(struct ether_vlan_header))
+#define IGB_TSO_SEG_SIZE 4096 /* Max dma segment size */
+#define IGB_TXPBSIZE 20408
+#define IGB_HDR_BUF 128
+#define IGB_PKTTYPE_MASK 0x0000FFF0
+#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coalesce Flush */
+
/*
* Driver state logic for the detection of a hung state
* in hardware. Set TX_HUNG whenever a TX packet is used
@@ -455,11 +476,11 @@ struct adapter {
struct ifmedia *media;
int msix;
int if_flags;
- int min_frame_size;
int em_insert_vlan_header;
u32 ims;
bool in_detach;
+ u32 flags;
/* Task for FAST handling */
struct grouptask link_task;
@@ -514,6 +535,7 @@ struct adapter {
unsigned long watchdog_events;
struct e1000_hw_stats stats;
+ u16 vf_ifp;
};
/********************************************************************************
diff --git a/freebsd/sys/dev/evdev/cdev.c b/freebsd/sys/dev/evdev/cdev.c
index b08a2440..10f4e77e 100644
--- a/freebsd/sys/dev/evdev/cdev.c
+++ b/freebsd/sys/dev/evdev/cdev.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,24 +31,23 @@
#include <rtems/bsd/local/opt_evdev.h>
-#include <sys/types.h>
-#include <sys/bitstring.h>
-#include <sys/systm.h>
#include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/bitstring.h>
#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/proc.h>
-#include <sys/poll.h>
#include <sys/filio.h>
#include <sys/fcntl.h>
-#include <sys/selinfo.h>
+#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/selinfo.h>
+#include <sys/systm.h>
#include <sys/time.h>
+#include <sys/uio.h>
-#include <dev/evdev/input.h>
#include <dev/evdev/evdev.h>
#include <dev/evdev/evdev_private.h>
+#include <dev/evdev/input.h>
#ifdef EVDEV_DEBUG
#define debugf(client, fmt, args...) printf("evdev cdev: "fmt"\n", ##args)
diff --git a/freebsd/sys/dev/evdev/evdev.c b/freebsd/sys/dev/evdev/evdev.c
index 185e48f7..b3c786a5 100644
--- a/freebsd/sys/dev/evdev/evdev.c
+++ b/freebsd/sys/dev/evdev/evdev.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,19 +31,18 @@
#include <rtems/bsd/local/opt_evdev.h>
-#include <sys/types.h>
-#include <sys/systm.h>
#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
+#include <sys/bitstring.h>
#include <sys/conf.h>
+#include <sys/kernel.h>
#include <sys/malloc.h>
-#include <sys/bitstring.h>
+#include <sys/module.h>
#include <sys/sysctl.h>
+#include <sys/systm.h>
-#include <dev/evdev/input.h>
#include <dev/evdev/evdev.h>
#include <dev/evdev/evdev_private.h>
+#include <dev/evdev/input.h>
#ifdef EVDEV_DEBUG
#define debugf(evdev, fmt, args...) printf("evdev: " fmt "\n", ##args)
@@ -764,14 +763,11 @@ evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
int32_t value)
{
- if (evdev->ev_lock_type != EV_LOCK_INTERNAL)
- EVDEV_LOCK_ASSERT(evdev);
-
if (evdev_check_event(evdev, type, code, value) != 0)
return (EINVAL);
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_LOCK(evdev);
+ EVDEV_ENTER(evdev);
+
evdev_modify_event(evdev, type, code, &value);
if (type == EV_SYN && code == SYN_REPORT &&
bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
@@ -780,8 +776,8 @@ evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
evdev_send_mt_compat(evdev);
evdev_send_event(evdev, type, code, value);
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_UNLOCK(evdev);
+
+ EVDEV_EXIT(evdev);
return (0);
}
diff --git a/freebsd/sys/dev/evdev/evdev_mt.c b/freebsd/sys/dev/evdev/evdev_mt.c
index 6412544b..d0eb48f4 100644
--- a/freebsd/sys/dev/evdev/evdev_mt.c
+++ b/freebsd/sys/dev/evdev/evdev_mt.c
@@ -1,7 +1,7 @@
#include <machine/rtems-bsd-kernel-space.h>
/*-
- * Copyright (c) 2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,14 +29,14 @@
*/
#include <sys/param.h>
-#include <sys/malloc.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/systm.h>
-#include <dev/evdev/input.h>
#include <dev/evdev/evdev.h>
#include <dev/evdev/evdev_private.h>
+#include <dev/evdev/input.h>
#ifdef DEBUG
#define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args)
@@ -226,13 +226,9 @@ void
evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
{
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_LOCK(evdev);
- else
- EVDEV_LOCK_ASSERT(evdev);
+ EVDEV_ENTER(evdev);
evdev_send_nfingers(evdev, nfingers);
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_UNLOCK(evdev);
+ EVDEV_EXIT(evdev);
}
void
@@ -266,13 +262,9 @@ void
evdev_push_mt_compat(struct evdev_dev *evdev)
{
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_LOCK(evdev);
- else
- EVDEV_LOCK_ASSERT(evdev);
+ EVDEV_ENTER(evdev);
evdev_send_mt_compat(evdev);
- if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
- EVDEV_UNLOCK(evdev);
+ EVDEV_EXIT(evdev);
}
void
diff --git a/freebsd/sys/dev/evdev/evdev_private.h b/freebsd/sys/dev/evdev/evdev_private.h
index b3de1bf0..05206a9d 100644
--- a/freebsd/sys/dev/evdev/evdev_private.h
+++ b/freebsd/sys/dev/evdev/evdev_private.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,11 @@
#define _DEV_EVDEV_EVDEV_PRIVATE_H
#include <sys/bitstring.h>
-#include <sys/queue.h>
-#include <sys/malloc.h>
#include <sys/kbio.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
#include <sys/selinfo.h>
+
#include <dev/evdev/evdev.h>
#include <dev/evdev/input.h>
#include <dev/kbd/kbdreg.h>
@@ -134,6 +135,16 @@ struct evdev_dev
#define EVDEV_LOCK(evdev) mtx_lock((evdev)->ev_lock)
#define EVDEV_UNLOCK(evdev) mtx_unlock((evdev)->ev_lock)
#define EVDEV_LOCK_ASSERT(evdev) mtx_assert((evdev)->ev_lock, MA_OWNED)
+#define EVDEV_ENTER(evdev) do { \
+ if ((evdev)->ev_lock_type == EV_LOCK_INTERNAL) \
+ EVDEV_LOCK(evdev); \
+ else \
+ EVDEV_LOCK_ASSERT(evdev); \
+} while (0)
+#define EVDEV_EXIT(evdev) do { \
+ if ((evdev)->ev_lock_type == EV_LOCK_INTERNAL) \
+ EVDEV_UNLOCK(evdev); \
+} while (0)
struct evdev_client
{
diff --git a/freebsd/sys/dev/evdev/evdev_utils.c b/freebsd/sys/dev/evdev/evdev_utils.c
index 49e03b6a..caf81a46 100644
--- a/freebsd/sys/dev/evdev/evdev_utils.c
+++ b/freebsd/sys/dev/evdev/evdev_utils.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,17 +29,16 @@
* $FreeBSD$
*/
-#include <sys/types.h>
-#include <sys/systm.h>
#include <sys/param.h>
#include <sys/bus.h>
-#include <sys/kernel.h>
#include <sys/conf.h>
-#include <sys/malloc.h>
#include <sys/kbio.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
-#include <dev/evdev/input.h>
#include <dev/evdev/evdev.h>
+#include <dev/evdev/input.h>
#include <dev/kbd/kbdreg.h>
diff --git a/freebsd/sys/dev/evdev/input-event-codes.h b/freebsd/sys/dev/evdev/input-event-codes.h
index 78ba7d2e..cc1528f6 100644
--- a/freebsd/sys/dev/evdev/input-event-codes.h
+++ b/freebsd/sys/dev/evdev/input-event-codes.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/freebsd/sys/dev/evdev/input.h b/freebsd/sys/dev/evdev/input.h
index 04638444..7639e0d6 100644
--- a/freebsd/sys/dev/evdev/input.h
+++ b/freebsd/sys/dev/evdev/input.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,8 @@
#define _EVDEV_INPUT_H
#ifndef __KERNEL__
-#include <sys/time.h>
#include <sys/ioccom.h>
+#include <sys/time.h>
#include <sys/types.h>
#endif
diff --git a/freebsd/sys/dev/evdev/uinput.c b/freebsd/sys/dev/evdev/uinput.c
index efebf02a..f1f812cc 100644
--- a/freebsd/sys/dev/evdev/uinput.c
+++ b/freebsd/sys/dev/evdev/uinput.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,25 +31,24 @@
#include <rtems/bsd/local/opt_evdev.h>
-#include <sys/types.h>
-#include <sys/systm.h>
#include <sys/param.h>
+#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/proc.h>
#include <sys/poll.h>
+#include <sys/proc.h>
#include <sys/selinfo.h>
-#include <sys/malloc.h>
-#include <sys/lock.h>
+#include <sys/systm.h>
#include <sys/sx.h>
+#include <sys/uio.h>
-#include <dev/evdev/input.h>
-#include <dev/evdev/uinput.h>
#include <dev/evdev/evdev.h>
#include <dev/evdev/evdev_private.h>
+#include <dev/evdev/input.h>
+#include <dev/evdev/uinput.h>
#ifdef UINPUT_DEBUG
#define debugf(state, fmt, args...) printf("uinput: " fmt "\n", ##args)
diff --git a/freebsd/sys/dev/evdev/uinput.h b/freebsd/sys/dev/evdev/uinput.h
index f1721e19..dd4b0a82 100644
--- a/freebsd/sys/dev/evdev/uinput.h
+++ b/freebsd/sys/dev/evdev/uinput.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
- * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@cicgroup.ru>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/freebsd/sys/dev/ffec/if_ffec.c b/freebsd/sys/dev/ffec/if_ffec.c
index b9a0d668..22b2cdfc 100644
--- a/freebsd/sys/dev/ffec/if_ffec.c
+++ b/freebsd/sys/dev/ffec/if_ffec.c
@@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
+#include <dev/mii/mii_fdt.h>
#include <rtems/bsd/local/miibus_if.h>
/*
@@ -140,7 +141,6 @@ static struct ofw_compat_data compat_data[] = {
#define TX_MAX_DMA_SEGS 8
#define WATCHDOG_TIMEOUT_SECS 5
-#define STATS_HARVEST_INTERVAL 3
#define MAX_IRQ_COUNT 3
@@ -153,13 +153,6 @@ struct ffec_bufmap {
bus_dmamap_t map;
};
-enum {
- PHY_CONN_UNKNOWN,
- PHY_CONN_MII,
- PHY_CONN_RMII,
- PHY_CONN_RGMII
-};
-
struct ffec_softc {
device_t dev;
device_t miibus;
@@ -172,15 +165,14 @@ struct ffec_softc {
struct resource *mem_res;
void * intr_cookie[MAX_IRQ_COUNT];
struct callout ffec_callout;
- uint8_t phy_conn_type;
+ mii_contype_t phy_conn_type;
uintptr_t fectype;
boolean_t link_is_up;
boolean_t is_attached;
boolean_t is_detaching;
int tx_watchdog_count;
- int stats_harvest_count;
- int rxbuf_align;
- int txbuf_align;
+ int rxbuf_align;
+ int txbuf_align;
bus_dma_tag_t rxdesc_tag;
bus_dmamap_t rxdesc_map;
@@ -320,10 +312,10 @@ ffec_miigasket_setup(struct ffec_softc *sc)
switch (sc->phy_conn_type)
{
- case PHY_CONN_MII:
+ case MII_CONTYPE_MII:
ifmode = 0;
break;
- case PHY_CONN_RMII:
+ case MII_CONTYPE_RMII:
ifmode = FEC_MIIGSK_CFGR_IF_MODE_RMII;
break;
default:
@@ -435,14 +427,17 @@ ffec_miibus_statchg(device_t dev)
rcr |= FEC_RCR_MII_MODE; /* Must always be on even for R[G]MII. */
switch (sc->phy_conn_type) {
- case PHY_CONN_MII:
- break;
- case PHY_CONN_RMII:
+ case MII_CONTYPE_RMII:
rcr |= FEC_RCR_RMII_MODE;
break;
- case PHY_CONN_RGMII:
+ case MII_CONTYPE_RGMII:
+ case MII_CONTYPE_RGMII_ID:
+ case MII_CONTYPE_RGMII_RXID:
+ case MII_CONTYPE_RGMII_TXID:
rcr |= FEC_RCR_RGMII_EN;
break;
+ default:
+ break;
}
switch (IFM_SUBTYPE(mii->mii_media_active)) {
@@ -518,22 +513,41 @@ ffec_media_change(struct ifnet * ifp)
static void ffec_clear_stats(struct ffec_softc *sc)
{
+ uint32_t mibc;
- WR4(sc, FEC_RMON_R_PACKETS, 0);
- WR4(sc, FEC_RMON_R_MC_PKT, 0);
- WR4(sc, FEC_RMON_R_CRC_ALIGN, 0);
- WR4(sc, FEC_RMON_R_UNDERSIZE, 0);
- WR4(sc, FEC_RMON_R_OVERSIZE, 0);
- WR4(sc, FEC_RMON_R_FRAG, 0);
- WR4(sc, FEC_RMON_R_JAB, 0);
- WR4(sc, FEC_RMON_T_PACKETS, 0);
- WR4(sc, FEC_RMON_T_MC_PKT, 0);
- WR4(sc, FEC_RMON_T_CRC_ALIGN, 0);
- WR4(sc, FEC_RMON_T_UNDERSIZE, 0);
- WR4(sc, FEC_RMON_T_OVERSIZE , 0);
- WR4(sc, FEC_RMON_T_FRAG, 0);
- WR4(sc, FEC_RMON_T_JAB, 0);
- WR4(sc, FEC_RMON_T_COL, 0);
+ mibc = RD4(sc, FEC_MIBC_REG);
+
+ /*
+ * On newer hardware the statistic regs are cleared by toggling a bit in
+ * the mib control register. On older hardware the clear procedure is
+ * to disable statistics collection, zero the regs, then re-enable.
+ */
+ if (sc->fectype == FECTYPE_IMX6 || sc->fectype == FECTYPE_MVF) {
+ WR4(sc, FEC_MIBC_REG, mibc | FEC_MIBC_CLEAR);
+ WR4(sc, FEC_MIBC_REG, mibc & ~FEC_MIBC_CLEAR);
+ } else {
+ WR4(sc, FEC_MIBC_REG, mibc | FEC_MIBC_DIS);
+
+ WR4(sc, FEC_IEEE_R_DROP, 0);
+ WR4(sc, FEC_IEEE_R_MACERR, 0);
+ WR4(sc, FEC_RMON_R_CRC_ALIGN, 0);
+ WR4(sc, FEC_RMON_R_FRAG, 0);
+ WR4(sc, FEC_RMON_R_JAB, 0);
+ WR4(sc, FEC_RMON_R_MC_PKT, 0);
+ WR4(sc, FEC_RMON_R_OVERSIZE, 0);
+ WR4(sc, FEC_RMON_R_PACKETS, 0);
+ WR4(sc, FEC_RMON_R_UNDERSIZE, 0);
+ WR4(sc, FEC_RMON_T_COL, 0);
+ WR4(sc, FEC_RMON_T_CRC_ALIGN, 0);
+ WR4(sc, FEC_RMON_T_FRAG, 0);
+ WR4(sc, FEC_RMON_T_JAB, 0);
+ WR4(sc, FEC_RMON_T_MC_PKT, 0);
+ WR4(sc, FEC_RMON_T_OVERSIZE , 0);
+ WR4(sc, FEC_RMON_T_PACKETS, 0);
+ WR4(sc, FEC_RMON_T_UNDERSIZE, 0);
+
+ WR4(sc, FEC_MIBC_REG, mibc);
+ }
}
static void
@@ -541,28 +555,21 @@ ffec_harvest_stats(struct ffec_softc *sc)
{
struct ifnet *ifp;
- /* We don't need to harvest too often. */
- if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL)
- return;
+ ifp = sc->ifp;
/*
- * Try to avoid harvesting unless the IDLE flag is on, but if it has
- * been too long just go ahead and do it anyway, the worst that'll
- * happen is we'll lose a packet count or two as we clear at the end.
+ * - FEC_IEEE_R_DROP is "dropped due to invalid start frame delimiter"
+ * so it's really just another type of input error.
+ * - FEC_IEEE_R_MACERR is "no receive fifo space"; count as input drops.
*/
- if (sc->stats_harvest_count < (2 * STATS_HARVEST_INTERVAL) &&
- ((RD4(sc, FEC_MIBC_REG) & FEC_MIBC_IDLE) == 0))
- return;
-
- sc->stats_harvest_count = 0;
- ifp = sc->ifp;
-
if_inc_counter(ifp, IFCOUNTER_IPACKETS, RD4(sc, FEC_RMON_R_PACKETS));
if_inc_counter(ifp, IFCOUNTER_IMCASTS, RD4(sc, FEC_RMON_R_MC_PKT));
if_inc_counter(ifp, IFCOUNTER_IERRORS,
RD4(sc, FEC_RMON_R_CRC_ALIGN) + RD4(sc, FEC_RMON_R_UNDERSIZE) +
RD4(sc, FEC_RMON_R_OVERSIZE) + RD4(sc, FEC_RMON_R_FRAG) +
- RD4(sc, FEC_RMON_R_JAB));
+ RD4(sc, FEC_RMON_R_JAB) + RD4(sc, FEC_IEEE_R_DROP));
+
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, RD4(sc, FEC_IEEE_R_MACERR));
if_inc_counter(ifp, IFCOUNTER_OPACKETS, RD4(sc, FEC_RMON_T_PACKETS));
if_inc_counter(ifp, IFCOUNTER_OMCASTS, RD4(sc, FEC_RMON_T_MC_PKT));
@@ -1132,7 +1139,6 @@ ffec_stop_locked(struct ffec_softc *sc)
ifp = sc->ifp;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
sc->tx_watchdog_count = 0;
- sc->stats_harvest_count = 0;
/*
* Stop the hardware, mask all interrupts, and clear all current
@@ -1311,7 +1317,8 @@ ffec_init_locked(struct ffec_softc *sc)
WR4(sc, FEC_IEM_REG, FEC_IER_TXF | FEC_IER_RXF | FEC_IER_EBERR);
/*
- * MIBC - MIB control (hardware stats).
+ * MIBC - MIB control (hardware stats); clear all statistics regs, then
+ * enable collection of statistics.
*/
regval = RD4(sc, FEC_MIBC_REG);
WR4(sc, FEC_MIBC_REG, regval | FEC_MIBC_DIS);
@@ -1708,7 +1715,6 @@ ffec_attach(device_t dev)
phandle_t ofw_node;
int error, phynum, rid, irq;
uint8_t eaddr[ETHER_ADDR_LEN];
- char phy_conn_name[32];
uint32_t idx, mscr;
sc = device_get_softc(dev);
@@ -1739,20 +1745,8 @@ ffec_attach(device_t dev)
error = ENXIO;
goto out;
}
- if (OF_searchprop(ofw_node, "phy-mode",
- phy_conn_name, sizeof(phy_conn_name)) != -1) {
- if (strcasecmp(phy_conn_name, "mii") == 0)
- sc->phy_conn_type = PHY_CONN_MII;
- else if (strcasecmp(phy_conn_name, "rmii") == 0)
- sc->phy_conn_type = PHY_CONN_RMII;
-#ifndef __rtems__
- else if (strcasecmp(phy_conn_name, "rgmii") == 0)
-#else /* __rtems__ */
- else if (strncasecmp(phy_conn_name, "rgmii", 5) == 0)
-#endif /* __rtems__ */
- sc->phy_conn_type = PHY_CONN_RGMII;
- }
- if (sc->phy_conn_type == PHY_CONN_UNKNOWN) {
+ sc->phy_conn_type = mii_fdt_get_contype(ofw_node);
+ if (sc->phy_conn_type == MII_CONTYPE_UNKNOWN) {
device_printf(sc->dev, "No valid 'phy-mode' "
"property found in FDT data for device.\n");
#ifndef __rtems__
diff --git a/freebsd/sys/dev/mii/mii_fdt.c b/freebsd/sys/dev/mii/mii_fdt.c
new file mode 100644
index 00000000..de994ff9
--- /dev/null
+++ b/freebsd/sys/dev/mii/mii_fdt.c
@@ -0,0 +1,202 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2017 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Development sponsored by Microsemi, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Utility functions for PHY drivers on systems configured using FDT data.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/mii_fdt.h>
+
+/*
+ * Table to translate MII_CONTYPE_xxxx constants to/from devicetree strings.
+ * We explicitly associate the enum values with the strings in a table to avoid
+ * relying on this list being sorted in the same order as the enum in miivar.h,
+ * and to avoid problems if the enum gains new types that aren't in the FDT
+ * data. However, the "unknown" entry must be first because it is referenced
+ * using subscript 0 in mii_fdt_contype_to_name().
+ */
+static struct contype_names {
+ mii_contype_t type;
+ const char *name;
+} fdt_contype_names[] = {
+ {MII_CONTYPE_UNKNOWN, "unknown"},
+ {MII_CONTYPE_MII, "mii"},
+ {MII_CONTYPE_GMII, "gmii"},
+ {MII_CONTYPE_SGMII, "sgmii"},
+ {MII_CONTYPE_QSGMII, "qsgmii"},
+ {MII_CONTYPE_TBI, "tbi"},
+ {MII_CONTYPE_REVMII, "rev-mii"},
+ {MII_CONTYPE_RMII, "rmii"},
+ {MII_CONTYPE_RGMII, "rgmii"},
+ {MII_CONTYPE_RGMII_ID, "rgmii-id"},
+ {MII_CONTYPE_RGMII_RXID, "rgmii-rxid"},
+ {MII_CONTYPE_RGMII_TXID, "rgmii-txid"},
+ {MII_CONTYPE_RTBI, "rtbi"},
+ {MII_CONTYPE_SMII, "smii"},
+ {MII_CONTYPE_XGMII, "xgmii"},
+ {MII_CONTYPE_TRGMII, "trgmii"},
+ {MII_CONTYPE_2000BX, "2000base-x"},
+ {MII_CONTYPE_2500BX, "2500base-x"},
+ {MII_CONTYPE_RXAUI, "rxaui"},
+};
+
+static phandle_t
+mii_fdt_get_phynode(phandle_t macnode)
+{
+ static const char *props[] = {
+ "phy-handle", "phy", "phy-device"
+ };
+ pcell_t xref;
+ u_int i;
+
+ for (i = 0; i < nitems(props); ++i) {
+ if (OF_getencprop(macnode, props[i], &xref, sizeof(xref)) > 0)
+ return (OF_node_from_xref(xref));
+ }
+ return (-1);
+}
+
+mii_contype_t
+mii_fdt_contype_from_name(const char *name)
+{
+ u_int i;
+
+ for (i = 0; i < nitems(fdt_contype_names); ++i) {
+ if (strcmp(name, fdt_contype_names[i].name) == 0)
+ return (fdt_contype_names[i].type);
+ }
+ return (MII_CONTYPE_UNKNOWN);
+}
+
+const char *
+mii_fdt_contype_to_name(mii_contype_t contype)
+{
+ u_int i;
+
+ for (i = 0; i < nitems(fdt_contype_names); ++i) {
+ if (contype == fdt_contype_names[i].type)
+ return (fdt_contype_names[i].name);
+ }
+ return (fdt_contype_names[0].name);
+}
+
+mii_contype_t
+mii_fdt_get_contype(phandle_t macnode)
+{
+ char val[32];
+
+ if (OF_getprop(macnode, "phy-mode", val, sizeof(val)) <= 0 &&
+ OF_getprop(macnode, "phy-connection-type", val, sizeof(val)) <= 0) {
+ return (MII_CONTYPE_UNKNOWN);
+ }
+ return (mii_fdt_contype_from_name(val));
+}
+
+void
+mii_fdt_free_config(struct mii_fdt_phy_config *cfg)
+{
+
+ free(cfg, M_OFWPROP);
+}
+
+mii_fdt_phy_config_t *
+mii_fdt_get_config(device_t phydev)
+{
+ mii_fdt_phy_config_t *cfg;
+ device_t miibus, macdev;
+ pcell_t val;
+
+ miibus = device_get_parent(phydev);
+ macdev = device_get_parent(miibus);
+
+ cfg = malloc(sizeof(*cfg), M_OFWPROP, M_ZERO | M_WAITOK);
+
+ /*
+ * If we can't find our parent MAC's node, there's nothing more we can
+ * fill in; cfg is already full of zero/default values, return it.
+ */
+ if ((cfg->macnode = ofw_bus_get_node(macdev)) == -1)
+ return (cfg);
+
+ cfg->con_type = mii_fdt_get_contype(cfg->macnode);
+
+ /*
+ * If we can't find our own PHY node, there's nothing more we can fill
+ * in, just return what we've got.
+ */
+ if ((cfg->phynode = mii_fdt_get_phynode(cfg->macnode)) == -1)
+ return (cfg);
+
+ if (OF_getencprop(cfg->phynode, "max-speed", &val, sizeof(val)) > 0)
+ cfg->max_speed = val;
+
+ if (ofw_bus_node_is_compatible(cfg->phynode,
+ "ethernet-phy-ieee802.3-c45"))
+ cfg->flags |= MIIF_FDT_COMPAT_CLAUSE45;
+
+ if (OF_hasprop(cfg->phynode, "broken-turn-around"))
+ cfg->flags |= MIIF_FDT_BROKEN_TURNAROUND;
+ if (OF_hasprop(cfg->phynode, "enet-phy-lane-swap"))
+ cfg->flags |= MIIF_FDT_LANE_SWAP;
+ if (OF_hasprop(cfg->phynode, "enet-phy-lane-no-swap"))
+ cfg->flags |= MIIF_FDT_NO_LANE_SWAP;
+ if (OF_hasprop(cfg->phynode, "eee-broken-100tx"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_100TX;
+ if (OF_hasprop(cfg->phynode, "eee-broken-1000t"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_1000T;
+ if (OF_hasprop(cfg->phynode, "eee-broken-10gt"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_10GT;
+ if (OF_hasprop(cfg->phynode, "eee-broken-1000kx"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_1000KX;
+ if (OF_hasprop(cfg->phynode, "eee-broken-10gkx4"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKX4;
+ if (OF_hasprop(cfg->phynode, "eee-broken-10gkr"))
+ cfg->flags |= MIIF_FDT_EEE_BROKEN_10GKR;
+
+ return (cfg);
+}
diff --git a/freebsd/sys/dev/mii/mii_fdt.h b/freebsd/sys/dev/mii/mii_fdt.h
new file mode 100644
index 00000000..7b0b5131
--- /dev/null
+++ b/freebsd/sys/dev/mii/mii_fdt.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2017 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Development sponsored by Microsemi, Inc.
+ *
+ * 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$
+ */
+
+#ifndef _DEV_MII_FDT_H_
+#define _DEV_MII_FDT_H_
+
+/*
+ * Common FDT config for a PHY, as documented in the devicetree bindings
+ * documents ethernet.txt and phy.txt. Boolean properties are represented as
+ * bits in the flags member.
+ */
+struct mii_fdt_phy_config {
+ phandle_t macnode; /* Node (not xref) of parent MAC */
+ phandle_t phynode; /* Node (not xref) of PHY */
+ mii_contype_t con_type; /* MAC<->PHY connection type */
+ u_int max_speed; /* Mbits/sec, 0 = not specified */
+ uint32_t flags; /* MIIF_FDT_xxx boolean properties */
+};
+typedef struct mii_fdt_phy_config mii_fdt_phy_config_t;
+
+/* PHY config flags. */
+#define MIIF_FDT_COMPAT_CLAUSE45 0x0001
+#define MIIF_FDT_BROKEN_TURNAROUND 0x0002
+#define MIIF_FDT_LANE_SWAP 0x0004
+#define MIIF_FDT_NO_LANE_SWAP 0x0008
+#define MIIF_FDT_EEE_BROKEN_100TX 0x0010
+#define MIIF_FDT_EEE_BROKEN_1000T 0x0020
+#define MIIF_FDT_EEE_BROKEN_10GT 0x0040
+#define MIIF_FDT_EEE_BROKEN_1000KX 0x0080
+#define MIIF_FDT_EEE_BROKEN_10GKX4 0x0100
+#define MIIF_FDT_EEE_BROKEN_10GKR 0x0200
+
+/*
+ * Convert between mii_contype enums and devicetree property strings.
+ */
+const char *mii_fdt_contype_to_name(mii_contype_t contype);
+mii_contype_t mii_fdt_contype_from_name(const char *name);
+
+/* Get the connection type from the given MAC node. */
+mii_contype_t mii_fdt_get_contype(phandle_t macnode);
+
+/*
+ * Get/free the config for the given PHY device.
+ */
+void mii_fdt_free_config(struct mii_fdt_phy_config *cfg);
+mii_fdt_phy_config_t *mii_fdt_get_config(device_t phydev);
+
+#endif
diff --git a/freebsd/sys/dev/mii/miivar.h b/freebsd/sys/dev/mii/miivar.h
index 498e7204..ef81bdb2 100644
--- a/freebsd/sys/dev/mii/miivar.h
+++ b/freebsd/sys/dev/mii/miivar.h
@@ -156,6 +156,42 @@ typedef struct mii_softc mii_softc_t;
#define MII_PHY_ANY -1
/*
+ * Constants used to describe the type of attachment between MAC and PHY.
+ */
+enum mii_contype {
+ MII_CONTYPE_UNKNOWN, /* Must be have value 0. */
+
+ MII_CONTYPE_MII,
+ MII_CONTYPE_GMII,
+ MII_CONTYPE_SGMII,
+ MII_CONTYPE_QSGMII,
+ MII_CONTYPE_TBI,
+ MII_CONTYPE_REVMII, /* Reverse MII */
+ MII_CONTYPE_RMII,
+ MII_CONTYPE_RGMII, /* Delays provided by MAC or PCB */
+ MII_CONTYPE_RGMII_ID, /* Rx and tx delays provided by PHY */
+ MII_CONTYPE_RGMII_RXID, /* Only rx delay provided by PHY */
+ MII_CONTYPE_RGMII_TXID, /* Only tx delay provided by PHY */
+ MII_CONTYPE_RTBI,
+ MII_CONTYPE_SMII,
+ MII_CONTYPE_XGMII,
+ MII_CONTYPE_TRGMII,
+ MII_CONTYPE_2000BX,
+ MII_CONTYPE_2500BX,
+ MII_CONTYPE_RXAUI,
+
+ MII_CONTYPE_COUNT /* Add new types before this line. */
+};
+typedef enum mii_contype mii_contype_t;
+
+static inline bool
+mii_contype_is_rgmii(mii_contype_t con)
+{
+
+ return (con >= MII_CONTYPE_RGMII && con <= MII_CONTYPE_RGMII_TXID);
+}
+
+/*
* Used to attach a PHY to a parent.
*/
struct mii_attach_args {
diff --git a/freebsd/sys/dev/mmc/bridge.h b/freebsd/sys/dev/mmc/bridge.h
index a780ffae..53e61b48 100644
--- a/freebsd/sys/dev/mmc/bridge.h
+++ b/freebsd/sys/dev/mmc/bridge.h
@@ -137,6 +137,10 @@ enum mmc_card_mode {
mode_mmc, mode_sd
};
+enum mmc_retune_req {
+ retune_req_none = 0, retune_req_normal, retune_req_reset
+};
+
struct mmc_host {
int f_min;
int f_max;
@@ -174,15 +178,17 @@ struct mmc_host {
struct mmc_ios ios; /* Current state of the host */
};
+#ifdef _KERNEL
extern driver_t mmc_driver;
extern devclass_t mmc_devclass;
-#define MMC_VERSION 3
+#define MMC_VERSION 4
#define MMC_DECLARE_BRIDGE(name) \
DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL); \
MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION);
#define MMC_DEPEND(name) \
MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION);
+#endif /* _KERNEL */
#endif /* DEV_MMC_BRIDGE_H */
diff --git a/freebsd/sys/dev/mmc/mmc.c b/freebsd/sys/dev/mmc/mmc.c
index 023091eb..74e26332 100644
--- a/freebsd/sys/dev/mmc/mmc.c
+++ b/freebsd/sys/dev/mmc/mmc.c
@@ -90,14 +90,14 @@ struct mmc_ivars {
uint8_t raw_ext_csd[MMC_EXTCSD_SIZE]; /* Raw bits of the EXT_CSD */
uint32_t raw_sd_status[16]; /* Raw bits of the SD_STATUS */
uint16_t rca;
+ u_char read_only; /* True when the device is read-only */
+ u_char high_cap; /* High Capacity device (block addressed) */
enum mmc_card_mode mode;
+ enum mmc_bus_width bus_width; /* Bus width to use */
struct mmc_cid cid; /* cid decoded */
struct mmc_csd csd; /* csd decoded */
struct mmc_scr scr; /* scr decoded */
struct mmc_sd_status sd_status; /* SD_STATUS decoded */
- u_char read_only; /* True when the device is read-only */
- u_char bus_width; /* Bus width to use */
- u_char high_cap; /* High Capacity card (block addressed) */
uint32_t sec_count; /* Card capacity in 512byte blocks */
uint32_t timings; /* Mask of bus timings supported */
uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */
@@ -129,8 +129,10 @@ static int mmc_read_ivar(device_t bus, device_t child, int which,
uintptr_t *result);
static int mmc_release_bus(device_t busdev, device_t dev);
static int mmc_resume(device_t dev);
+static void mmc_retune_pause(device_t busdev, device_t dev, bool retune);
+static void mmc_retune_unpause(device_t busdev, device_t dev);
static int mmc_suspend(device_t dev);
-static int mmc_wait_for_request(device_t brdev, device_t reqdev,
+static int mmc_wait_for_request(device_t busdev, device_t dev,
struct mmc_request *req);
static int mmc_write_ivar(device_t bus, device_t child, int which,
uintptr_t value);
@@ -157,21 +159,23 @@ static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid,
bool is_4_41p);
static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid);
static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd);
-static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd);
+static int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd);
static void mmc_delayed_attach(void *xsc);
-static int mmc_delete_cards(struct mmc_softc *sc);
+static int mmc_delete_cards(struct mmc_softc *sc, bool final);
static void mmc_discover_cards(struct mmc_softc *sc);
static void mmc_format_card_id_string(struct mmc_ivars *ivar);
static void mmc_go_discovery(struct mmc_softc *sc);
static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start,
int size);
static int mmc_highest_voltage(uint32_t ocr);
+static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing);
static void mmc_idle_cards(struct mmc_softc *sc);
static void mmc_ms_delay(int ms);
static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard);
static void mmc_power_down(struct mmc_softc *sc);
static void mmc_power_up(struct mmc_softc *sc);
static void mmc_rescan_cards(struct mmc_softc *sc);
+static int mmc_retune(device_t busdev, device_t dev, bool reset);
static void mmc_scan(struct mmc_softc *sc);
static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp,
uint8_t value, uint8_t *res);
@@ -185,15 +189,23 @@ static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr,
uint32_t *rocr);
static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp);
static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len);
-static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar);
+static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing);
static int mmc_set_power_class(struct mmc_softc *sc, struct mmc_ivars *ivar);
static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp);
static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
enum mmc_bus_timing timing);
+static int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing);
+static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock);
+static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t max_dtr, enum mmc_bus_timing max_timing);
static int mmc_test_bus_width(struct mmc_softc *sc);
static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar,
enum mmc_bus_timing timing);
static const char *mmc_timing_to_string(enum mmc_bus_timing timing);
+static void mmc_update_child_list(struct mmc_softc *sc);
static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
uint32_t arg, uint32_t flags, uint32_t *resp, int retries);
static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req);
@@ -237,7 +249,8 @@ mmc_detach(device_t dev)
struct mmc_softc *sc = device_get_softc(dev);
int err;
- if ((err = mmc_delete_cards(sc)) != 0)
+ err = mmc_delete_cards(sc, true);
+ if (err != 0)
return (err);
mmc_power_down(sc);
MMC_LOCK_DESTROY(sc);
@@ -252,10 +265,21 @@ mmc_suspend(device_t dev)
int err;
err = bus_generic_suspend(dev);
- if (err)
+ if (err != 0)
+ return (err);
+ /*
+ * We power down with the bus acquired here, mainly so that no device
+ * is selected any longer and sc->last_rca gets set to 0. Otherwise,
+ * the deselect as part of the bus acquisition in mmc_scan() may fail
+ * during resume, as the bus isn't powered up again before later in
+ * mmc_go_discovery().
+ */
+ err = mmc_acquire_bus(dev, dev);
+ if (err != 0)
return (err);
mmc_power_down(sc);
- return (0);
+ err = mmc_release_bus(dev, dev);
+ return (err);
}
static int
@@ -272,7 +296,8 @@ mmc_acquire_bus(device_t busdev, device_t dev)
{
struct mmc_softc *sc;
struct mmc_ivars *ivar;
- int err, rca;
+ int err;
+ uint16_t rca;
enum mmc_bus_timing timing;
err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev);
@@ -296,12 +321,27 @@ mmc_acquire_bus(device_t busdev, device_t dev)
rca = ivar->rca;
if (sc->last_rca != rca) {
if (mmc_select_card(sc, rca) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to select.\n", rca);
+ device_printf(busdev, "Card at relative "
+ "address %d failed to select\n", rca);
return (ENXIO);
}
sc->last_rca = rca;
timing = mmcbr_get_timing(busdev);
+ /*
+ * For eMMC modes, setting/updating bus width and VCCQ
+ * only really is necessary if there actually is more
+ * than one device on the bus as generally that already
+ * had to be done by mmc_calculate_clock() or one of
+ * its calees. Moreover, setting the bus width anew
+ * can trigger re-tuning (via a CRC error on the next
+ * CMD), even if not switching between devices an the
+ * previously selected one is still tuned. Obviously,
+ * we need to re-tune the host controller if devices
+ * are actually switched, though.
+ */
+ if (timing >= bus_timing_mmc_ddr52 &&
+ sc->child_count == 1)
+ return (0);
/* Prepare bus width for the new card. */
if (bootverbose || mmc_debug) {
device_printf(busdev,
@@ -310,38 +350,34 @@ mmc_acquire_bus(device_t busdev, device_t dev)
(ivar->bus_width == bus_width_8) ? 8 : 1,
mmc_timing_to_string(timing));
}
- if (mmc_set_card_bus_width(sc, ivar) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to set bus width.\n",
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(busdev, "Card at relative "
+ "address %d failed to set bus width\n",
rca);
return (ENXIO);
}
- if (isset(&ivar->vccq_120, timing))
- mmcbr_set_vccq(busdev, vccq_120);
- else if (isset(&ivar->vccq_180, timing))
- mmcbr_set_vccq(busdev, vccq_180);
- else
- mmcbr_set_vccq(busdev, vccq_330);
- if (mmcbr_switch_vccq(busdev) != 0) {
- device_printf(sc->dev, "Failed to set VCCQ "
- "for card at relative address %d.\n", rca);
+ mmcbr_set_bus_width(busdev, ivar->bus_width);
+ mmcbr_update_ios(busdev);
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(busdev, "Failed to set VCCQ "
+ "for card at relative address %d\n", rca);
return (ENXIO);
}
- if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to set power class.\n",
- rca);
+ if (timing >= bus_timing_mmc_hs200 &&
+ mmc_retune(busdev, dev, true) != 0) {
+ device_printf(busdev, "Card at relative "
+ "address %d failed to re-tune\n", rca);
return (ENXIO);
}
- mmcbr_set_bus_width(busdev, ivar->bus_width);
- mmcbr_update_ios(busdev);
}
} else {
/*
* If there's a card selected, stand down.
*/
if (sc->last_rca != 0) {
- mmc_select_card(sc, 0);
+ if (mmc_select_card(sc, 0) != MMC_ERR_NONE)
+ return (ENXIO);
sc->last_rca = 0;
}
}
@@ -416,7 +452,7 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
#endif /* __rtems__ */
req->done = mmc_wakeup;
req->done_data = sc;
- if (mmc_debug > 1) {
+ if (__predict_false(mmc_debug > 1)) {
device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags %#x",
req->cmd->opcode, req->cmd->arg, req->cmd->flags);
if (req->cmd->data) {
@@ -434,18 +470,66 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
rtems_binary_semaphore_wait(&req->req_done);
rtems_binary_semaphore_destroy(&req->req_done);
#endif /* __rtems__ */
- if (mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE))
+ if (__predict_false(mmc_debug > 2 || (mmc_debug > 0 &&
+ req->cmd->error != MMC_ERR_NONE)))
device_printf(sc->dev, "CMD%d RESULT: %d\n",
req->cmd->opcode, req->cmd->error);
return (0);
}
static int
-mmc_wait_for_request(device_t brdev, device_t reqdev __unused,
- struct mmc_request *req)
+mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req)
{
- struct mmc_softc *sc = device_get_softc(brdev);
+ struct mmc_softc *sc;
+ struct mmc_ivars *ivar;
+ int err, i;
+ enum mmc_retune_req retune_req;
+
+ sc = device_get_softc(busdev);
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+ /*
+ * Unless no device is selected or re-tuning is already ongoing,
+ * execute re-tuning if a) the bridge is requesting to do so and
+ * re-tuning hasn't been otherwise paused, or b) if a child asked
+ * to be re-tuned prior to pausing (see also mmc_retune_pause()).
+ */
+ if (__predict_false(sc->last_rca != 0 && sc->retune_ongoing == 0 &&
+ (((retune_req = mmcbr_get_retune_req(busdev)) != retune_req_none &&
+ sc->retune_paused == 0) || sc->retune_needed == 1))) {
+ if (__predict_false(mmc_debug > 1)) {
+ device_printf(busdev,
+ "Re-tuning with%s circuit reset required\n",
+ retune_req == retune_req_reset ? "" : "out");
+ }
+ if (device_get_parent(dev) == busdev)
+ ivar = device_get_ivars(dev);
+ else {
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
+ if (ivar->rca == sc->last_rca)
+ break;
+ }
+ if (ivar->rca != sc->last_rca)
+ return (EINVAL);
+ }
+ sc->retune_ongoing = 1;
+ err = mmc_retune(busdev, dev, retune_req == retune_req_reset);
+ sc->retune_ongoing = 0;
+ switch (err) {
+ case MMC_ERR_NONE:
+ case MMC_ERR_FAILED: /* Re-tune error but still might work */
+ break;
+ case MMC_ERR_BADCRC: /* Switch failure on HS400 recovery */
+ return (ENXIO);
+ case MMC_ERR_INVALID: /* Driver implementation b0rken */
+ default: /* Unknown error, should not happen */
+ return (EINVAL);
+ }
+ sc->retune_needed = 0;
+ }
return (mmc_wait_for_req(sc, req));
}
@@ -613,11 +697,14 @@ mmc_power_down(struct mmc_softc *sc)
static int
mmc_select_card(struct mmc_softc *sc, uint16_t rca)
{
- int flags;
+ int err, flags;
flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC;
- return (mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16,
- flags, NULL, CMD_RETRIES));
+ sc->retune_paused++;
+ err = mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16,
+ flags, NULL, CMD_RETRIES);
+ sc->retune_paused--;
+ return (err);
}
static int
@@ -649,7 +736,8 @@ mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value,
}
static int
-mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
+mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing)
{
struct mmc_command cmd;
int err;
@@ -682,28 +770,33 @@ mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
} else {
switch (ivar->bus_width) {
case bus_width_1:
+ if (timing == bus_timing_mmc_hs400 ||
+ timing == bus_timing_mmc_hs400es)
+ return (MMC_ERR_INVALID);
value = EXT_CSD_BUS_WIDTH_1;
break;
case bus_width_4:
- switch (mmcbr_get_timing(sc->dev)) {
+ switch (timing) {
case bus_timing_mmc_ddr52:
- case bus_timing_mmc_hs200:
- case bus_timing_mmc_hs400:
- case bus_timing_mmc_hs400es:
value = EXT_CSD_BUS_WIDTH_4_DDR;
break;
+ case bus_timing_mmc_hs400:
+ case bus_timing_mmc_hs400es:
+ return (MMC_ERR_INVALID);
default:
value = EXT_CSD_BUS_WIDTH_4;
break;
}
break;
case bus_width_8:
- switch (mmcbr_get_timing(sc->dev)) {
+ value = 0;
+ switch (timing) {
+ case bus_timing_mmc_hs400es:
+ value = EXT_CSD_BUS_WIDTH_ES;
+ /* FALLTHROUGH */
case bus_timing_mmc_ddr52:
- case bus_timing_mmc_hs200:
case bus_timing_mmc_hs400:
- case bus_timing_mmc_hs400es:
- value = EXT_CSD_BUS_WIDTH_8_DDR;
+ value |= EXT_CSD_BUS_WIDTH_8_DDR;
break;
default:
value = EXT_CSD_BUS_WIDTH_8;
@@ -828,6 +921,13 @@ mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
case bus_timing_mmc_ddr52:
value = EXT_CSD_HS_TIMING_HS;
break;
+ case bus_timing_mmc_hs200:
+ value = EXT_CSD_HS_TIMING_HS200;
+ break;
+ case bus_timing_mmc_hs400:
+ case bus_timing_mmc_hs400es:
+ value = EXT_CSD_HS_TIMING_HS400;
+ break;
default:
return (MMC_ERR_INVALID);
}
@@ -844,6 +944,23 @@ mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
return (err);
}
+static int
+mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing)
+{
+
+ if (isset(&ivar->vccq_120, timing))
+ mmcbr_set_vccq(sc->dev, vccq_120);
+ else if (isset(&ivar->vccq_180, timing))
+ mmcbr_set_vccq(sc->dev, vccq_180);
+ else
+ mmcbr_set_vccq(sc->dev, vccq_330);
+ if (mmcbr_switch_vccq(sc->dev) != 0)
+ return (MMC_ERR_INVALID);
+ else
+ return (MMC_ERR_NONE);
+}
+
static const uint8_t p8[8] = {
0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1051,7 +1168,7 @@ static const int cur_max[8] = {
1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000
};
-static void
+static int
mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
{
int v;
@@ -1092,6 +1209,7 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
+ return (MMC_ERR_NONE);
} else if (v == 1) {
m = mmc_get_bits(raw_csd, 128, 115, 4);
e = mmc_get_bits(raw_csd, 128, 112, 3);
@@ -1115,8 +1233,9 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
- } else
- panic("unknown SD CSD version");
+ return (MMC_ERR_NONE);
+ }
+ return (MMC_ERR_INVALID);
}
static void
@@ -1380,6 +1499,53 @@ mmc_timing_to_string(enum mmc_bus_timing timing)
return ("");
}
+static bool
+mmc_host_timing(device_t dev, enum mmc_bus_timing timing)
+{
+ int host_caps;
+
+ host_caps = mmcbr_get_caps(dev);
+
+#define HOST_TIMING_CAP(host_caps, cap) ({ \
+ bool retval; \
+ if (((host_caps) & (cap)) == (cap)) \
+ retval = true; \
+ else \
+ retval = false; \
+ retval; \
+})
+
+ switch (timing) {
+ case bus_timing_normal:
+ return (true);
+ case bus_timing_hs:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_HSPEED));
+ case bus_timing_uhs_sdr12:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR12));
+ case bus_timing_uhs_sdr25:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR25));
+ case bus_timing_uhs_ddr50:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_DDR50));
+ case bus_timing_uhs_sdr50:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR50));
+ case bus_timing_uhs_sdr104:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR104));
+ case bus_timing_mmc_ddr52:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_DDR52));
+ case bus_timing_mmc_hs200:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200));
+ case bus_timing_mmc_hs400:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400));
+ case bus_timing_mmc_hs400es:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 |
+ MMC_CAP_MMC_ENH_STROBE));
+ }
+
+#undef HOST_TIMING_CAP
+
+ return (false);
+}
+
static void
mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard)
{
@@ -1411,9 +1577,8 @@ mmc_discover_cards(struct mmc_softc *sc)
u_char switch_res[64];
uint32_t raw_cid[4];
struct mmc_ivars *ivar = NULL;
- device_t *devlist;
device_t child;
- int devcount, err, host_caps, i, newcard;
+ int err, host_caps, i, newcard;
uint32_t resp, sec_count, status;
uint16_t rca = 2;
@@ -1421,6 +1586,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (bootverbose || mmc_debug)
device_printf(sc->dev, "Probing cards\n");
while (1) {
+ child = NULL;
sc->squelched++; /* Errors are expected, squelch reporting. */
err = mmc_all_send_cid(sc, raw_cid);
sc->squelched--;
@@ -1431,18 +1597,14 @@ mmc_discover_cards(struct mmc_softc *sc)
break;
}
newcard = 1;
- if ((err = device_get_children(sc->dev, &devlist,
- &devcount)) != 0)
- return;
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) ==
0) {
newcard = 0;
break;
}
}
- free(devlist, M_TEMP);
if (bootverbose || mmc_debug) {
device_printf(sc->dev,
"%sard detected (CID %08x%08x%08x%08x)\n",
@@ -1465,7 +1627,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error getting RCA %d\n", err);
- break;
+ goto free_ivar;
}
ivar->rca = resp >> 16;
/* Get card CSD. */
@@ -1473,7 +1635,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error getting CSD %d\n", err);
- break;
+ goto free_ivar;
}
if (bootverbose || mmc_debug)
device_printf(sc->dev,
@@ -1481,7 +1643,11 @@ mmc_discover_cards(struct mmc_softc *sc)
newcard ? "New c" : "C", ivar->raw_csd[0],
ivar->raw_csd[1], ivar->raw_csd[2],
ivar->raw_csd[3]);
- mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd);
+ err = mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd);
+ if (err != MMC_ERR_NONE) {
+ device_printf(sc->dev, "Error decoding CSD\n");
+ goto free_ivar;
+ }
ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE;
if (ivar->csd.csd_structure > 0)
ivar->high_cap = 1;
@@ -1494,12 +1660,12 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading card status %d\n", err);
- break;
+ goto free_ivar;
}
if ((status & R1_CARD_IS_LOCKED) != 0) {
device_printf(sc->dev,
- "Card is password protected, skipping.\n");
- break;
+ "Card is password protected, skipping\n");
+ goto free_ivar;
}
/* Get card SCR. Card must be selected to fetch it. */
@@ -1507,13 +1673,13 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error selecting card %d\n", err);
- break;
+ goto free_ivar;
}
err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading SCR %d\n", err);
- break;
+ goto free_ivar;
}
mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
/* Get card switch capabilities (command class 10). */
@@ -1541,7 +1707,7 @@ mmc_discover_cards(struct mmc_softc *sc)
* use from the sd_status is the erase sector size, but
* it is still nice to get that right.
*/
- mmc_select_card(sc, 0);
+ (void)mmc_select_card(sc, 0);
(void)mmc_select_card(sc, ivar->rca);
(void)mmc_app_sd_status(sc, ivar->rca,
ivar->raw_sd_status);
@@ -1551,47 +1717,24 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->erase_sector =
16 << ivar->sd_status.au_size;
}
- /* Find max supported bus width. */
+ /* Find maximum supported bus width. */
if ((host_caps & MMC_CAP_4_BIT_DATA) &&
(ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
ivar->bus_width = bus_width_4;
- /*
- * Some cards that report maximum I/O block sizes
- * greater than 512 require the block length to be
- * set to 512, even though that is supposed to be
- * the default. Example:
- *
- * Transcend 2GB SDSC card, CID:
- * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000
- */
- if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE ||
- ivar->csd.write_bl_len != MMC_SECTOR_SIZE)
- mmc_set_blocklen(sc, MMC_SECTOR_SIZE);
-
- mmc_format_card_id_string(ivar);
-
- if (bootverbose || mmc_debug)
- mmc_log_card(sc->dev, ivar, newcard);
- if (newcard) {
- /* Add device. */
- child = device_add_child(sc->dev, NULL, -1);
- device_set_ivars(child, ivar);
- }
- mmc_select_card(sc, 0);
- return;
+ goto child_common;
}
ivar->rca = rca++;
err = mmc_set_relative_addr(sc, ivar->rca);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error setting RCA %d\n", err);
- break;
+ goto free_ivar;
}
/* Get card CSD. */
err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error getting CSD %d\n", err);
- break;
+ goto free_ivar;
}
if (bootverbose || mmc_debug)
device_printf(sc->dev,
@@ -1610,19 +1753,19 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading card status %d\n", err);
- break;
+ goto free_ivar;
}
if ((status & R1_CARD_IS_LOCKED) != 0) {
device_printf(sc->dev,
- "Card is password protected, skipping.\n");
- break;
+ "Card is password protected, skipping\n");
+ goto free_ivar;
}
err = mmc_select_card(sc, ivar->rca);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error selecting card %d\n",
err);
- break;
+ goto free_ivar;
}
/* Only MMC >= 4.x devices support EXT_CSD. */
@@ -1632,7 +1775,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading EXT_CSD %d\n", err);
- break;
+ goto free_ivar;
}
/* Handle extended capacity from EXT_CSD */
sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] +
@@ -1643,6 +1786,8 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->sec_count = sec_count;
ivar->high_cap = 1;
}
+ /* Find maximum supported bus width. */
+ ivar->bus_width = mmc_test_bus_width(sc);
/* Get device speeds beyond normal mode. */
if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
EXT_CSD_CARD_TYPE_HS_52) != 0) {
@@ -1665,6 +1810,50 @@ mmc_discover_cards(struct mmc_softc *sc)
setbit(&ivar->timings, bus_timing_mmc_ddr52);
setbit(&ivar->vccq_180, bus_timing_mmc_ddr52);
}
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0) {
+ setbit(&ivar->timings, bus_timing_mmc_hs200);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs200);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0) {
+ setbit(&ivar->timings, bus_timing_mmc_hs200);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs200);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs400);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs400);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400es);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs400es);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400es);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs400es);
+ }
/*
* Determine generic switch timeout (provided in
* units of 10 ms), defaulting to 500 ms.
@@ -1673,8 +1862,6 @@ mmc_discover_cards(struct mmc_softc *sc)
if (ivar->csd.spec_vers >= 6)
ivar->cmd6_time = 10 *
ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME];
- /* Find max supported bus width. */
- ivar->bus_width = mmc_test_bus_width(sc);
/* Handle HC erase sector size. */
if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) {
ivar->erase_sector = 1024 *
@@ -1688,11 +1875,15 @@ mmc_discover_cards(struct mmc_softc *sc)
device_printf(sc->dev,
"Error setting erase group %d\n",
err);
- break;
+ goto free_ivar;
}
}
}
+ mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid,
+ ivar->raw_ext_csd[EXT_CSD_REV] >= 5);
+
+child_common:
/*
* Some cards that report maximum I/O block sizes greater
* than 512 require the block length to be set to 512, even
@@ -1705,8 +1896,6 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->csd.write_bl_len != MMC_SECTOR_SIZE)
mmc_set_blocklen(sc, MMC_SECTOR_SIZE);
- mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid,
- ivar->raw_ext_csd[EXT_CSD_REV] >= 5);
mmc_format_card_id_string(ivar);
if (bootverbose || mmc_debug)
@@ -1714,56 +1903,111 @@ mmc_discover_cards(struct mmc_softc *sc)
if (newcard) {
/* Add device. */
child = device_add_child(sc->dev, NULL, -1);
- device_set_ivars(child, ivar);
+ if (child != NULL) {
+ device_set_ivars(child, ivar);
+ sc->child_list = realloc(sc->child_list,
+ sizeof(device_t) * sc->child_count + 1,
+ M_DEVBUF, M_WAITOK);
+ sc->child_list[sc->child_count++] = child;
+ } else
+ device_printf(sc->dev, "Error adding child\n");
}
- mmc_select_card(sc, 0);
+
+free_ivar:
+ if (newcard && child == NULL)
+ free(ivar, M_DEVBUF);
+ (void)mmc_select_card(sc, 0);
+ /*
+ * Not returning here when one MMC device could no be added
+ * potentially would mean looping forever when that device
+ * is broken (in which case it also may impact the remainder
+ * of the bus anyway, though).
+ */
+ if ((newcard && child == NULL) ||
+ mmcbr_get_mode(sc->dev) == mode_sd)
+ return;
}
}
static void
+mmc_update_child_list(struct mmc_softc *sc)
+{
+ device_t child;
+ int i, j;
+
+ if (sc->child_count == 0) {
+ free(sc->child_list, M_DEVBUF);
+ return;
+ }
+ for (i = j = 0; i < sc->child_count; i++) {
+ for (;;) {
+ child = sc->child_list[j++];
+ if (child != NULL)
+ break;
+ }
+ if (i != j)
+ sc->child_list[i] = child;
+ }
+ sc->child_list = realloc(sc->child_list, sizeof(device_t) *
+ sc->child_count, M_DEVBUF, M_WAITOK);
+}
+
+static void
mmc_rescan_cards(struct mmc_softc *sc)
{
struct mmc_ivars *ivar;
- device_t *devlist;
- int err, i, devcount;
+ int err, i, j;
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- return;
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ for (i = j = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE) {
if (bootverbose || mmc_debug)
device_printf(sc->dev,
- "Card at relative address %d lost.\n",
+ "Card at relative address %d lost\n",
ivar->rca);
- device_delete_child(sc->dev, devlist[i]);
+ err = device_delete_child(sc->dev, sc->child_list[i]);
+ if (err != 0) {
+ j++;
+ continue;
+ }
free(ivar, M_DEVBUF);
- }
+ } else
+ j++;
}
- free(devlist, M_TEMP);
- mmc_select_card(sc, 0);
+ if (sc->child_count == j)
+ goto out;
+ sc->child_count = j;
+ mmc_update_child_list(sc);
+out:
+ (void)mmc_select_card(sc, 0);
}
static int
-mmc_delete_cards(struct mmc_softc *sc)
+mmc_delete_cards(struct mmc_softc *sc, bool final)
{
struct mmc_ivars *ivar;
- device_t *devlist;
- int err, i, devcount;
+ int err, i, j;
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- return (err);
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ err = 0;
+ for (i = j = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (bootverbose || mmc_debug)
device_printf(sc->dev,
- "Card at relative address %d deleted.\n",
+ "Card at relative address %d deleted\n",
ivar->rca);
- device_delete_child(sc->dev, devlist[i]);
+ err = device_delete_child(sc->dev, sc->child_list[i]);
+ if (err != 0) {
+ j++;
+ if (final == false)
+ continue;
+ else
+ break;
+ }
free(ivar, M_DEVBUF);
}
- free(devlist, M_TEMP);
- return (0);
+ sc->child_count = j;
+ mmc_update_child_list(sc);
+ return (err);
}
static void
@@ -1827,7 +2071,7 @@ mmc_go_discovery(struct mmc_softc *sc)
mmcbr_get_ocr(dev));
if (mmcbr_get_ocr(dev) == 0) {
device_printf(sc->dev, "No compatible cards found on bus\n");
- mmc_delete_cards(sc);
+ (void)mmc_delete_cards(sc, false);
mmc_power_down(sc);
return;
}
@@ -1851,31 +2095,27 @@ mmc_go_discovery(struct mmc_softc *sc)
static int
mmc_calculate_clock(struct mmc_softc *sc)
{
- device_t *kids;
+ device_t dev;
struct mmc_ivars *ivar;
- int host_caps, i, nkid;
+ int i;
uint32_t dtr, max_dtr;
+ uint16_t rca;
enum mmc_bus_timing max_timing, timing;
- bool changed;
+ bool changed, hs400;
- max_dtr = mmcbr_get_f_max(sc->dev);
- host_caps = mmcbr_get_caps(sc->dev);
- if ((host_caps & MMC_CAP_MMC_DDR52) != 0)
- max_timing = bus_timing_mmc_ddr52;
- else if ((host_caps & MMC_CAP_HSPEED) != 0)
- max_timing = bus_timing_hs;
- else
- max_timing = bus_timing_normal;
- if (device_get_children(sc->dev, &kids, &nkid) != 0)
- panic("can't get children");
+ dev = sc->dev;
+ max_dtr = mmcbr_get_f_max(dev);
+ max_timing = bus_timing_max;
do {
changed = false;
- for (i = 0; i < nkid; i++) {
- ivar = device_get_ivars(kids[i]);
- if (isclr(&ivar->timings, max_timing)) {
- for (timing = max_timing; timing >=
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
+ if (isclr(&ivar->timings, max_timing) ||
+ !mmc_host_timing(dev, max_timing)) {
+ for (timing = max_timing - 1; timing >=
bus_timing_normal; timing--) {
- if (isset(&ivar->timings, timing)) {
+ if (isset(&ivar->timings, timing) &&
+ mmc_host_timing(dev, timing)) {
max_timing = timing;
break;
}
@@ -1889,38 +2129,316 @@ mmc_calculate_clock(struct mmc_softc *sc)
}
}
} while (changed == true);
+
if (bootverbose || mmc_debug) {
- device_printf(sc->dev,
+ device_printf(dev,
"setting transfer rate to %d.%03dMHz (%s timing)\n",
max_dtr / 1000000, (max_dtr / 1000) % 1000,
mmc_timing_to_string(max_timing));
}
- for (i = 0; i < nkid; i++) {
- ivar = device_get_ivars(kids[i]);
+
+ /*
+ * HS400 must be tuned in HS200 mode, so in case of HS400 we begin
+ * with HS200 following the sequence as described in "6.6.2.2 HS200
+ * timing mode selection" of the eMMC specification v5.1, too, and
+ * switch to max_timing later. HS400ES requires no tuning and, thus,
+ * can be switch to directly, but requires the same detour via high
+ * speed mode as does HS400 (see mmc_switch_to_hs400()).
+ */
+ hs400 = max_timing == bus_timing_mmc_hs400;
+ timing = hs400 == true ? bus_timing_mmc_hs200 : max_timing;
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if ((ivar->timings & ~(1 << bus_timing_normal)) == 0)
continue;
- if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE ||
- mmc_set_timing(sc, ivar, max_timing) != MMC_ERR_NONE)
- device_printf(sc->dev, "Card at relative address %d "
- "failed to set timing.\n", ivar->rca);
+
+ rca = ivar->rca;
+ if (mmc_select_card(sc, rca) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to select\n", rca);
+ continue;
+ }
+
+ if (timing == bus_timing_mmc_hs200 || /* includes HS400 */
+ timing == bus_timing_mmc_hs400es) {
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Failed to set VCCQ for "
+ "card at relative address %d\n", rca);
+ continue;
+ }
+ }
+
+ if (timing == bus_timing_mmc_hs200) { /* includes HS400 */
+ /* Set bus width (required for initial tuning). */
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set bus width\n", rca);
+ continue;
+ }
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+ } else if (timing == bus_timing_mmc_hs400es) {
+ if (mmc_switch_to_hs400(sc, ivar, max_dtr, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set %s timing\n", rca,
+ mmc_timing_to_string(timing));
+ continue;
+ }
+ goto power_class;
+ }
+
+ if (mmc_set_timing(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set %s timing\n", rca,
+ mmc_timing_to_string(timing));
+ continue;
+ }
+
+ if (timing == bus_timing_mmc_ddr52) {
+ /*
+ * Set EXT_CSD_BUS_WIDTH_n_DDR in EXT_CSD_BUS_WIDTH
+ * (must be done after switching to EXT_CSD_HS_TIMING).
+ */
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set bus width\n", rca);
+ continue;
+ }
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Failed to set VCCQ for "
+ "card at relative address %d\n", rca);
+ continue;
+ }
+ }
+
+ /* Set clock (must be done before initial tuning). */
+ mmcbr_set_clock(dev, max_dtr);
+ mmcbr_update_ios(dev);
+
+ if (mmcbr_tune(dev, hs400) != 0) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to execute initial tuning\n", rca);
+ continue;
+ }
+
+ if (hs400 == true && mmc_switch_to_hs400(sc, ivar, max_dtr,
+ max_timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set %s timing\n", rca,
+ mmc_timing_to_string(max_timing));
+ continue;
+ }
+
+power_class:
+ if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set power class\n", rca);
+ }
}
- mmc_select_card(sc, 0);
- free(kids, M_TEMP);
- mmcbr_set_clock(sc->dev, max_dtr);
- mmcbr_update_ios(sc->dev);
+ (void)mmc_select_card(sc, 0);
return (max_dtr);
}
+/*
+ * Switch from HS200 to HS400 (either initially or for re-tuning) or directly
+ * to HS400ES. This follows the sequences described in "6.6.2.3 HS400 timing
+ * mode selection" of the eMMC specification v5.1.
+ */
+static int
+mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock, enum mmc_bus_timing max_timing)
+{
+ device_t dev;
+ int err;
+ uint16_t rca;
+
+ dev = sc->dev;
+ rca = ivar->rca;
+
+ /*
+ * Both clock and timing must be set as appropriate for high speed
+ * before eventually switching to HS400/HS400ES; mmc_set_timing()
+ * will issue mmcbr_update_ios().
+ */
+ mmcbr_set_clock(dev, ivar->hs_tran_speed);
+ err = mmc_set_timing(sc, ivar, bus_timing_hs);
+ if (err != MMC_ERR_NONE)
+ return (err);
+
+ /*
+ * Set EXT_CSD_BUS_WIDTH_8_DDR in EXT_CSD_BUS_WIDTH (and additionally
+ * EXT_CSD_BUS_WIDTH_ES for HS400ES).
+ */
+ err = mmc_set_card_bus_width(sc, ivar, max_timing);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+
+ /* Finally, switch to HS400/HS400ES mode. */
+ err = mmc_set_timing(sc, ivar, max_timing);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_clock(dev, clock);
+ mmcbr_update_ios(dev);
+ return (MMC_ERR_NONE);
+}
+
+/*
+ * Switch from HS400 to HS200 (for re-tuning).
+ */
+static int
+mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock)
+{
+ device_t dev;
+ int err;
+ uint16_t rca;
+
+ dev = sc->dev;
+ rca = ivar->rca;
+
+ /*
+ * Both clock and timing must initially be set as appropriate for
+ * DDR52 before eventually switching to HS200; mmc_set_timing()
+ * will issue mmcbr_update_ios().
+ */
+ mmcbr_set_clock(dev, ivar->hs_tran_speed);
+ err = mmc_set_timing(sc, ivar, bus_timing_mmc_ddr52);
+ if (err != MMC_ERR_NONE)
+ return (err);
+
+ /*
+ * Next, switch to high speed. Thus, clear EXT_CSD_BUS_WIDTH_n_DDR
+ * in EXT_CSD_BUS_WIDTH and update bus width and timing in ios.
+ */
+ err = mmc_set_card_bus_width(sc, ivar, bus_timing_hs);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_set_timing(sc->dev, bus_timing_hs);
+ mmcbr_update_ios(dev);
+
+ /* Finally, switch to HS200 mode. */
+ err = mmc_set_timing(sc, ivar, bus_timing_mmc_hs200);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_clock(dev, clock);
+ mmcbr_update_ios(dev);
+ return (MMC_ERR_NONE);
+}
+
+static int
+mmc_retune(device_t busdev, device_t dev, bool reset)
+{
+ struct mmc_softc *sc;
+ struct mmc_ivars *ivar;
+ int err;
+ uint32_t clock;
+ enum mmc_bus_timing timing;
+
+ if (device_get_parent(dev) != busdev)
+ return (MMC_ERR_INVALID);
+
+ sc = device_get_softc(busdev);
+ if (sc->retune_needed != 1 && sc->retune_paused != 0)
+ return (MMC_ERR_INVALID);
+
+ timing = mmcbr_get_timing(busdev);
+ if (timing == bus_timing_mmc_hs400) {
+ /*
+ * Controllers use the data strobe line to latch data from
+ * the devices in HS400 mode so periodic re-tuning isn't
+ * expected to be required, i. e. only if a CRC or tuning
+ * error is signaled to the bridge. In these latter cases
+ * we are asked to reset the tuning circuit and need to do
+ * the switch timing dance.
+ */
+ if (reset == false)
+ return (0);
+ ivar = device_get_ivars(dev);
+ clock = mmcbr_get_clock(busdev);
+ if (mmc_switch_to_hs200(sc, ivar, clock) != MMC_ERR_NONE)
+ return (MMC_ERR_BADCRC);
+ }
+ err = mmcbr_retune(busdev, reset);
+ if (err != 0 && timing == bus_timing_mmc_hs400)
+ return (MMC_ERR_BADCRC);
+ switch (err) {
+ case 0:
+ break;
+ case EIO:
+ return (MMC_ERR_FAILED);
+ default:
+ return (MMC_ERR_INVALID);
+ }
+ if (timing == bus_timing_mmc_hs400) {
+ if (mmc_switch_to_hs400(sc, ivar, clock, timing) !=
+ MMC_ERR_NONE)
+ return (MMC_ERR_BADCRC);
+ }
+ return (MMC_ERR_NONE);
+}
+
+static void
+mmc_retune_pause(device_t busdev, device_t dev, bool retune)
+{
+ struct mmc_softc *sc;
+
+ sc = device_get_softc(busdev);
+ KASSERT(device_get_parent(dev) == busdev,
+ ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev),
+ device_get_nameunit(busdev)));
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+
+ if (retune == true && sc->retune_paused == 0)
+ sc->retune_needed = 1;
+ sc->retune_paused++;
+}
+
+static void
+mmc_retune_unpause(device_t busdev, device_t dev)
+{
+ struct mmc_softc *sc;
+
+ sc = device_get_softc(busdev);
+ KASSERT(device_get_parent(dev) == busdev,
+ ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev),
+ device_get_nameunit(busdev)));
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+ KASSERT(sc->retune_paused != 0,
+ ("%s: Re-tune pause count already at 0", __func__));
+
+ sc->retune_paused--;
+}
+
static void
mmc_scan(struct mmc_softc *sc)
{
device_t dev = sc->dev;
+ int err;
- mmc_acquire_bus(dev, dev);
+ err = mmc_acquire_bus(dev, dev);
+ if (err != 0) {
+ device_printf(dev, "Failed to acquire bus for scanning\n");
+ return;
+ }
mmc_go_discovery(sc);
- mmc_release_bus(dev, dev);
-
- bus_generic_attach(dev);
+ err = mmc_release_bus(dev, dev);
+ if (err != 0) {
+ device_printf(dev, "Failed to release bus after scanning\n");
+ return;
+ }
+ (void)bus_generic_attach(dev);
}
static int
@@ -2019,6 +2537,8 @@ static device_method_t mmc_methods[] = {
DEVMETHOD(bus_child_location_str, mmc_child_location_str),
/* MMC Bus interface */
+ DEVMETHOD(mmcbus_retune_pause, mmc_retune_pause),
+ DEVMETHOD(mmcbus_retune_unpause, mmc_retune_unpause),
DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request),
DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus),
DEVMETHOD(mmcbus_release_bus, mmc_release_bus),
diff --git a/freebsd/sys/dev/mmc/mmc_ioctl.h b/freebsd/sys/dev/mmc/mmc_ioctl.h
index 97cff068..e633fec9 100644
--- a/freebsd/sys/dev/mmc/mmc_ioctl.h
+++ b/freebsd/sys/dev/mmc/mmc_ioctl.h
@@ -54,7 +54,7 @@ struct mmc_ioc_multi_cmd {
#define MMC_IOC_BASE 'M'
#define MMC_IOC_CMD _IOWR(MMC_IOC_BASE, 0, struct mmc_ioc_cmd)
-#define MMC_IOC_CMD_MULTI _IOWR(MMC_IOC_BASE, 1, struct mmc_ioc_multi_cmd)
+#define MMC_IOC_MULTI_CMD _IOWR(MMC_IOC_BASE, 1, struct mmc_ioc_multi_cmd)
/* Maximum accepted data transfer size */
#define MMC_IOC_MAX_BYTES (512 * 256)
diff --git a/freebsd/sys/dev/mmc/mmc_private.h b/freebsd/sys/dev/mmc/mmc_private.h
index bbca0c60..633d0784 100644
--- a/freebsd/sys/dev/mmc/mmc_private.h
+++ b/freebsd/sys/dev/mmc/mmc_private.h
@@ -60,9 +60,14 @@ struct mmc_softc {
struct mtx sc_mtx;
struct intr_config_hook config_intrhook;
device_t owner;
- uint32_t last_rca;
- int squelched; /* suppress reporting of (expected) errors */
- int log_count;
+ device_t *child_list;
+ int child_count;
+ uint16_t last_rca;
+ uint16_t retune_paused;
+ uint8_t retune_needed;
+ uint8_t retune_ongoing;
+ uint16_t squelched; /* suppress reporting of (expected) errors */
+ int log_count;
struct timeval log_time;
};
diff --git a/freebsd/sys/dev/mmc/mmc_subr.c b/freebsd/sys/dev/mmc/mmc_subr.c
index f76e9637..006354ba 100644
--- a/freebsd/sys/dev/mmc/mmc_subr.c
+++ b/freebsd/sys/dev/mmc/mmc_subr.c
@@ -140,7 +140,6 @@ mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
sc->squelched--;
if (err != MMC_ERR_NONE && brdev == reqdev) {
- sc = device_get_softc(brdev);
if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
&sc->log_count, LOG_PPS)) {
device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n",
@@ -156,10 +155,13 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
uint8_t index, uint8_t value, u_int timeout, bool status)
{
struct mmc_command cmd;
+ struct mmc_softc *sc;
int err;
KASSERT(timeout != 0, ("%s: no timeout", __func__));
+ sc = device_get_softc(brdev);
+
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_SWITCH_FUNC;
cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) |
@@ -174,10 +176,19 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
else
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ /*
+ * Pause re-tuning so it won't interfere with the busy state and also
+ * so that the result of CMD13 will always refer to switching rather
+ * than to a tuning command that may have snuck in between.
+ */
+ sc->retune_paused++;
err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE || status == false)
- return (err);
- return (mmc_switch_status(brdev, reqdev, rca, timeout));
+ goto out;
+ err = mmc_switch_status(brdev, reqdev, rca, timeout);
+out:
+ sc->retune_paused--;
+ return (err);
}
int
@@ -194,6 +205,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
* type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only
* once and then exit the loop.
*/
+ end.tv_sec = end.tv_usec = 0;
for (;;) {
err = mmc_send_status(brdev, reqdev, rca, &status);
if (err != MMC_ERR_NONE)
@@ -210,7 +222,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
break;
}
}
- if (err == MMC_ERR_NONE && R1_CURRENT_STATE(status) == R1_SWITCH_ERROR)
+ if (err == MMC_ERR_NONE && (status & R1_SWITCH_ERROR) != 0)
return (MMC_ERR_FAILED);
return (err);
}
diff --git a/freebsd/sys/dev/mmc/mmcbrvar.h b/freebsd/sys/dev/mmc/mmcbrvar.h
index 77c304b4..c70af92a 100644
--- a/freebsd/sys/dev/mmc/mmcbrvar.h
+++ b/freebsd/sys/dev/mmc/mmcbrvar.h
@@ -70,6 +70,7 @@ enum mmcbr_device_ivars {
MMCBR_IVAR_MODE,
MMCBR_IVAR_OCR,
MMCBR_IVAR_POWER_MODE,
+ MMCBR_IVAR_RETUNE_REQ,
MMCBR_IVAR_VDD,
MMCBR_IVAR_VCCQ,
MMCBR_IVAR_CAPS,
@@ -94,6 +95,7 @@ MMCBR_ACCESSOR(host_ocr, HOST_OCR, int)
MMCBR_ACCESSOR(mode, MODE, int)
MMCBR_ACCESSOR(ocr, OCR, int)
MMCBR_ACCESSOR(power_mode, POWER_MODE, int)
+MMCBR_ACCESSOR(retune_req, RETUNE_REQ, int)
MMCBR_ACCESSOR(vdd, VDD, int)
MMCBR_ACCESSOR(vccq, VCCQ, int)
MMCBR_ACCESSOR(caps, CAPS, int)
@@ -109,6 +111,20 @@ mmcbr_update_ios(device_t dev)
}
static int __inline
+mmcbr_tune(device_t dev, bool hs400)
+{
+
+ return (MMCBR_TUNE(device_get_parent(dev), dev, hs400));
+}
+
+static int __inline
+mmcbr_retune(device_t dev, bool reset)
+{
+
+ return (MMCBR_RETUNE(device_get_parent(dev), dev, reset));
+}
+
+static int __inline
mmcbr_switch_vccq(device_t dev)
{
diff --git a/freebsd/sys/dev/mmc/mmcreg.h b/freebsd/sys/dev/mmc/mmcreg.h
index 39680ad6..80f433c1 100644
--- a/freebsd/sys/dev/mmc/mmcreg.h
+++ b/freebsd/sys/dev/mmc/mmcreg.h
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2006 M. Warner Losh. All rights reserved.
* Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
+ * Copyright (c) 2015-2016 Ilya Bakulin <kibab@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -159,6 +160,34 @@ struct mmc_command {
#define R1_STATE_PRG 7
#define R1_STATE_DIS 8
+/* R4 response (SDIO) */
+#define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3)
+#define R4_IO_MEM_PRESENT (0x1<<27)
+#define R4_IO_OCR_MASK 0x00fffff0
+
+/*
+ * R5 responses
+ *
+ * Types (per SD 2.0 standard)
+ *e : error bit
+ *s : status bit
+ *r : detected and set for the actual command response
+ *x : Detected and set during command execution. The host can get
+ * the status by issuing a command with R1 response.
+ *
+ * Clear Condition (per SD 2.0 standard)
+ *a : according to the card current state.
+ *b : always related to the previous command. reception of a valid
+ * command will clear it (with a delay of one command).
+ *c : clear by read
+ */
+#define R5_COM_CRC_ERROR (1u << 15)/* er, b */
+#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */
+#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */
+#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12)
+#define R5_ERROR (1u << 11)/* erx, c */
+#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */
+#define R5_OUT_OF_RANGE (1u << 8)/* er, c */
struct mmc_data {
size_t len; /* size of the data */
size_t xfer_len;
@@ -176,10 +205,12 @@ struct mmc_request {
struct mmc_command *stop;
void (*done)(struct mmc_request *); /* Completion function */
void *done_data; /* requestor set data */
-#ifndef __rtems__
uint32_t flags;
+#ifndef __rtems__
#define MMC_REQ_DONE 1
-#else /* __rtems__ */
+#endif /* __rtems__ */
+#define MMC_TUNE_DONE 2
+#ifdef __rtems__
rtems_binary_semaphore req_done;
#endif /* __rtems__ */
};
@@ -194,6 +225,7 @@ struct mmc_request {
#define SD_SEND_RELATIVE_ADDR 3
#define MMC_SET_DSR 4
#define MMC_SLEEP_AWAKE 5
+#define IO_SEND_OP_COND 5
#define MMC_SWITCH_FUNC 6
#define MMC_SWITCH_FUNC_CMDS 0
#define MMC_SWITCH_FUNC_SET 1
@@ -276,7 +308,31 @@ struct mmc_request {
/* Class 9: I/O cards (sd) */
#define SD_IO_RW_DIRECT 52
+/* CMD52 arguments */
+#define SD_ARG_CMD52_READ (0<<31)
+#define SD_ARG_CMD52_WRITE (1<<31)
+#define SD_ARG_CMD52_FUNC_SHIFT 28
+#define SD_ARG_CMD52_FUNC_MASK 0x7
+#define SD_ARG_CMD52_EXCHANGE (1<<27)
+#define SD_ARG_CMD52_REG_SHIFT 9
+#define SD_ARG_CMD52_REG_MASK 0x1ffff
+#define SD_ARG_CMD52_DATA_SHIFT 0
+#define SD_ARG_CMD52_DATA_MASK 0xff
+#define SD_R5_DATA(resp) ((resp)[0] & 0xff)
+
#define SD_IO_RW_EXTENDED 53
+/* CMD53 arguments */
+#define SD_ARG_CMD53_READ (0<<31)
+#define SD_ARG_CMD53_WRITE (1<<31)
+#define SD_ARG_CMD53_FUNC_SHIFT 28
+#define SD_ARG_CMD53_FUNC_MASK 0x7
+#define SD_ARG_CMD53_BLOCK_MODE (1<<27)
+#define SD_ARG_CMD53_INCREMENT (1<<26)
+#define SD_ARG_CMD53_REG_SHIFT 9
+#define SD_ARG_CMD53_REG_MASK 0x1ffff
+#define SD_ARG_CMD53_LENGTH_SHIFT 0
+#define SD_ARG_CMD53_LENGTH_MASK 0x1ff
+#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */
/* Class 10: Switch function commands */
#define SD_SWITCH_FUNC 6
@@ -384,8 +440,8 @@ struct mmc_request {
#define EXT_CSD_HS_TIMING_BC 0
#define EXT_CSD_HS_TIMING_HS 1
-#define EXT_CSD_HS_TIMING_DDR200 2
-#define EXT_CSD_HS_TIMING_DDR400 3
+#define EXT_CSD_HS_TIMING_HS200 2
+#define EXT_CSD_HS_TIMING_HS400 3
#define EXT_CSD_HS_TIMING_DRV_STR_SHIFT 4
#define EXT_CSD_POWER_CLASS_8BIT_MASK 0xf0
@@ -401,7 +457,6 @@ struct mmc_request {
#define EXT_CSD_CARD_TYPE_HS200_1_2V 0x0020
#define EXT_CSD_CARD_TYPE_HS400_1_8V 0x0040
#define EXT_CSD_CARD_TYPE_HS400_1_2V 0x0080
-#define EXT_CSD_CARD_TYPE_HS400ES 0x0100
#define EXT_CSD_BUS_WIDTH_1 0
#define EXT_CSD_BUS_WIDTH_4 1
@@ -410,6 +465,8 @@ struct mmc_request {
#define EXT_CSD_BUS_WIDTH_8_DDR 6
#define EXT_CSD_BUS_WIDTH_ES 0x80
+#define EXT_CSD_STROBE_SUPPORT_EN 0x01
+
#define MMC_TYPE_HS_26_MAX 26000000
#define MMC_TYPE_HS_52_MAX 52000000
#define MMC_TYPE_DDR52_MAX 52000000
@@ -447,6 +504,54 @@ struct mmc_request {
/* Specifications require 400 kHz max. during ID phase. */
#define SD_MMC_CARD_ID_FREQUENCY 400000
+/*
+ * SDIO Direct & Extended I/O
+ */
+#define SD_IO_RW_WR (1u << 31)
+#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28)
+#define SD_IO_RW_RAW (1u << 27)
+#define SD_IO_RW_INCR (1u << 26)
+#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9)
+#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0)
+#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0)
+
+#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0)
+#define SD_IOE_RW_BLK (1u << 27)
+
+/* Card Common Control Registers (CCCR) */
+#define SD_IO_CCCR_START 0x00000
+#define SD_IO_CCCR_SIZE 0x100
+#define SD_IO_CCCR_FN_ENABLE 0x02
+#define SD_IO_CCCR_FN_READY 0x03
+#define SD_IO_CCCR_INT_ENABLE 0x04
+#define SD_IO_CCCR_INT_PENDING 0x05
+#define SD_IO_CCCR_CTL 0x06
+#define CCCR_CTL_RES (1<<3)
+#define SD_IO_CCCR_BUS_WIDTH 0x07
+#define CCCR_BUS_WIDTH_4 (1<<1)
+#define CCCR_BUS_WIDTH_1 (1<<0)
+#define SD_IO_CCCR_CARDCAP 0x08
+#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */
+
+/* Function Basic Registers (FBR) */
+#define SD_IO_FBR_START 0x00100
+#define SD_IO_FBR_SIZE 0x00700
+
+/* Card Information Structure (CIS) */
+#define SD_IO_CIS_START 0x01000
+#define SD_IO_CIS_SIZE 0x17000
+
+/* CIS tuple codes (based on PC Card 16) */
+#define SD_IO_CISTPL_VERS_1 0x15
+#define SD_IO_CISTPL_MANFID 0x20
+#define SD_IO_CISTPL_FUNCID 0x21
+#define SD_IO_CISTPL_FUNCE 0x22
+#define SD_IO_CISTPL_END 0xff
+
+/* CISTPL_FUNCID codes */
+/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */
+/* #define SDMMC_FUNCTION_WLAN 0x0c */
+
/* OCR bits */
/*
@@ -562,6 +667,10 @@ struct mmc_sd_status
#define MMC_PART_GP_MAX 4
#define MMC_PART_MAX 8
+#define MMC_TUNING_MAX 64 /* Maximum tuning iterations */
+#define MMC_TUNING_LEN 64 /* Size of tuning data */
+#define MMC_TUNING_LEN_HS200 128 /* Size of tuning data in HS200 mode */
+
/*
* Older versions of the MMC standard had a variable sector size. However,
* I've been able to find no old MMC or SD cards that have a non 512
diff --git a/freebsd/sys/dev/mmc/mmcsd.c b/freebsd/sys/dev/mmc/mmcsd.c
index 5066e250..195feae2 100644
--- a/freebsd/sys/dev/mmc/mmcsd.c
+++ b/freebsd/sys/dev/mmc/mmcsd.c
@@ -108,7 +108,8 @@ __FBSDID("$FreeBSD$");
struct mmcsd_softc;
struct mmcsd_part {
- struct mtx part_mtx;
+ struct mtx disk_mtx;
+ struct mtx ioctl_mtx;
struct mmcsd_softc *sc;
#ifndef __rtems__
struct disk *disk;
@@ -120,6 +121,7 @@ struct mmcsd_part {
u_int type;
int running;
int suspend;
+ int ioctl;
bool ro;
char name[MMCSD_PART_NAMELEN];
};
@@ -129,6 +131,9 @@ struct mmcsd_softc {
device_t mmcbr;
struct mmcsd_part *part[MMC_PART_MAX];
enum mmc_card_mode mode;
+ u_int max_data; /* Maximum data size [blocks] */
+ u_int erase_sector; /* Device native erase sector size [blocks] */
+ uint8_t high_cap; /* High Capacity device (block addressed) */
uint8_t part_curr; /* Partition currently switched to */
uint8_t ext_csd[MMC_EXTCSD_SIZE];
uint16_t rca;
@@ -199,15 +204,25 @@ static int mmcsd_slicer(device_t dev, const char *provider,
static int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca,
u_int part);
-#define MMCSD_PART_LOCK(_part) mtx_lock(&(_part)->part_mtx)
-#define MMCSD_PART_UNLOCK(_part) mtx_unlock(&(_part)->part_mtx)
-#define MMCSD_PART_LOCK_INIT(_part) \
- mtx_init(&(_part)->part_mtx, (_part)->name, "mmcsd part", MTX_DEF)
-#define MMCSD_PART_LOCK_DESTROY(_part) mtx_destroy(&(_part)->part_mtx);
-#define MMCSD_PART_ASSERT_LOCKED(_part) \
- mtx_assert(&(_part)->part_mtx, MA_OWNED);
-#define MMCSD_PART_ASSERT_UNLOCKED(_part) \
- mtx_assert(&(_part)->part_mtx, MA_NOTOWNED);
+#define MMCSD_DISK_LOCK(_part) mtx_lock(&(_part)->disk_mtx)
+#define MMCSD_DISK_UNLOCK(_part) mtx_unlock(&(_part)->disk_mtx)
+#define MMCSD_DISK_LOCK_INIT(_part) \
+ mtx_init(&(_part)->disk_mtx, (_part)->name, "mmcsd disk", MTX_DEF)
+#define MMCSD_DISK_LOCK_DESTROY(_part) mtx_destroy(&(_part)->disk_mtx);
+#define MMCSD_DISK_ASSERT_LOCKED(_part) \
+ mtx_assert(&(_part)->disk_mtx, MA_OWNED);
+#define MMCSD_DISK_ASSERT_UNLOCKED(_part) \
+ mtx_assert(&(_part)->disk_mtx, MA_NOTOWNED);
+
+#define MMCSD_IOCTL_LOCK(_part) mtx_lock(&(_part)->ioctl_mtx)
+#define MMCSD_IOCTL_UNLOCK(_part) mtx_unlock(&(_part)->ioctl_mtx)
+#define MMCSD_IOCTL_LOCK_INIT(_part) \
+ mtx_init(&(_part)->ioctl_mtx, (_part)->name, "mmcsd IOCTL", MTX_DEF)
+#define MMCSD_IOCTL_LOCK_DESTROY(_part) mtx_destroy(&(_part)->ioctl_mtx);
+#define MMCSD_IOCTL_ASSERT_LOCKED(_part) \
+ mtx_assert(&(_part)->ioctl_mtx, MA_OWNED);
+#define MMCSD_IOCLT_ASSERT_UNLOCKED(_part) \
+ mtx_assert(&(_part)->ioctl_mtx, MA_NOTOWNED);
static int
mmcsd_probe(device_t dev)
@@ -277,7 +292,7 @@ rtems_bsd_mmcsd_disk_read_write(struct mmcsd_part *part, rtems_blkdev_request *b
data_flags = MMC_DATA_READ;
}
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
for (i = 0; i < buffer_count; ++i) {
rtems_blkdev_sg_buffer *sg = &blkreq->bufs [i];
@@ -354,7 +369,7 @@ rtems_bsd_mmcsd_disk_read_write(struct mmcsd_part *part, rtems_blkdev_request *b
error:
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
rtems_blkdev_request_done(blkreq, status_code);
@@ -439,6 +454,18 @@ mmcsd_attach(device_t dev)
sc->dev = dev;
sc->mmcbr = mmcbr = device_get_parent(dev);
sc->mode = mmcbr_get_mode(mmcbr);
+ /*
+ * Note that in principle with an SDHCI-like re-tuning implementation,
+ * the maximum data size can change at runtime due to a device removal/
+ * insertion that results in switches to/from a transfer mode involving
+ * re-tuning, iff there are multiple devices on a given bus. Until now
+ * mmc(4) lacks support for rescanning already attached buses, however,
+ * and sdhci(4) to date has no support for shared buses in the first
+ * place either.
+ */
+ sc->max_data = mmc_get_max_data(dev);
+ sc->erase_sector = mmc_get_erase_sector(dev);
+ sc->high_cap = mmc_get_high_cap(dev);
sc->rca = mmc_get_rca(dev);
/* Only MMC >= 4.x devices support EXT_CSD. */
@@ -492,7 +519,7 @@ mmcsd_attach(device_t dev)
(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24)) *
- (mmc_get_high_cap(dev) ? MMC_SECTOR_SIZE : 1);
+ (sc->high_cap != 0 ? MMC_SECTOR_SIZE : 1);
} else if (bootverbose)
device_printf(dev,
"enhanced user data area spans entire device\n");
@@ -505,7 +532,7 @@ mmcsd_attach(device_t dev)
ro = mmc_get_read_only(dev);
mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd",
device_get_unit(dev), mmc_get_media_size(dev) * sector_size,
- mmc_get_erase_sector(dev) * sector_size, ro);
+ sc->erase_sector * sector_size, ro);
if (mmc_get_spec_vers(dev) < 3)
return (0);
@@ -644,7 +671,16 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
part->ro = ro;
snprintf(part->name, sizeof(part->name), name, device_get_unit(dev));
- /* For the RPMB partition, allow IOCTL access only. */
+ MMCSD_IOCTL_LOCK_INIT(part);
+
+ /*
+ * For the RPMB partition, allow IOCTL access only.
+ * NB: If ever attaching RPMB partitions to disk(9), the re-tuning
+ * implementation and especially its pausing need to be revisited,
+ * because then re-tuning requests may be issued by the IOCTL half
+ * of this driver while re-tuning is already paused by the disk(9)
+ * one and vice versa.
+ */
if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
make_dev_args_init(&args);
args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
@@ -659,7 +695,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
return;
}
} else {
- MMCSD_PART_LOCK_INIT(part);
+ MMCSD_DISK_LOCK_INIT(part);
#ifndef __rtems__
d = part->disk = disk_alloc();
@@ -672,7 +708,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
d->d_name = part->name;
d->d_drv1 = part;
d->d_sectorsize = mmc_get_sector_size(dev);
- d->d_maxsize = mmc_get_max_data(dev) * d->d_sectorsize;
+ d->d_maxsize = sc->max_data * d->d_sectorsize;
d->d_mediasize = media_size;
d->d_stripesize = erase_size;
d->d_unit = cnt;
@@ -704,7 +740,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
part->name, cnt, bytes, unit, mmc_get_card_id_string(dev),
ro ? " (read-only)" : "", device_get_nameunit(mmcbr),
speed / 1000000, (speed / 100000) % 10,
- mmcsd_bus_bit_width(dev), mmc_get_max_data(dev));
+ mmcsd_bus_bit_width(dev), sc->max_data);
} else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
printf("%s: %ju%sB partion %d%s at %s\n", part->name, bytes,
unit, type, ro ? " (read-only)" : "",
@@ -795,19 +831,27 @@ mmcsd_detach(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 0;
- if (part->running > 0) {
- /* kill thread */
- part->running = 0;
- wakeup(part);
- /* wait for thread to finish. */
- while (part->running != -1)
- msleep(part, &part->part_mtx, 0,
- "detach", 0);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 0;
+ if (part->running > 0) {
+ /* kill thread */
+ part->running = 0;
+ wakeup(part);
+ /* wait for thread to finish. */
+ while (part->running != -1)
+ msleep(part, &part->disk_mtx, 0,
+ "mmcsd disk detach", 0);
+ }
+ MMCSD_DISK_UNLOCK(part);
}
- MMCSD_PART_UNLOCK(part);
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl > 0)
+ msleep(part, &part->ioctl_mtx, 0,
+ "mmcsd IOCTL detach", 0);
+ part->ioctl = -1;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
@@ -823,8 +867,9 @@ mmcsd_detach(device_t dev)
/* kill disk */
disk_destroy(part->disk);
- MMCSD_PART_LOCK_DESTROY(part);
+ MMCSD_DISK_LOCK_DESTROY(part);
}
+ MMCSD_IOCTL_LOCK_DESTROY(part);
free(part, M_DEVBUF);
}
}
@@ -844,19 +889,27 @@ mmcsd_suspend(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 1;
- if (part->running > 0) {
- /* kill thread */
- part->running = 0;
- wakeup(part);
- /* wait for thread to finish. */
- while (part->running != -1)
- msleep(part, &part->part_mtx, 0,
- "detach", 0);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 1;
+ if (part->running > 0) {
+ /* kill thread */
+ part->running = 0;
+ wakeup(part);
+ /* wait for thread to finish. */
+ while (part->running != -1)
+ msleep(part, &part->disk_mtx, 0,
+ "mmcsd disk suspension", 0);
+ }
+ MMCSD_DISK_UNLOCK(part);
}
- MMCSD_PART_UNLOCK(part);
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl > 0)
+ msleep(part, &part->ioctl_mtx, 0,
+ "mmcsd IOCTL suspension", 0);
+ part->ioctl = -1;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
#else /* __rtems__ */
@@ -875,16 +928,22 @@ mmcsd_resume(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 0;
- if (part->running <= 0) {
- part->running = 1;
- kproc_create(&mmcsd_task, part, &part->p, 0, 0,
- "%s%d: mmc/sd card", part->name, part->cnt);
- MMCSD_PART_UNLOCK(part);
- } else
- MMCSD_PART_UNLOCK(part);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 0;
+ if (part->running <= 0) {
+ part->running = 1;
+ MMCSD_DISK_UNLOCK(part);
+ kproc_create(&mmcsd_task, part,
+ &part->p, 0, 0, "%s%d: mmc/sd card",
+ part->name, part->cnt);
+ } else
+ MMCSD_DISK_UNLOCK(part);
+ }
+ MMCSD_IOCTL_LOCK(part);
+ part->ioctl = 0;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
#else /* __rtems__ */
@@ -916,13 +975,13 @@ mmcsd_strategy(struct bio *bp)
part = bp->bio_disk->d_drv1;
sc = part->sc;
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
if (part->running > 0 || part->suspend > 0) {
bioq_disksort(&part->bio_queue, bp);
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
wakeup(part);
} else {
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
biofinish(bp, NULL, ENXIO);
}
}
@@ -961,9 +1020,9 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
switch (cmd) {
case MMC_IOC_CMD:
mic = data;
- err = mmcsd_ioctl_cmd(part, data, fflag);
+ err = mmcsd_ioctl_cmd(part, mic, fflag);
break;
- case MMC_IOC_CMD_MULTI:
+ case MMC_IOC_MULTI_CMD:
mimc = data;
if (mimc->num_of_cmds == 0)
break;
@@ -973,12 +1032,12 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
size = sizeof(*mic) * cnt;
mic = malloc(size, M_TEMP, M_WAITOK);
err = copyin((const void *)mimc->cmds, mic, size);
- if (err != 0)
- break;
- for (i = 0; i < cnt; i++) {
- err = mmcsd_ioctl_cmd(part, &mic[i], fflag);
- if (err != 0)
- break;
+ if (err == 0) {
+ for (i = 0; i < cnt; i++) {
+ err = mmcsd_ioctl_cmd(part, &mic[i], fflag);
+ if (err != 0)
+ break;
+ }
}
free(mic, M_TEMP);
break;
@@ -1007,11 +1066,31 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
if (part->ro == TRUE && mic->write_flag != 0)
return (EROFS);
+ /*
+ * We don't need to explicitly lock against the disk(9) half of this
+ * driver as MMCBUS_ACQUIRE_BUS() will serialize us. However, it's
+ * necessary to protect against races with detachment and suspension,
+ * especially since it's required to switch away from RPMB partitions
+ * again after an access (see mmcsd_switch_part()).
+ */
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl != 0) {
+ if (part->ioctl < 0) {
+ MMCSD_IOCTL_UNLOCK(part);
+ return (ENXIO);
+ }
+ msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL", 0);
+ }
+ part->ioctl = 1;
+ MMCSD_IOCTL_UNLOCK(part);
+
err = 0;
dp = NULL;
len = mic->blksz * mic->blocks;
- if (len > MMC_IOC_MAX_BYTES)
- return (EOVERFLOW);
+ if (len > MMC_IOC_MAX_BYTES) {
+ err = EOVERFLOW;
+ goto out;
+ }
if (len != 0) {
dp = malloc(len, M_TEMP, M_WAITOK);
err = copyin((void *)(uintptr_t)mic->data_ptr, dp, len);
@@ -1066,7 +1145,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
err = mmcsd_set_blockcount(sc, mic->blocks,
mic->write_flag & (1 << 31));
if (err != MMC_ERR_NONE)
- goto release;
+ goto switch_back;
}
if (mic->is_acmd != 0)
(void)mmc_wait_for_app_cmd(mmcbr, dev, rca, &cmd, 0);
@@ -1088,6 +1167,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
DELAY(1000);
} while (retries-- > 0);
+switch_back:
/* ... and always switch back to the default partition. */
err = mmcsd_switch_part(mmcbr, dev, rca,
EXT_CSD_PART_CONFIG_ACC_DEFAULT);
@@ -1138,6 +1218,10 @@ release:
err = EIO;
out:
+ MMCSD_IOCTL_LOCK(part);
+ part->ioctl = 0;
+ MMCSD_IOCTL_UNLOCK(part);
+ wakeup(part);
if (dp != NULL)
free(dp, M_TEMP);
return (err);
@@ -1191,10 +1275,23 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part)
sc = device_get_softc(dev);
- if (sc->part_curr == part)
+ if (sc->mode == mode_sd)
return (MMC_ERR_NONE);
- if (sc->mode == mode_sd)
+ /*
+ * According to section "6.2.2 Command restrictions" of the eMMC
+ * specification v5.1, CMD19/CMD21 aren't allowed to be used with
+ * RPMB partitions. So we pause re-tuning along with triggering
+ * it up-front to decrease the likelihood of re-tuning becoming
+ * necessary while accessing an RPMB partition. Consequently, an
+ * RPMB partition should immediately be switched away from again
+ * after an access in order to allow for re-tuning to take place
+ * anew.
+ */
+ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_PAUSE(sc->mmcbr, sc->dev, true);
+
+ if (sc->part_curr == part)
return (MMC_ERR_NONE);
value = (sc->ext_csd[EXT_CSD_PART_CONFIG] &
@@ -1202,10 +1299,15 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part)
/* Jump! */
err = mmc_switch(bus, dev, rca, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, value, sc->part_time, true);
- if (err != MMC_ERR_NONE)
+ if (err != MMC_ERR_NONE) {
+ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev);
return (err);
+ }
sc->ext_csd[EXT_CSD_PART_CONFIG] = value;
+ if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev);
sc->part_curr = part;
return (MMC_ERR_NONE);
}
@@ -1217,7 +1319,7 @@ mmcsd_errmsg(int e)
if (e < 0 || e > MMC_ERR_MAX)
return "Bad error code";
- return errmsg[e];
+ return (errmsg[e]);
}
static daddr_t
@@ -1230,7 +1332,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
struct mmc_data data;
struct mmcsd_softc *sc;
device_t dev, mmcbr;
- int numblocks, sz;
+ u_int numblocks, sz;
char *vaddr;
sc = part->sc;
@@ -1242,7 +1344,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
end = bp->bio_pblkno + (bp->bio_bcount / sz);
while (block < end) {
vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
- numblocks = min(end - block, mmc_get_max_data(dev));
+ numblocks = min(end - block, sc->max_data);
memset(&req, 0, sizeof(req));
memset(&cmd, 0, sizeof(cmd));
memset(&stop, 0, sizeof(stop));
@@ -1262,7 +1364,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
cmd.opcode = MMC_WRITE_BLOCK;
}
cmd.arg = block;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.data = vaddr;
@@ -1302,7 +1404,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
struct mmc_request req;
struct mmcsd_softc *sc;
device_t dev, mmcbr;
- int erase_sector, sz;
+ u_int erase_sector, sz;
sc = part->sc;
dev = sc->dev;
@@ -1317,7 +1419,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
if (end >= part->eblock && end < part->eend)
end = part->eend;
/* Safe round to the erase sector boundaries. */
- erase_sector = mmc_get_erase_sector(dev);
+ erase_sector = sc->erase_sector;
start = block + erase_sector - 1; /* Round up. */
start -= start % erase_sector;
stop = end; /* Round down. */
@@ -1329,6 +1431,12 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
return (end);
}
+ /*
+ * Pause re-tuning so it won't interfere with the order of erase
+ * commands. Note that these latter don't use the data lines, so
+ * re-tuning shouldn't actually become necessary during erase.
+ */
+ MMCBUS_RETUNE_PAUSE(mmcbr, dev, false);
/* Set erase start position. */
memset(&req, 0, sizeof(req));
memset(&cmd, 0, sizeof(cmd));
@@ -1339,13 +1447,15 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
else
cmd.opcode = MMC_ERASE_GROUP_START;
cmd.arg = start;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err1: %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "Setting erase start position failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Set erase stop position. */
memset(&req, 0, sizeof(req));
@@ -1356,14 +1466,16 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
else
cmd.opcode = MMC_ERASE_GROUP_END;
cmd.arg = stop;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.arg--;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err2: %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "Setting erase stop position failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Erase range. */
memset(&req, 0, sizeof(req));
@@ -1374,8 +1486,11 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err3 %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "erase err3: %d\n", req.cmd->error);
+ device_printf(dev, "Issuing erase command failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Store one of remaining parts for the next call. */
if (bp->bio_pblkno >= part->eblock || block == start) {
@@ -1385,7 +1500,10 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
part->eblock = block; /* Predict next backward. */
part->eend = start;
}
- return (end);
+ block = end;
+unpause:
+ MMCBUS_RETUNE_UNPAUSE(mmcbr, dev);
+ return (block);
}
static int
@@ -1446,16 +1564,16 @@ mmcsd_task(void *arg)
mmcbr = sc->mmcbr;
while (1) {
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
do {
if (part->running == 0)
goto out;
bp = bioq_takefirst(&part->bio_queue);
if (bp == NULL)
- msleep(part, &part->part_mtx, PRIBIO,
- "jobqueue", 0);
+ msleep(part, &part->disk_mtx, PRIBIO,
+ "mmcsd disk jobqueue", 0);
} while (bp == NULL);
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
if (bp->bio_cmd != BIO_READ && part->ro) {
bp->bio_error = EROFS;
bp->bio_resid = bp->bio_bcount;
@@ -1496,7 +1614,7 @@ release:
out:
/* tell parent we're done */
part->running = -1;
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
wakeup(part);
kproc_exit(0);
diff --git a/freebsd/sys/dev/nvme/nvme.h b/freebsd/sys/dev/nvme/nvme.h
index ff64cb00..aa640b37 100644
--- a/freebsd/sys/dev/nvme/nvme.h
+++ b/freebsd/sys/dev/nvme/nvme.h
@@ -341,9 +341,11 @@ enum nvme_admin_opcode {
NVME_OPC_GET_FEATURES = 0x0a,
/* 0x0b - reserved */
NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c,
- /* 0x0d-0x0f - reserved */
+ NVME_OPC_NAMESPACE_MANAGEMENT = 0x0d,
+ /* 0x0e-0x0f - reserved */
NVME_OPC_FIRMWARE_ACTIVATE = 0x10,
NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11,
+ NVME_OPC_NAMESPACE_ATTACHMENT = 0x15,
NVME_OPC_FORMAT_NVM = 0x80,
NVME_OPC_SECURITY_SEND = 0x81,
@@ -456,7 +458,10 @@ struct nvme_controller_data {
/** maximum data transfer size */
uint8_t mdts;
- uint8_t reserved1[178];
+ /** Controller ID */
+ uint16_t ctrlr_id;
+
+ uint8_t reserved1[176];
/* bytes 256-511: admin command set attributes */
@@ -471,7 +476,10 @@ struct nvme_controller_data {
/* supports firmware activate/download commands */
uint16_t firmware : 1;
- uint16_t oacs_rsvd : 13;
+ /* supports namespace management commands */
+ uint16_t nsmgmt : 1;
+
+ uint16_t oacs_rsvd : 12;
} __packed oacs;
/** abort command limit */
@@ -513,8 +521,16 @@ struct nvme_controller_data {
uint8_t avscc_rsvd : 7;
} __packed avscc;
- uint8_t reserved2[247];
+ uint8_t reserved2[15];
+
+ /** Name space capabilities */
+ struct {
+ /* if nsmgmt, report tnvmcap and unvmcap */
+ uint8_t tnvmcap[16];
+ uint8_t unvmcap[16];
+ } __packed untncap;
+ uint8_t reserved3[200];
/* bytes 512-703: nvm command set attributes */
/** submission queue entry size */
@@ -529,7 +545,7 @@ struct nvme_controller_data {
uint8_t max : 4;
} __packed cqes;
- uint8_t reserved3[2];
+ uint8_t reserved4[2];
/** number of namespaces */
uint32_t nn;
@@ -555,10 +571,10 @@ struct nvme_controller_data {
} __packed vwc;
/* TODO: flesh out remaining nvm command set attributes */
- uint8_t reserved4[178];
+ uint8_t reserved5[178];
/* bytes 704-2047: i/o command set attributes */
- uint8_t reserved5[1344];
+ uint8_t reserved6[1344];
/* bytes 2048-3071: power state descriptors */
struct nvme_power_state power_state[32];
diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.c b/freebsd/sys/dev/rtwn/if_rtwn_rx.c
index 5dd72605..7b3f1c2e 100644
--- a/freebsd/sys/dev/rtwn/if_rtwn_rx.c
+++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.c
@@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/if_rtwn_rx.h>
#include <dev/rtwn/rtl8192c/r92c_reg.h>
-#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
void
@@ -192,7 +191,8 @@ rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id)
}
static uint64_t
-rtwn_extend_rx_tsf(struct rtwn_softc *sc, const struct r92c_rx_stat *stat)
+rtwn_extend_rx_tsf(struct rtwn_softc *sc,
+ const struct rtwn_rx_stat_common *stat)
{
uint64_t tsft;
uint32_t rxdw3, tsfl, tsfl_curr;
@@ -200,7 +200,7 @@ rtwn_extend_rx_tsf(struct rtwn_softc *sc, const struct r92c_rx_stat *stat)
rxdw3 = le32toh(stat->rxdw3);
tsfl = le32toh(stat->tsf_low);
- id = MS(rxdw3, R92C_RXDW3_BSSID_FIT);
+ id = MS(rxdw3, RTWN_RXDW3_BSSID01_FIT);
switch (id) {
case 1:
@@ -243,7 +243,7 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
struct ieee80211_frame_min *wh;
struct ieee80211_rx_stats rxs;
struct rtwn_node *un;
- struct r92c_rx_stat *stat;
+ struct rtwn_rx_stat_common *stat;
void *physt;
uint32_t rxdw0;
int8_t rssi;
@@ -252,10 +252,10 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
stat = desc;
rxdw0 = le32toh(stat->rxdw0);
- cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
- infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
- pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
- shift = MS(rxdw0, R92C_RXDW0_SHIFT);
+ cipher = MS(rxdw0, RTWN_RXDW0_CIPHER);
+ infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
+ pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
+ shift = MS(rxdw0, RTWN_RXDW0_SHIFT);
wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz));
if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
@@ -270,7 +270,7 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
ni = NULL;
un = RTWN_NODE(ni);
- if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST))
+ if (infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST))
physt = (void *)mtodo(m, shift);
else
physt = (un != NULL) ? &un->last_physt : &sc->last_physt;
@@ -286,7 +286,7 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
/* Add some common bits. */
/* NB: should not happen. */
- if (rxdw0 & R92C_RXDW0_CRCERR)
+ if (rxdw0 & RTWN_RXDW0_CRCERR)
rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC;
rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */
@@ -300,7 +300,7 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc)
/* XXX TODO: we really need a rate-to-string method */
RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, rate %d\n",
__func__, rssi, rxs.c_rate);
- if (un != NULL && infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
+ if (un != NULL && infosz != 0 && (rxdw0 & RTWN_RXDW0_PHYST)) {
/* Update our average RSSI. */
rtwn_update_avgrssi(sc, un, rssi, is_cck);
}
diff --git a/freebsd/sys/dev/rtwn/if_rtwnreg.h b/freebsd/sys/dev/rtwn/if_rtwnreg.h
index 9dc830a2..00903d88 100644
--- a/freebsd/sys/dev/rtwn/if_rtwnreg.h
+++ b/freebsd/sys/dev/rtwn/if_rtwnreg.h
@@ -18,6 +18,9 @@
* $FreeBSD$
*/
+#ifndef IF_RTWNREG_H
+#define IF_RTWNREG_H
+
#define R92C_MIN_TX_PWR 0x00
#define R92C_MAX_TX_PWR 0x3f
@@ -48,6 +51,55 @@ struct rtwn_tx_desc_common {
} txdw7;
} __packed __attribute__((aligned(4)));
+/* Common part of Rx descriptor. */
+struct rtwn_rx_stat_common {
+ uint32_t rxdw0;
+#define RTWN_RXDW0_PKTLEN_M 0x00003fff
+#define RTWN_RXDW0_PKTLEN_S 0
+#define RTWN_RXDW0_CRCERR 0x00004000
+#define RTWN_RXDW0_ICVERR 0x00008000
+#define RTWN_RXDW0_INFOSZ_M 0x000f0000
+#define RTWN_RXDW0_INFOSZ_S 16
+#define RTWN_RXDW0_CIPHER_M 0x00700000
+#define RTWN_RXDW0_CIPHER_S 20
+#define RTWN_RXDW0_QOS 0x00800000
+#define RTWN_RXDW0_SHIFT_M 0x03000000
+#define RTWN_RXDW0_SHIFT_S 24
+#define RTWN_RXDW0_PHYST 0x04000000
+#define RTWN_RXDW0_SWDEC 0x08000000
+#define RTWN_RXDW0_LS 0x10000000
+#define RTWN_RXDW0_FS 0x20000000
+#define RTWN_RXDW0_EOR 0x40000000
+#define RTWN_RXDW0_OWN 0x80000000
+
+ uint32_t rxdw1;
+#define RTWN_RXDW1_AMSDU 0x00002000
+#define RTWN_RXDW1_MC 0x40000000
+#define RTWN_RXDW1_BC 0x80000000
+
+ uint32_t rxdw2;
+ uint32_t rxdw3;
+#define RTWN_RXDW3_HTC 0x00000400
+#define RTWN_RXDW3_BSSID01_FIT_M 0x00003000
+#define RTWN_RXDW3_BSSID01_FIT_S 12
+
+ uint32_t rxdw4;
+ uint32_t tsf_low;
+} __packed __attribute__((aligned(4)));
+
+/* Rx descriptor for PCIe devices. */
+struct rtwn_rx_stat_pci {
+ uint32_t rxdw0;
+ uint32_t rxdw1;
+ uint32_t rxdw2;
+ uint32_t rxdw3;
+ uint32_t rxdw4;
+ uint32_t tsf_low;
+
+ uint32_t rxbufaddr;
+ uint32_t rxbufaddr64;
+} __packed __attribute__((aligned(4)));
+
/*
* Macros to access subfields in registers.
*/
@@ -116,3 +168,5 @@ rtwn_chan2centieee(const struct ieee80211_channel *c)
return (chan);
}
+
+#endif /* IF_RTWNREG_H */
diff --git a/freebsd/sys/dev/rtwn/if_rtwnvar.h b/freebsd/sys/dev/rtwn/if_rtwnvar.h
index d8754024..3ebcba52 100644
--- a/freebsd/sys/dev/rtwn/if_rtwnvar.h
+++ b/freebsd/sys/dev/rtwn/if_rtwnvar.h
@@ -25,8 +25,6 @@
#define RTWN_TX_DESC_SIZE 64
-#define RTWN_TXBUFSZ (16 * 1024)
-
#define RTWN_BCN_MAX_SIZE 512
#define RTWN_CAM_ENTRY_LIMIT 64
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
index 85ede40a..c121c5a5 100644
--- a/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_attach.c
@@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/pci/rtwn_pci_tx.h>
#include <dev/rtwn/rtl8192c/pci/r92ce_reg.h>
-#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
static device_probe_t rtwn_pci_probe;
@@ -135,7 +134,7 @@ rtwn_pci_alloc_rx_list(struct rtwn_softc *sc)
int i, error;
/* Allocate Rx descriptors. */
- size = sizeof(struct r92ce_rx_stat) * RTWN_PCI_RX_LIST_COUNT;
+ size = sizeof(struct rtwn_rx_stat_pci) * RTWN_PCI_RX_LIST_COUNT;
error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat);
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
index 150500d8..1934b741 100644
--- a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.c
@@ -58,8 +58,6 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/pci/rtwn_pci_var.h>
#include <dev/rtwn/pci/rtwn_pci_rx.h>
-#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
-
void
rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs,
@@ -73,21 +71,21 @@ rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs,
}
void
-rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, struct r92ce_rx_stat *desc,
- bus_addr_t addr, size_t len, int idx)
+rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc,
+ struct rtwn_rx_stat_pci *desc, bus_addr_t addr, size_t len, int idx)
{
memset(desc, 0, sizeof(*desc));
- desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) |
- ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0));
+ desc->rxdw0 = htole32(SM(RTWN_RXDW0_PKTLEN, len) |
+ ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? RTWN_RXDW0_EOR : 0));
desc->rxbufaddr = htole32(addr);
bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize,
BUS_SPACE_BARRIER_WRITE);
- desc->rxdw0 |= htole32(R92C_RXDW0_OWN);
+ desc->rxdw0 |= htole32(RTWN_RXDW0_OWN);
}
static void
-rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc,
+rtwn_pci_rx_frame(struct rtwn_softc *sc, struct rtwn_rx_stat_pci *rx_desc,
int desc_idx)
{
struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc);
@@ -109,18 +107,18 @@ rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc,
le32toh(rx_desc->rxbufaddr), le32toh(rx_desc->rxbufaddr64));
rxdw0 = le32toh(rx_desc->rxdw0);
- if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
+ if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) {
/*
* This should not happen since we setup our Rx filter
* to not receive these frames.
*/
RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
"%s: RX flags error (%s)\n", __func__,
- rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
+ rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV");
goto fail;
}
- pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+ pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) ||
pktlen > MJUMPAGESIZE)) {
RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
@@ -128,8 +126,8 @@ rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc,
goto fail;
}
- infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
- shift = MS(rxdw0, R92C_RXDW0_SHIFT);
+ infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
+ shift = MS(rxdw0, RTWN_RXDW0_SHIFT);
m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
if (__predict_false(m1 == NULL)) {
@@ -270,9 +268,9 @@ rtwn_pci_rx_done(struct rtwn_softc *sc)
bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD);
for (;;) {
- struct r92ce_rx_stat *rx_desc = &ring->desc[ring->cur];
+ struct rtwn_rx_stat_pci *rx_desc = &ring->desc[ring->cur];
- if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN)
+ if (le32toh(rx_desc->rxdw0) & RTWN_RXDW0_OWN)
break;
rtwn_pci_rx_frame(sc, rx_desc, ring->cur);
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
index 265d32d8..30dd785a 100644
--- a/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_rx.h
@@ -21,7 +21,7 @@
void rtwn_pci_dma_map_addr(void *, bus_dma_segment_t *, int, int);
void rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *,
- struct r92ce_rx_stat *, bus_addr_t, size_t, int);
+ struct rtwn_rx_stat_pci *, bus_addr_t, size_t, int);
void rtwn_pci_intr(void *);
#endif /* RTWN_PCI_RX_H */
diff --git a/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
index 5a9e64e7..194fab4a 100644
--- a/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
+++ b/freebsd/sys/dev/rtwn/pci/rtwn_pci_var.h
@@ -23,9 +23,6 @@
#ifndef RTWN_PCI_VAR_H
#define RTWN_PCI_VAR_H
-#include <dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h>
-
-
#define RTWN_PCI_RX_LIST_COUNT 256
#define RTWN_PCI_TX_LIST_COUNT 256
@@ -36,7 +33,7 @@ struct rtwn_rx_data {
};
struct rtwn_rx_ring {
- struct r92ce_rx_stat *desc;
+ struct rtwn_rx_stat_pci *desc;
bus_addr_t paddr;
bus_dma_tag_t desc_dmat;
bus_dmamap_t desc_map;
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
index fe9d58b7..903398a4 100644
--- a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c
@@ -91,8 +91,7 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain,
{
struct r92c_softc *rs = sc->sc_priv;
const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr;
- const struct rtwn_r88e_txagc *base = rs->rs_txagc;
- uint16_t cckpow, ofdmpow, bw20pow, htpow;
+ uint8_t cckpow, ofdmpow, bw20pow, htpow = 0;
int max_mcs, ridx, group;
/* Determine channel group. */
@@ -108,35 +107,24 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain,
KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n"));
memset(power, 0, max_mcs * sizeof(power[0]));
- if (rs->regulatory == 0) {
- for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
- power[ridx] = base->pwr[0][ridx];
- }
- for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) {
- if (rs->regulatory == 3)
- power[ridx] = base->pwr[0][ridx];
- else if (rs->regulatory == 1) {
- if (!IEEE80211_IS_CHAN_HT40(c))
- power[ridx] = base->pwr[group][ridx];
- } else if (rs->regulatory != 2)
- power[ridx] = base->pwr[0][ridx];
- }
/* Compute per-CCK rate Tx power. */
cckpow = rt->cck_tx_pwr[group];
- for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++)
- power[ridx] += cckpow;
+ for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) {
+ power[ridx] = (ridx == RTWN_RIDX_CCK2) ? cckpow - 9 : cckpow;
+ }
- htpow = rt->ht40_tx_pwr[group];
+ if (group < 5)
+ htpow = rt->ht40_tx_pwr[group];
/* Compute per-OFDM rate Tx power. */
ofdmpow = htpow + rt->ofdm_tx_pwr_diff;
for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++)
- power[ridx] += ofdmpow;
+ power[ridx] = ofdmpow;
bw20pow = htpow + rt->bw20_tx_pwr_diff;
for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++)
- power[ridx] += bw20pow;
+ power[ridx] = bw20pow;
/* Apply max limit. */
for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) {
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
index cb4f7edb..28f4b1fb 100644
--- a/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_priv.h
@@ -227,47 +227,4 @@ static const struct rtwn_rf_prog rtl8188eu_rf[] = {
{ 0, NULL, NULL, { 0 }, NULL }
};
-
-struct rtwn_r88e_txagc {
- uint8_t pwr[R88E_GROUP_2G][20]; /* RTWN_RIDX_MCS(7) + 1 */
-};
-
-/*
- * Per RF chain/group/rate Tx gain values.
- */
-static const struct rtwn_r88e_txagc r88e_txagc[] = {
- { { /* Chain 0. */
- { /* Group 0. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- },
- { /* Group 1. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- },
- { /* Group 2. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- },
- { /* Group 3. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- },
- { /* Group 4. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- },
- { /* Group 5. */
- 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */
- }
- } }
-};
-
#endif /* R88E_PRIV_H */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
index 5734246f..c6033678 100644
--- a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h
@@ -23,7 +23,7 @@
#define R88E_GROUP_2G 6
-#define R88E_EFUSE_MAX_LEN 512
+#define R88E_EFUSE_MAX_LEN 256
#define R88E_EFUSE_MAP_LEN 512
#endif /* R88E_ROM_DEFS_H */
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
index 88159876..856ec88b 100644
--- a/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
+++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_rx.c
@@ -223,7 +223,7 @@ r88e_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
if (!sc->sc_ht40) { /* XXX center channel */
rxs->r_flags |= IEEE80211_R_IEEE | IEEE80211_R_FREQ;
- rxs->c_ieee = le16toh(physt->chan);
+ rxs->c_ieee = physt->chan;
rxs->c_freq = ieee80211_ieee2mhz(rxs->c_ieee,
IEEE80211_CHAN_2GHZ);
}
diff --git a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
index f5ac1d9d..73cc7856 100644
--- a/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
+++ b/freebsd/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
@@ -87,7 +87,7 @@ r88eu_attach_private(struct rtwn_softc *sc)
rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO);
rs->rs_txpwr = &r88e_txpwr;
- rs->rs_txagc = &r88e_txagc;
+ rs->rs_txagc = NULL;
rs->rs_set_bw20 = r88e_set_bw20;
rs->rs_get_txpower = r88e_get_txpower;
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
index 304324e6..5c2880bb 100644
--- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rom_image.h
@@ -48,7 +48,7 @@ struct r92c_rom {
uint8_t ofdm_tx_pwr_diff[R92C_GROUP_2G];
uint8_t ht40_max_pwr[R92C_GROUP_2G];
uint8_t ht20_max_pwr[R92C_GROUP_2G];
- uint8_t xtal_calib;
+ uint8_t channel_plan;
uint8_t tssi[R92C_MAX_CHAINS];
uint8_t thermal_meter;
#define R92C_ROM_THERMAL_METER_M 0x1f
@@ -58,9 +58,7 @@ struct r92c_rom {
uint8_t rf_opt2;
uint8_t rf_opt3;
uint8_t rf_opt4;
- uint8_t channel_plan;
-#define R92C_CHANNEL_PLAN_BY_HW 0x80
-
+ uint8_t reserved5;
uint8_t version;
uint8_t customer_id;
} __packed;
diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
index 454da87c..c2a6eab0 100644
--- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
+++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c
@@ -333,8 +333,6 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
if (m->m_flags & M_AMPDU_MPDU) {
seqno = ni->ni_txseqs[tid];
- /* NB: clear Fragment Number field. */
- *(uint16_t *)wh->i_seq = 0;
ni->ni_txseqs[tid]++;
} else
seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
index c5a9e465..895f71e4 100644
--- a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
+++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c
@@ -340,8 +340,6 @@ r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
if (m->m_flags & M_AMPDU_MPDU) {
seqno = ni->ni_txseqs[tid];
- /* NB: clear Fragment Number field. */
- *(uint16_t *)wh->i_seq = 0;
ni->ni_txseqs[tid]++;
} else
seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE;
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
index 93e1f768..8626d0a3 100644
--- a/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_attach.c
@@ -79,12 +79,14 @@ static void rtwn_usb_reset_lists(struct rtwn_softc *,
struct ieee80211vap *);
static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *,
rtwn_datahead *, struct ieee80211vap *);
+static void rtwn_usb_reset_rx_list(struct rtwn_usb_softc *);
static void rtwn_usb_start_xfers(struct rtwn_softc *);
static void rtwn_usb_abort_xfers(struct rtwn_softc *);
static int rtwn_usb_fw_write_block(struct rtwn_softc *,
const uint8_t *, uint16_t, int);
static void rtwn_usb_drop_incorrect_tx(struct rtwn_softc *);
static void rtwn_usb_attach_methods(struct rtwn_softc *);
+static void rtwn_usb_sysctlattach(struct rtwn_softc *);
#define RTWN_CONFIG_INDEX 0
@@ -135,9 +137,8 @@ rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
int error, i;
- /* XXX recheck */
error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
- sc->rx_dma_size + 1024);
+ uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT);
if (error != 0)
return (error);
@@ -157,7 +158,7 @@ rtwn_usb_alloc_tx_list(struct rtwn_softc *sc)
int error, i;
error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT,
- RTWN_TXBUFSZ);
+ RTWN_USB_TXBUFSZ);
if (error != 0)
return (error);
@@ -201,6 +202,9 @@ rtwn_usb_free_rx_list(struct rtwn_softc *sc)
rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT);
+ uc->uc_rx_stat_len = 0;
+ uc->uc_rx_off = 0;
+
STAILQ_INIT(&uc->uc_rx_active);
STAILQ_INIT(&uc->uc_rx_inactive);
}
@@ -226,8 +230,10 @@ rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap)
rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap);
rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap);
- if (vap == NULL)
+ if (vap == NULL) {
+ rtwn_usb_reset_rx_list(uc);
sc->qfullmsk = 0;
+ }
}
static void
@@ -261,6 +267,23 @@ rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc,
}
static void
+rtwn_usb_reset_rx_list(struct rtwn_usb_softc *uc)
+{
+ int i;
+
+ for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) {
+ struct rtwn_data *dp = &uc->uc_rx[i];
+
+ if (dp->m != NULL) {
+ m_freem(dp->m);
+ dp->m = NULL;
+ }
+ }
+ uc->uc_rx_stat_len = 0;
+ uc->uc_rx_off = 0;
+}
+
+static void
rtwn_usb_start_xfers(struct rtwn_softc *sc)
{
struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
@@ -329,6 +352,31 @@ rtwn_usb_attach_methods(struct rtwn_softc *sc)
sc->bcn_check_interval = 100;
}
+static void
+rtwn_usb_sysctlattach(struct rtwn_softc *sc)
+{
+ struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+ char str[64];
+ int ret;
+
+ ret = snprintf(str, sizeof(str),
+ "Rx buffer size, 512-byte units [%d...%d]",
+ RTWN_USB_RXBUFSZ_MIN, RTWN_USB_RXBUFSZ_MAX);
+ KASSERT(ret > 0, ("ret (%d) <= 0!\n", ret));
+ (void) ret;
+
+ uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_DEF;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "rx_buf_size", CTLFLAG_RDTUN, &uc->uc_rx_buf_size,
+ uc->uc_rx_buf_size, str);
+ if (uc->uc_rx_buf_size < RTWN_USB_RXBUFSZ_MIN)
+ uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN;
+ if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX)
+ uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX;
+}
+
static int
rtwn_usb_attach(device_t self)
{
@@ -345,6 +393,7 @@ rtwn_usb_attach(device_t self)
/* Need to be initialized early. */
rtwn_sysctlattach(sc);
+ rtwn_usb_sysctlattach(sc);
mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF);
rtwn_usb_attach_methods(sc);
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
index ef7d1ffc..f56e96c0 100644
--- a/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_ep.c
@@ -75,7 +75,7 @@ static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = RTWN_TXBUFSZ,
+ .bufsize = RTWN_USB_TXBUFSZ,
.flags = {
.ext_buffer = 1,
.pipe_bof = 1,
@@ -88,7 +88,7 @@ static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = RTWN_TXBUFSZ,
+ .bufsize = RTWN_USB_TXBUFSZ,
.flags = {
.ext_buffer = 1,
.pipe_bof = 1,
@@ -101,7 +101,7 @@ static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = RTWN_TXBUFSZ,
+ .bufsize = RTWN_USB_TXBUFSZ,
.flags = {
.ext_buffer = 1,
.pipe_bof = 1,
@@ -114,7 +114,7 @@ static const struct usb_config rtwn_config_common[RTWN_N_TRANSFER] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
- .bufsize = RTWN_TXBUFSZ,
+ .bufsize = RTWN_USB_TXBUFSZ,
.flags = {
.ext_buffer = 1,
.pipe_bof = 1,
@@ -227,7 +227,8 @@ rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc)
break;
}
- rtwn_config[RTWN_BULK_RX].bufsize = sc->rx_dma_size + 1024;
+ rtwn_config[RTWN_BULK_RX].bufsize =
+ uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT;
error = usbd_transfer_setup(uc->uc_udev, &iface_index,
uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx);
free(rtwn_config, M_TEMP);
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
index 4f39b580..9de8fca4 100644
--- a/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_rx.c
@@ -65,57 +65,69 @@ __FBSDID("$FreeBSD$");
#include <dev/rtwn/usb/rtwn_usb_var.h>
#include <dev/rtwn/usb/rtwn_usb_rx.h>
-#include <dev/rtwn/rtl8192c/r92c_reg.h> /* for CAM_ALGO_NONE */
-#include <dev/rtwn/rtl8192c/r92c_rx_desc.h>
+static struct mbuf * rtwn_rxeof(struct rtwn_softc *, struct rtwn_data *,
+ uint8_t *, int);
-
-static struct mbuf *
-rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *stat,
- int totlen)
+static int
+rtwn_rx_check_pre_alloc(struct rtwn_softc *sc,
+ struct rtwn_rx_stat_common *stat)
{
- struct ieee80211com *ic = &sc->sc_ic;
- struct mbuf *m;
uint32_t rxdw0;
int pktlen;
RTWN_ASSERT_LOCKED(sc);
- /* Dump Rx descriptor. */
- RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
- "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n",
- __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1),
- le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4),
- le32toh(stat->tsf_low));
-
/*
* don't pass packets to the ieee80211 framework if the driver isn't
* RUNNING.
*/
if (!(sc->sc_flags & RTWN_RUNNING))
- return (NULL);
+ return (-1);
rxdw0 = le32toh(stat->rxdw0);
- if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) {
+ if (__predict_false(rxdw0 & (RTWN_RXDW0_CRCERR | RTWN_RXDW0_ICVERR))) {
/*
* This should not happen since we setup our Rx filter
* to not receive these frames.
*/
RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
"%s: RX flags error (%s)\n", __func__,
- rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV");
- goto fail;
+ rxdw0 & RTWN_RXDW0_CRCERR ? "CRC" : "ICV");
+ return (-1);
}
- pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+ pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) {
/*
* Should not happen (because of Rx filter setup).
*/
RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
"%s: frame is too short: %d\n", __func__, pktlen);
- goto fail;
+ return (-1);
}
+ return (0);
+}
+
+static struct mbuf *
+rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct rtwn_rx_stat_common *stat,
+ int totlen)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct mbuf *m;
+
+ RTWN_ASSERT_LOCKED(sc);
+
+ /* Dump Rx descriptor. */
+ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
+ "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n",
+ __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1),
+ le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4),
+ le32toh(stat->tsf_low));
+
+ if (rtwn_rx_check_pre_alloc(sc, stat) != 0)
+ goto fail;
+
m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR);
if (__predict_false(m == NULL)) {
device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n",
@@ -139,30 +151,124 @@ fail:
}
static struct mbuf *
-rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len)
+rtwn_rxeof_fragmented(struct rtwn_usb_softc *uc, struct rtwn_data *data,
+ uint8_t *buf, int len)
+{
+ struct rtwn_softc *sc = &uc->uc_sc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct rtwn_rx_stat_common *stat = &uc->uc_rx_stat;
+ uint32_t rxdw0;
+ int totlen, pktlen, infosz, min_len;
+ int orig_len = len;
+ int alloc_mbuf = 0;
+
+ /* Check if Rx descriptor is not truncated. */
+ if (uc->uc_rx_stat_len < sizeof(*stat)) {
+ min_len = min(sizeof(*stat) - uc->uc_rx_stat_len, len);
+ memcpy((uint8_t *)stat + uc->uc_rx_stat_len, buf, min_len);
+
+ uc->uc_rx_stat_len += min_len;
+ buf += min_len;
+ len -= min_len;
+
+ if (uc->uc_rx_stat_len < sizeof(*stat))
+ goto end;
+
+ KASSERT(data->m == NULL, ("%s: data->m != NULL!\n", __func__));
+ alloc_mbuf = 1;
+
+ /* Dump Rx descriptor. */
+ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC,
+ "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, "
+ "tsfl %08X\n", __func__, le32toh(stat->rxdw0),
+ le32toh(stat->rxdw1), le32toh(stat->rxdw2),
+ le32toh(stat->rxdw3), le32toh(stat->rxdw4),
+ le32toh(stat->tsf_low));
+ }
+
+ rxdw0 = le32toh(stat->rxdw0);
+ pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
+ infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
+ totlen = sizeof(*stat) + infosz + pktlen;
+ if (alloc_mbuf) {
+ if (rtwn_rx_check_pre_alloc(sc, stat) == 0) {
+ data->m = m_getm(NULL, totlen, M_NOWAIT, MT_DATA);
+ if (data->m != NULL) {
+ m_copyback(data->m, 0, uc->uc_rx_stat_len,
+ (caddr_t)stat);
+
+ if (rtwn_check_frame(sc, data->m) != 0) {
+ m_freem(data->m);
+ data->m = NULL;
+ counter_u64_add(ic->ic_ierrors, 1);
+ }
+ } else
+ counter_u64_add(ic->ic_ierrors, 1);
+ } else
+ counter_u64_add(ic->ic_ierrors, 1);
+
+ uc->uc_rx_off = sizeof(*stat);
+ }
+
+ /* If mbuf allocation fails just discard the data. */
+ min_len = min(totlen - uc->uc_rx_off, len);
+ if (data->m != NULL)
+ m_copyback(data->m, uc->uc_rx_off, min_len, buf);
+
+ uc->uc_rx_off += min_len;
+ if (uc->uc_rx_off == totlen) {
+ /* Align next frame. */
+ min_len = rtwn_usb_align_rx(uc,
+ orig_len - len + min_len, orig_len);
+ min_len -= (orig_len - len);
+ KASSERT(len >= min_len, ("%s: len (%d) < min_len (%d)!\n",
+ __func__, len, min_len));
+
+ /* Clear mbuf stats. */
+ uc->uc_rx_stat_len = 0;
+ uc->uc_rx_off = 0;
+ }
+ len -= min_len;
+ buf += min_len;
+end:
+ if (uc->uc_rx_stat_len == 0)
+ return (rtwn_rxeof(sc, data, buf, len));
+ else
+ return (NULL);
+}
+
+static struct mbuf *
+rtwn_rxeof(struct rtwn_softc *sc, struct rtwn_data *data, uint8_t *buf,
+ int len)
{
struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
- struct r92c_rx_stat *stat;
+ struct rtwn_rx_stat_common *stat;
struct mbuf *m, *m0 = NULL;
uint32_t rxdw0;
int totlen, pktlen, infosz;
+ /* Prepend defragmented frame (if any). */
+ if (data->m != NULL) {
+ m0 = m = data->m;
+ data->m = NULL;
+ }
+
/* Process packets. */
while (len >= sizeof(*stat)) {
- stat = (struct r92c_rx_stat *)buf;
+ stat = (struct rtwn_rx_stat_common *)buf;
rxdw0 = le32toh(stat->rxdw0);
- pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN);
+ pktlen = MS(rxdw0, RTWN_RXDW0_PKTLEN);
if (__predict_false(pktlen == 0))
break;
- infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
+ infosz = MS(rxdw0, RTWN_RXDW0_INFOSZ) * 8;
/* Make sure everything fits in xfer. */
totlen = sizeof(*stat) + infosz + pktlen;
if (totlen > len) {
- device_printf(sc->sc_dev,
- "%s: totlen (%d) > len (%d)!\n",
+ RTWN_DPRINTF(sc, RTWN_DEBUG_RECV,
+ "%s: frame is fragmented (totlen %d len %d)\n",
__func__, totlen, len);
break;
}
@@ -170,9 +276,9 @@ rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len)
if (m0 == NULL)
m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
else {
- m->m_next = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
- if (m->m_next != NULL)
- m = m->m_next;
+ m->m_nextpkt = rtwn_rx_copy_to_mbuf(sc, stat, totlen);
+ if (m->m_nextpkt != NULL)
+ m = m->m_nextpkt;
}
/* Align next frame. */
@@ -181,6 +287,9 @@ rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len)
len -= totlen;
}
+ if (len > 0)
+ (void)rtwn_rxeof_fragmented(uc, data, buf, len);
+
return (m0);
}
@@ -195,15 +304,19 @@ rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer,
usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
- if (__predict_false(len < sizeof(struct r92c_rx_stat))) {
+ if (__predict_false(len < sizeof(struct rtwn_rx_stat_common) &&
+ uc->uc_rx_stat_len == 0)) {
counter_u64_add(ic->ic_ierrors, 1);
return (NULL);
}
buf = data->buf;
+ if (uc->uc_rx_stat_len > 0)
+ return (rtwn_rxeof_fragmented(uc, data, data->buf, len));
+
switch (rtwn_classify_intr(sc, buf, len)) {
case RTWN_RX_DATA:
- return (rtwn_rxeof(sc, buf, len));
+ return (rtwn_rxeof(sc, data, buf, len));
case RTWN_RX_TX_REPORT:
if (sc->sc_ratectl != RTWN_RATECTL_NET80211) {
/* shouldn't happen */
@@ -240,11 +353,11 @@ rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer,
static struct ieee80211_node *
rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m)
{
- struct r92c_rx_stat stat;
+ struct rtwn_rx_stat_common stat;
/* Imitate PCIe layout. */
- m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat);
- m_adj(m, sizeof(struct r92c_rx_stat));
+ m_copydata(m, 0, sizeof(stat), (caddr_t)&stat);
+ m_adj(m, sizeof(stat));
return (rtwn_rx_common(sc, m, &stat));
}
@@ -289,8 +402,8 @@ tr_setup:
* callback and safe to unlock.
*/
while (m != NULL) {
- next = m->m_next;
- m->m_next = NULL;
+ next = m->m_nextpkt;
+ m->m_nextpkt = NULL;
ni = rtwn_rx_frame(sc, m);
@@ -314,6 +427,8 @@ tr_setup:
STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next);
}
if (error != USB_ERR_CANCELLED) {
+ /* XXX restart device if frame was fragmented? */
+
usbd_xfer_set_stall(xfer);
counter_u64_add(ic->ic_ierrors, 1);
goto tr_setup;
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
index 7bede4dc..61f0ba43 100644
--- a/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_tx.c
@@ -235,6 +235,9 @@ rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni,
RTWN_ASSERT_LOCKED(sc);
+ if (m->m_pkthdr.len + sc->txdesc_len > RTWN_USB_TXBUFSZ)
+ return (EINVAL);
+
data = rtwn_usb_getbuf(uc);
if (data == NULL)
return (ENOBUFS);
diff --git a/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
index be7f8f19..7ef21463 100644
--- a/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
+++ b/freebsd/sys/dev/rtwn/usb/rtwn_usb_var.h
@@ -21,6 +21,14 @@
#ifndef RTWN_USBVAR_H
#define RTWN_USBVAR_H
+#include <dev/rtwn/if_rtwnreg.h> /* for struct rtwn_rx_stat_common */
+
+#define RTWN_USB_RXBUFSZ_UNIT (512)
+#define RTWN_USB_RXBUFSZ_MIN ( 4)
+#define RTWN_USB_RXBUFSZ_DEF (24)
+#define RTWN_USB_RXBUFSZ_MAX (64)
+#define RTWN_USB_TXBUFSZ (16 * 1024)
+
#define RTWN_IFACE_INDEX 0
#define RTWN_USB_RX_LIST_COUNT 1
@@ -56,6 +64,12 @@ struct rtwn_usb_softc {
struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT];
rtwn_datahead uc_rx_active;
rtwn_datahead uc_rx_inactive;
+ int uc_rx_buf_size;
+
+ struct rtwn_rx_stat_common uc_rx_stat;
+ int uc_rx_stat_len;
+ int uc_rx_off;
+
struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT];
rtwn_datahead uc_tx_active;
rtwn_datahead uc_tx_inactive;
diff --git a/freebsd/sys/dev/sdhci/sdhci.c b/freebsd/sys/dev/sdhci/sdhci.c
index c87199a8..f1616a6e 100644
--- a/freebsd/sys/dev/sdhci/sdhci.c
+++ b/freebsd/sys/dev/sdhci/sdhci.c
@@ -2,6 +2,7 @@
/*-
* Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
+ * Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +35,9 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/kobj.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <rtems/bsd/sys/resource.h>
@@ -50,13 +53,22 @@ __FBSDID("$FreeBSD$");
#include <dev/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
+#include <dev/sdhci/sdhci.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+
#include <rtems/bsd/local/mmcbr_if.h>
-#include "sdhci.h"
#include <rtems/bsd/local/sdhci_if.h>
+#include <rtems/bsd/local/opt_mmccam.h>
+
SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
-static int sdhci_debug;
+static int sdhci_debug = 0;
SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0,
"Debug level");
u_int sdhci_quirk_clear = 0;
@@ -78,17 +90,30 @@ SYSCTL_INT(_hw_sdhci, OID_AUTO, quirk_set, CTLFLAG_RWTUN, &sdhci_quirk_set, 0,
#define WR_MULTI_4(slot, off, ptr, count) \
SDHCI_WRITE_MULTI_4((slot)->bus, (slot), (off), (ptr), (count))
+static void sdhci_card_poll(void *arg);
+static void sdhci_card_task(void *arg, int pending);
+static int sdhci_exec_tuning(struct sdhci_slot *slot, bool reset);
+static void sdhci_req_wakeup(struct mmc_request *req);
+static void sdhci_retune(void *arg);
static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock);
static void sdhci_start(struct sdhci_slot *slot);
static void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data);
-static void sdhci_card_poll(void *);
-static void sdhci_card_task(void *, int);
+#ifdef MMCCAM
+/* CAM-related */
+int sdhci_cam_get_possible_host_clock(struct sdhci_slot *slot, int proposed_clock);
+static int sdhci_cam_update_ios(struct sdhci_slot *slot);
+static int sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb);
+static void sdhci_cam_action(struct cam_sim *sim, union ccb *ccb);
+static void sdhci_cam_poll(struct cam_sim *sim);
+static int sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb);
+#endif
/* helper routines */
static void sdhci_dumpregs(struct sdhci_slot *slot);
static int slot_printf(struct sdhci_slot *slot, const char * fmt, ...)
__printflike(2, 3);
+static uint32_t sdhci_tuning_intmask(struct sdhci_slot *slot);
#define SDHCI_LOCK(_slot) mtx_lock(&(_slot)->mtx)
#define SDHCI_UNLOCK(_slot) mtx_unlock(&(_slot)->mtx)
@@ -169,13 +194,13 @@ sdhci_dumpregs(struct sdhci_slot *slot)
RD1(slot, SDHCI_TIMEOUT_CONTROL), RD4(slot, SDHCI_INT_STATUS));
slot_printf(slot, "Int enab: 0x%08x | Sig enab: 0x%08x\n",
RD4(slot, SDHCI_INT_ENABLE), RD4(slot, SDHCI_SIGNAL_ENABLE));
- slot_printf(slot, "AC12 err: 0x%08x | Host ctl2: 0x%08x\n",
+ slot_printf(slot, "AC12 err: 0x%08x | Host ctl2:0x%08x\n",
RD2(slot, SDHCI_ACMD12_ERR), RD2(slot, SDHCI_HOST_CONTROL2));
slot_printf(slot, "Caps: 0x%08x | Caps2: 0x%08x\n",
RD4(slot, SDHCI_CAPABILITIES), RD4(slot, SDHCI_CAPABILITIES2));
slot_printf(slot, "Max curr: 0x%08x | ADMA err: 0x%08x\n",
RD4(slot, SDHCI_MAX_CURRENT), RD1(slot, SDHCI_ADMA_ERR));
- slot_printf(slot, "ADMA addr: 0x%08x | Slot int: 0x%08x\n",
+ slot_printf(slot, "ADMA addr:0x%08x | Slot int: 0x%08x\n",
RD4(slot, SDHCI_ADMA_ADDRESS_LO), RD2(slot, SDHCI_SLOT_INT_STATUS));
slot_printf(slot,
@@ -242,6 +267,21 @@ sdhci_reset(struct sdhci_slot *slot, uint8_t mask)
}
}
+static uint32_t
+sdhci_tuning_intmask(struct sdhci_slot *slot)
+{
+ uint32_t intmask;
+
+ intmask = 0;
+ if (slot->opt & SDHCI_TUNING_SUPPORTED) {
+ intmask |= SDHCI_INT_TUNEERR;
+ if (slot->retune_mode == SDHCI_RETUNE_MODE_2 ||
+ slot->retune_mode == SDHCI_RETUNE_MODE_3)
+ intmask |= SDHCI_INT_RETUNE;
+ }
+ return (intmask);
+}
+
static void
sdhci_init(struct sdhci_slot *slot)
{
@@ -261,7 +301,7 @@ sdhci_init(struct sdhci_slot *slot)
slot->intmask |= SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT;
}
- WR4(slot, SDHCI_INT_ENABLE, slot->intmask);
+ WR4(slot, SDHCI_INT_ENABLE, slot->intmask | sdhci_tuning_intmask(slot));
WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
}
@@ -368,6 +408,7 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
static void
sdhci_set_power(struct sdhci_slot *slot, u_char power)
{
+ int i;
uint8_t pwr;
if (slot->power == power)
@@ -396,9 +437,20 @@ sdhci_set_power(struct sdhci_slot *slot, u_char power)
break;
}
WR1(slot, SDHCI_POWER_CONTROL, pwr);
- /* Turn on the power. */
+ /*
+ * Turn on VDD1 power. Note that at least some Intel controllers can
+ * fail to enable bus power on the first try after transiting from D3
+ * to D0, so we give them up to 2 ms.
+ */
pwr |= SDHCI_POWER_ON;
- WR1(slot, SDHCI_POWER_CONTROL, pwr);
+ for (i = 0; i < 20; i++) {
+ WR1(slot, SDHCI_POWER_CONTROL, pwr);
+ if (RD1(slot, SDHCI_POWER_CONTROL) & SDHCI_POWER_ON)
+ break;
+ DELAY(100);
+ }
+ if (!(RD1(slot, SDHCI_POWER_CONTROL) & SDHCI_POWER_ON))
+ slot_printf(slot, "Bus power failed to enable");
if (slot->quirks & SDHCI_QUIRK_INTEL_POWER_UP_RESET) {
WR1(slot, SDHCI_POWER_CONTROL, pwr | 0x10);
@@ -521,25 +573,93 @@ sdhci_card_task(void *arg, int pending __unused)
SDHCI_LOCK(slot);
if (SDHCI_GET_CARD_PRESENT(slot->bus, slot)) {
+#ifdef MMCCAM
+ if (slot->card_present == 0) {
+#else
if (slot->dev == NULL) {
+#endif
/* If card is present - attach mmc bus. */
if (bootverbose || sdhci_debug)
slot_printf(slot, "Card inserted\n");
- slot->dev = device_add_child(slot->bus, "mmc", -1);
- device_set_ivars(slot->dev, slot);
+#ifdef MMCCAM
+ slot->card_present = 1;
+ union ccb *ccb;
+ uint32_t pathid;
+ pathid = cam_sim_path(slot->sim);
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ slot_printf(slot, "Unable to alloc CCB for rescan\n");
+ SDHCI_UNLOCK(slot);
+ return;
+ }
+
+ /*
+ * We create a rescan request for BUS:0:0, since the card
+ * will be at lun 0.
+ */
+ if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
+ /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) {
+ slot_printf(slot, "Unable to create path for rescan\n");
+ SDHCI_UNLOCK(slot);
+ xpt_free_ccb(ccb);
+ return;
+ }
+ SDHCI_UNLOCK(slot);
+ xpt_rescan(ccb);
+#else
+ d = slot->dev = device_add_child(slot->bus, "mmc", -1);
SDHCI_UNLOCK(slot);
- device_probe_and_attach(slot->dev);
+ if (d) {
+ device_set_ivars(d, slot);
+ (void)device_probe_and_attach(d);
+ }
+#endif
} else
SDHCI_UNLOCK(slot);
} else {
+#ifdef MMCCAM
+ if (slot->card_present == 1) {
+#else
if (slot->dev != NULL) {
+#endif
/* If no card present - detach mmc bus. */
if (bootverbose || sdhci_debug)
slot_printf(slot, "Card removed\n");
d = slot->dev;
slot->dev = NULL;
+#ifdef MMCCAM
+ slot->card_present = 0;
+ union ccb *ccb;
+ uint32_t pathid;
+ pathid = cam_sim_path(slot->sim);
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ slot_printf(slot, "Unable to alloc CCB for rescan\n");
+ SDHCI_UNLOCK(slot);
+ return;
+ }
+
+ /*
+ * We create a rescan request for BUS:0:0, since the card
+ * will be at lun 0.
+ */
+ if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid,
+ /* target */ 0, /* lun */ 0) != CAM_REQ_CMP) {
+ slot_printf(slot, "Unable to create path for rescan\n");
+ SDHCI_UNLOCK(slot);
+ xpt_free_ccb(ccb);
+ return;
+ }
SDHCI_UNLOCK(slot);
+ xpt_rescan(ccb);
+#else
+ slot->intmask &= ~sdhci_tuning_intmask(slot);
+ WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
+ slot->opt &= ~SDHCI_TUNING_ENABLED;
+ SDHCI_UNLOCK(slot);
+ callout_drain(&slot->retune_callout);
device_delete_child(slot->bus, d);
+#endif
} else
SDHCI_UNLOCK(slot);
}
@@ -561,7 +681,11 @@ sdhci_handle_card_present_locked(struct sdhci_slot *slot, bool is_present)
* because once power is removed, a full card re-init is needed, and
* that happens by deleting and recreating the child device.
*/
+#ifdef MMCCAM
+ was_present = slot->card_present;
+#else
was_present = slot->dev != NULL;
+#endif
if (!was_present && is_present) {
taskqueue_enqueue_timeout(taskqueue_swi_giant,
&slot->card_delayed_task, -SDHCI_INSERT_DELAY_TICKS);
@@ -593,10 +717,13 @@ sdhci_card_poll(void *arg)
int
sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
{
+ kobjop_desc_t kobj_desc;
+ kobj_method_t *kobj_method;
uint32_t caps, caps2, freq, host_caps;
int err;
SDHCI_LOCK_INIT(slot);
+
slot->num = num;
slot->bus = dev;
@@ -617,6 +744,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
BUS_DMA_NOWAIT, &slot->dmamap);
if (err != 0) {
device_printf(dev, "Can't alloc DMA memory\n");
+ bus_dma_tag_destroy(slot->dmatag);
SDHCI_LOCK_DESTROY(slot);
return (err);
}
@@ -626,6 +754,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
sdhci_getaddr, &slot->paddr, 0);
if (err != 0 || slot->paddr == 0) {
device_printf(dev, "Can't load DMA memory\n");
+ bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
+ bus_dma_tag_destroy(slot->dmatag);
SDHCI_LOCK_DESTROY(slot);
if (err)
return (err);
@@ -633,8 +763,6 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
return (EFAULT);
}
- /* Initialize slot. */
- sdhci_init(slot);
slot->version = (RD2(slot, SDHCI_HOST_VERSION)
>> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK;
if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) {
@@ -647,6 +775,22 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
else
caps2 = 0;
}
+ if (slot->version >= SDHCI_SPEC_300) {
+ if ((caps & SDHCI_SLOTTYPE_MASK) != SDHCI_SLOTTYPE_REMOVABLE &&
+ (caps & SDHCI_SLOTTYPE_MASK) != SDHCI_SLOTTYPE_EMBEDDED) {
+ device_printf(dev,
+ "Driver doesn't support shared bus slots\n");
+ bus_dmamap_unload(slot->dmatag, slot->dmamap);
+ bus_dmamem_free(slot->dmatag, slot->dmamem,
+ slot->dmamap);
+ bus_dma_tag_destroy(slot->dmatag);
+ SDHCI_LOCK_DESTROY(slot);
+ return (ENXIO);
+ } else if ((caps & SDHCI_SLOTTYPE_MASK) ==
+ SDHCI_SLOTTYPE_EMBEDDED) {
+ slot->opt |= SDHCI_SLOT_EMBEDDED | SDHCI_NON_REMOVABLE;
+ }
+ }
/* Calculate base clock frequency. */
if (slot->version >= SDHCI_SPEC_300)
freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
@@ -696,12 +840,14 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
slot->host.host_ocr |= MMC_OCR_320_330 | MMC_OCR_330_340;
if (caps & SDHCI_CAN_VDD_300)
slot->host.host_ocr |= MMC_OCR_290_300 | MMC_OCR_300_310;
- if (caps & SDHCI_CAN_VDD_180)
+ /* 1.8V VDD is not supposed to be used for removable cards. */
+ if ((caps & SDHCI_CAN_VDD_180) && (slot->opt & SDHCI_SLOT_EMBEDDED))
slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE;
if (slot->host.host_ocr == 0) {
device_printf(dev, "Hardware doesn't report any "
"support voltages.\n");
}
+
host_caps = MMC_CAP_4_BIT_DATA;
if (caps & SDHCI_CAN_DO_8BITBUS)
host_caps |= MMC_CAP_8_BIT_DATA;
@@ -711,6 +857,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
host_caps |= MMC_CAP_BOOT_NOACC;
if (slot->quirks & SDHCI_QUIRK_WAIT_WHILE_BUSY)
host_caps |= MMC_CAP_WAIT_WHILE_BUSY;
+
+ /* Determine supported UHS-I and eMMC modes. */
if (caps2 & (SDHCI_CAN_SDR50 | SDHCI_CAN_SDR104 | SDHCI_CAN_DDR50))
host_caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
if (caps2 & SDHCI_CAN_SDR104) {
@@ -727,12 +875,91 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
if (slot->quirks & SDHCI_QUIRK_CAPS_BIT63_FOR_MMC_HS400 &&
caps2 & SDHCI_CAN_MMC_HS400)
host_caps |= MMC_CAP_MMC_HS400;
+
+ /*
+ * Disable UHS-I and eMMC modes if the set_uhs_timing method is the
+ * default NULL implementation.
+ */
+ kobj_desc = &sdhci_set_uhs_timing_desc;
+ kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL,
+ kobj_desc);
+ if (kobj_method == &kobj_desc->deflt)
+ host_caps &= ~(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_MMC_DDR52 | MMC_CAP_MMC_HS200 | MMC_CAP_MMC_HS400);
+
+#define SDHCI_CAP_MODES_TUNING(caps2) \
+ (((caps2) & SDHCI_TUNE_SDR50 ? MMC_CAP_UHS_SDR50 : 0) | \
+ MMC_CAP_UHS_DDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_MMC_HS200 | \
+ MMC_CAP_MMC_HS400)
+
+ /*
+ * Disable UHS-I and eMMC modes that require (re-)tuning if either
+ * the tune or re-tune method is the default NULL implementation.
+ */
+ kobj_desc = &mmcbr_tune_desc;
+ kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL,
+ kobj_desc);
+ if (kobj_method == &kobj_desc->deflt)
+ goto no_tuning;
+ kobj_desc = &mmcbr_retune_desc;
+ kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL,
+ kobj_desc);
+ if (kobj_method == &kobj_desc->deflt) {
+no_tuning:
+ host_caps &= ~(SDHCI_CAP_MODES_TUNING(caps2));
+ }
+
+ /* Allocate tuning structures and determine tuning parameters. */
+ if (host_caps & SDHCI_CAP_MODES_TUNING(caps2)) {
+ slot->opt |= SDHCI_TUNING_SUPPORTED;
+ slot->tune_req = malloc(sizeof(*slot->tune_req), M_DEVBUF,
+ M_WAITOK);
+ slot->tune_cmd = malloc(sizeof(*slot->tune_cmd), M_DEVBUF,
+ M_WAITOK);
+ slot->tune_data = malloc(sizeof(*slot->tune_data), M_DEVBUF,
+ M_WAITOK);
+ if (caps2 & SDHCI_TUNE_SDR50)
+ slot->opt |= SDHCI_SDR50_NEEDS_TUNING;
+ slot->retune_mode = (caps2 & SDHCI_RETUNE_MODES_MASK) >>
+ SDHCI_RETUNE_MODES_SHIFT;
+ if (slot->retune_mode == SDHCI_RETUNE_MODE_1) {
+ slot->retune_count = (caps2 & SDHCI_RETUNE_CNT_MASK) >>
+ SDHCI_RETUNE_CNT_SHIFT;
+ if (slot->retune_count > 0xb) {
+ device_printf(dev, "Unknown re-tuning count "
+ "%x, using 1 sec\n", slot->retune_count);
+ slot->retune_count = 1;
+ } else if (slot->retune_count != 0)
+ slot->retune_count =
+ 1 << (slot->retune_count - 1);
+ }
+ }
+
+#undef SDHCI_CAP_MODES_TUNING
+
+ /* Determine supported VCCQ signaling levels. */
host_caps |= MMC_CAP_SIGNALING_330;
if (host_caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | MMC_CAP_UHS_SDR104 |
MMC_CAP_MMC_DDR52_180 | MMC_CAP_MMC_HS200_180 |
MMC_CAP_MMC_HS400_180))
- host_caps |= MMC_CAP_SIGNALING_180;
+ host_caps |= MMC_CAP_SIGNALING_120 | MMC_CAP_SIGNALING_180;
+
+ /*
+ * Disable 1.2 V and 1.8 V signaling if the switch_vccq method is the
+ * default NULL implementation. Disable 1.2 V support if it's the
+ * generic SDHCI implementation.
+ */
+ kobj_desc = &mmcbr_switch_vccq_desc;
+ kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL,
+ kobj_desc);
+ if (kobj_method == &kobj_desc->deflt)
+ host_caps &= ~(MMC_CAP_SIGNALING_120 | MMC_CAP_SIGNALING_180);
+ else if (kobj_method->func == (kobjop_t)sdhci_generic_switch_vccq)
+ host_caps &= ~MMC_CAP_SIGNALING_120;
+
+ /* Determine supported driver types (type B is always mandatory). */
if (caps2 & SDHCI_CAN_DRIVE_TYPE_A)
host_caps |= MMC_CAP_DRIVER_TYPE_A;
if (caps2 & SDHCI_CAN_DRIVE_TYPE_C)
@@ -761,20 +988,24 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
if (bootverbose || sdhci_debug) {
slot_printf(slot,
- "%uMHz%s %s VDD:%s%s%s VCCQ: 3.3V%s%s DRV: B%s%s%s %s\n",
+ "%uMHz%s %s VDD:%s%s%s VCCQ: 3.3V%s%s DRV: B%s%s%s %s %s\n",
slot->max_clk / 1000000,
(caps & SDHCI_CAN_DO_HISPD) ? " HS" : "",
(host_caps & MMC_CAP_8_BIT_DATA) ? "8bits" :
((host_caps & MMC_CAP_4_BIT_DATA) ? "4bits" : "1bit"),
(caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "",
(caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "",
- (caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "",
+ ((caps & SDHCI_CAN_VDD_180) &&
+ (slot->opt & SDHCI_SLOT_EMBEDDED)) ? " 1.8V" : "",
(host_caps & MMC_CAP_SIGNALING_180) ? " 1.8V" : "",
(host_caps & MMC_CAP_SIGNALING_120) ? " 1.2V" : "",
- (caps2 & SDHCI_CAN_DRIVE_TYPE_A) ? "A" : "",
- (caps2 & SDHCI_CAN_DRIVE_TYPE_C) ? "C" : "",
- (caps2 & SDHCI_CAN_DRIVE_TYPE_D) ? "D" : "",
- (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO");
+ (host_caps & MMC_CAP_DRIVER_TYPE_A) ? "A" : "",
+ (host_caps & MMC_CAP_DRIVER_TYPE_C) ? "C" : "",
+ (host_caps & MMC_CAP_DRIVER_TYPE_D) ? "D" : "",
+ (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO",
+ (slot->opt & SDHCI_SLOT_EMBEDDED) ? "embedded" :
+ (slot->opt & SDHCI_NON_REMOVABLE) ? "non-removable" :
+ "removable");
if (host_caps & (MMC_CAP_MMC_DDR52 | MMC_CAP_MMC_HS200 |
MMC_CAP_MMC_HS400 | MMC_CAP_MMC_ENH_STROBE))
slot_printf(slot, "eMMC:%s%s%s%s\n",
@@ -793,6 +1024,9 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
(host_caps & MMC_CAP_UHS_SDR50) ? " SDR50" : "",
(host_caps & MMC_CAP_UHS_SDR104) ? " SDR104" : "",
(host_caps & MMC_CAP_UHS_DDR50) ? " DDR50" : "");
+ if (slot->opt & SDHCI_TUNING_SUPPORTED)
+ slot_printf(slot, "Re-tuning count %d secs, mode %d\n",
+ slot->retune_count, slot->retune_mode + 1);
sdhci_dumpregs(slot);
}
@@ -806,6 +1040,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
sdhci_card_task, slot);
callout_init(&slot->card_poll_callout, 1);
callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0);
+ callout_init_mtx(&slot->retune_callout, &slot->mtx, 0);
if ((slot->quirks & SDHCI_QUIRK_POLL_CARD_PRESENT) &&
!(slot->opt & SDHCI_NON_REMOVABLE)) {
@@ -813,6 +1048,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
SDHCI_CARD_PRESENT_TICKS, sdhci_card_poll, slot);
}
+ sdhci_init(slot);
+
return (0);
}
@@ -830,6 +1067,7 @@ sdhci_cleanup_slot(struct sdhci_slot *slot)
callout_drain(&slot->timeout_callout);
callout_drain(&slot->card_poll_callout);
+ callout_drain(&slot->retune_callout);
taskqueue_drain(taskqueue_swi_giant, &slot->card_task);
taskqueue_drain_timeout(taskqueue_swi_giant, &slot->card_delayed_task);
@@ -846,6 +1084,11 @@ sdhci_cleanup_slot(struct sdhci_slot *slot)
bus_dmamap_unload(slot->dmatag, slot->dmamap);
bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
bus_dma_tag_destroy(slot->dmatag);
+ if (slot->opt & SDHCI_TUNING_SUPPORTED) {
+ free(slot->tune_req, M_DEVBUF);
+ free(slot->tune_cmd, M_DEVBUF);
+ free(slot->tune_data, M_DEVBUF);
+ }
SDHCI_LOCK_DESTROY(slot);
@@ -856,7 +1099,16 @@ int
sdhci_generic_suspend(struct sdhci_slot *slot)
{
+ /*
+ * We expect the MMC layer to issue initial tuning after resume.
+ * Otherwise, we'd need to indicate re-tuning including circuit reset
+ * being required at least for re-tuning modes 1 and 2 ourselves.
+ */
+ callout_drain(&slot->retune_callout);
+ SDHCI_LOCK(slot);
+ slot->opt &= ~SDHCI_TUNING_ENABLED;
sdhci_reset(slot, SDHCI_RESET_ALL);
+ SDHCI_UNLOCK(slot);
return (0);
}
@@ -865,7 +1117,9 @@ int
sdhci_generic_resume(struct sdhci_slot *slot)
{
+ SDHCI_LOCK(slot);
sdhci_init(slot);
+ SDHCI_UNLOCK(slot);
return (0);
}
@@ -899,15 +1153,18 @@ sdhci_generic_set_uhs_timing(device_t brdev __unused, struct sdhci_slot *slot)
if (slot->version < SDHCI_SPEC_300)
return;
+ SDHCI_ASSERT_LOCKED(slot);
ios = &slot->host.ios;
sdhci_set_clock(slot, 0);
hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
hostctrl2 &= ~SDHCI_CTRL2_UHS_MASK;
- if (ios->timing == bus_timing_mmc_hs400 ||
- ios->timing == bus_timing_mmc_hs400es)
- hostctrl2 |= SDHCI_CTRL2_MMC_HS400;
- else if (ios->clock > SD_SDR50_MAX)
- hostctrl2 |= SDHCI_CTRL2_UHS_SDR104;
+ if (ios->clock > SD_SDR50_MAX) {
+ if (ios->timing == bus_timing_mmc_hs400 ||
+ ios->timing == bus_timing_mmc_hs400es)
+ hostctrl2 |= SDHCI_CTRL2_MMC_HS400;
+ else
+ hostctrl2 |= SDHCI_CTRL2_UHS_SDR104;
+ }
else if (ios->clock > SD_SDR25_MAX)
hostctrl2 |= SDHCI_CTRL2_UHS_SDR50;
else if (ios->clock > SD_SDR12_MAX) {
@@ -1019,6 +1276,222 @@ done:
return (err);
}
+int
+sdhci_generic_tune(device_t brdev __unused, device_t reqdev, bool hs400)
+{
+ struct sdhci_slot *slot = device_get_ivars(reqdev);
+ struct mmc_ios *ios = &slot->host.ios;
+ struct mmc_command *tune_cmd;
+ struct mmc_data *tune_data;
+ uint32_t opcode;
+ int err;
+
+ if (!(slot->opt & SDHCI_TUNING_SUPPORTED))
+ return (0);
+
+ slot->retune_ticks = slot->retune_count * hz;
+ opcode = MMC_SEND_TUNING_BLOCK;
+ SDHCI_LOCK(slot);
+ switch (ios->timing) {
+ case bus_timing_mmc_hs400:
+ slot_printf(slot, "HS400 must be tuned in HS200 mode\n");
+ SDHCI_UNLOCK(slot);
+ return (EINVAL);
+ case bus_timing_mmc_hs200:
+ /*
+ * In HS400 mode, controllers use the data strobe line to
+ * latch data from the devices so periodic re-tuning isn't
+ * expected to be required.
+ */
+ if (hs400)
+ slot->retune_ticks = 0;
+ opcode = MMC_SEND_TUNING_BLOCK_HS200;
+ break;
+ case bus_timing_uhs_ddr50:
+ case bus_timing_uhs_sdr104:
+ break;
+ case bus_timing_uhs_sdr50:
+ if (slot->opt & SDHCI_SDR50_NEEDS_TUNING)
+ break;
+ /* FALLTHROUGH */
+ default:
+ SDHCI_UNLOCK(slot);
+ return (0);
+ }
+
+ tune_cmd = slot->tune_cmd;
+ memset(tune_cmd, 0, sizeof(*tune_cmd));
+ tune_cmd->opcode = opcode;
+ tune_cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ tune_data = tune_cmd->data = slot->tune_data;
+ memset(tune_data, 0, sizeof(*tune_data));
+ tune_data->len = (opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
+ ios->bus_width == bus_width_8) ? MMC_TUNING_LEN_HS200 :
+ MMC_TUNING_LEN;
+ tune_data->flags = MMC_DATA_READ;
+ tune_data->mrq = tune_cmd->mrq = slot->tune_req;
+
+ slot->opt &= ~SDHCI_TUNING_ENABLED;
+ err = sdhci_exec_tuning(slot, true);
+ if (err == 0) {
+ slot->opt |= SDHCI_TUNING_ENABLED;
+ slot->intmask |= sdhci_tuning_intmask(slot);
+ WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
+ if (slot->retune_ticks) {
+ callout_reset(&slot->retune_callout, slot->retune_ticks,
+ sdhci_retune, slot);
+ }
+ }
+ SDHCI_UNLOCK(slot);
+ return (err);
+}
+
+int
+sdhci_generic_retune(device_t brdev __unused, device_t reqdev, bool reset)
+{
+ struct sdhci_slot *slot = device_get_ivars(reqdev);
+ int err;
+
+ if (!(slot->opt & SDHCI_TUNING_ENABLED))
+ return (0);
+
+ /* HS400 must be tuned in HS200 mode. */
+ if (slot->host.ios.timing == bus_timing_mmc_hs400)
+ return (EINVAL);
+
+ SDHCI_LOCK(slot);
+ err = sdhci_exec_tuning(slot, reset);
+ /*
+ * There are two ways sdhci_exec_tuning() can fail:
+ * EBUSY should not actually happen when requests are only issued
+ * with the host properly acquired, and
+ * EIO re-tuning failed (but it did work initially).
+ *
+ * In both cases, we should retry at later point if periodic re-tuning
+ * is enabled. Note that due to slot->retune_req not being cleared in
+ * these failure cases, the MMC layer should trigger another attempt at
+ * re-tuning with the next request anyway, though.
+ */
+ if (slot->retune_ticks) {
+ callout_reset(&slot->retune_callout, slot->retune_ticks,
+ sdhci_retune, slot);
+ }
+ SDHCI_UNLOCK(slot);
+ return (err);
+}
+
+static int
+sdhci_exec_tuning(struct sdhci_slot *slot, bool reset)
+{
+ struct mmc_request *tune_req;
+ struct mmc_command *tune_cmd;
+ int i;
+ uint32_t intmask;
+ uint16_t hostctrl2;
+ u_char opt;
+
+ SDHCI_ASSERT_LOCKED(slot);
+ if (slot->req != NULL)
+ return (EBUSY);
+
+ /* Tuning doesn't work with DMA enabled. */
+ opt = slot->opt;
+ slot->opt = opt & ~SDHCI_HAVE_DMA;
+
+ /*
+ * Ensure that as documented, SDHCI_INT_DATA_AVAIL is the only
+ * kind of interrupt we receive in response to a tuning request.
+ */
+ intmask = slot->intmask;
+ slot->intmask = SDHCI_INT_DATA_AVAIL;
+ WR4(slot, SDHCI_SIGNAL_ENABLE, SDHCI_INT_DATA_AVAIL);
+
+ hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
+ if (reset)
+ hostctrl2 &= ~SDHCI_CTRL2_SAMPLING_CLOCK;
+ else
+ hostctrl2 |= SDHCI_CTRL2_SAMPLING_CLOCK;
+ WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2 | SDHCI_CTRL2_EXEC_TUNING);
+
+ tune_req = slot->tune_req;
+ tune_cmd = slot->tune_cmd;
+ for (i = 0; i < MMC_TUNING_MAX; i++) {
+ memset(tune_req, 0, sizeof(*tune_req));
+#ifdef __rtems__
+ rtems_binary_semaphore_init(&tune_req->req_done,
+ "sdhci_req_done");
+#endif /* __rtems__ */
+ tune_req->cmd = tune_cmd;
+ tune_req->done = sdhci_req_wakeup;
+ tune_req->done_data = slot;
+ slot->req = tune_req;
+ slot->flags = 0;
+ sdhci_start(slot);
+#ifndef __rtems__
+ while (!(tune_req->flags & MMC_REQ_DONE))
+ msleep(tune_req, &slot->mtx, 0, "sdhciet", 0);
+#else /* __rtems__ */
+ rtems_binary_semaphore_wait(&tune_req->req_done);
+ rtems_binary_semaphore_destroy(&tune_req->req_done);
+#endif /* __rtems__ */
+ if (!(tune_req->flags & MMC_TUNE_DONE))
+ break;
+ hostctrl2 = RD2(slot, SDHCI_HOST_CONTROL2);
+ if (!(hostctrl2 & SDHCI_CTRL2_EXEC_TUNING))
+ break;
+ if (tune_cmd->opcode == MMC_SEND_TUNING_BLOCK)
+ DELAY(1000);
+ }
+
+ slot->opt = opt;
+ slot->intmask = intmask;
+ WR4(slot, SDHCI_SIGNAL_ENABLE, intmask);
+
+ if ((hostctrl2 & (SDHCI_CTRL2_EXEC_TUNING |
+ SDHCI_CTRL2_SAMPLING_CLOCK)) == SDHCI_CTRL2_SAMPLING_CLOCK) {
+ slot->retune_req = 0;
+ return (0);
+ }
+
+ slot_printf(slot, "Tuning failed, using fixed sampling clock\n");
+ WR2(slot, SDHCI_HOST_CONTROL2, hostctrl2 & ~(SDHCI_CTRL2_EXEC_TUNING |
+ SDHCI_CTRL2_SAMPLING_CLOCK));
+ sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ return (EIO);
+}
+
+static void
+sdhci_retune(void *arg)
+{
+ struct sdhci_slot *slot = arg;
+
+ slot->retune_req |= SDHCI_RETUNE_REQ_NEEDED;
+}
+
+#ifdef MMCCAM
+static void
+sdhci_req_done(struct sdhci_slot *slot)
+{
+ union ccb *ccb;
+
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "%s\n", __func__);
+ if (slot->ccb != NULL && slot->curcmd != NULL) {
+ callout_stop(&slot->timeout_callout);
+ ccb = slot->ccb;
+ slot->ccb = NULL;
+ slot->curcmd = NULL;
+
+ /* Tell CAM the request is finished */
+ struct ccb_mmcio *mmcio;
+ mmcio = &ccb->mmcio;
+
+ ccb->ccb_h.status =
+ (mmcio->cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR);
+ xpt_done(ccb);
+ }
+}
+#else
static void
sdhci_req_done(struct sdhci_slot *slot)
{
@@ -1032,6 +1505,21 @@ sdhci_req_done(struct sdhci_slot *slot)
req->done(req);
}
}
+#endif
+
+static void
+sdhci_req_wakeup(struct mmc_request *req)
+{
+#ifndef __rtems__
+ struct sdhci_slot *slot;
+
+ slot = req->done_data;
+ req->flags |= MMC_REQ_DONE;
+ wakeup(req);
+#else /* __rtems__ */
+ rtems_binary_semaphore_post(&req->req_done);
+#endif /* __rtems__ */
+}
static void
sdhci_timeout(void *arg)
@@ -1039,13 +1527,13 @@ sdhci_timeout(void *arg)
struct sdhci_slot *slot = arg;
if (slot->curcmd != NULL) {
- slot_printf(slot, " Controller timeout\n");
+ slot_printf(slot, "Controller timeout\n");
sdhci_dumpregs(slot);
sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
slot->curcmd->error = MMC_ERR_TIMEOUT;
sdhci_req_done(slot);
} else {
- slot_printf(slot, " Spurious timeout - no active command\n");
+ slot_printf(slot, "Spurious timeout - no active command\n");
}
}
@@ -1062,8 +1550,16 @@ sdhci_set_transfer_mode(struct sdhci_slot *slot, struct mmc_data *data)
mode |= SDHCI_TRNS_MULTI;
if (data->flags & MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
+#ifdef MMCCAM
+ struct ccb_mmcio *mmcio;
+ mmcio = &slot->ccb->mmcio;
+ if (mmcio->stop.opcode == MMC_STOP_TRANSMISSION
+ && !(slot->quirks & SDHCI_QUIRK_BROKEN_AUTO_STOP))
+ mode |= SDHCI_TRNS_ACMD12;
+#else
if (slot->req->stop && !(slot->quirks & SDHCI_QUIRK_BROKEN_AUTO_STOP))
mode |= SDHCI_TRNS_ACMD12;
+#endif
if (slot->flags & SDHCI_USE_DMA)
mode |= SDHCI_TRNS_DMA;
@@ -1096,6 +1592,9 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
if (!SDHCI_GET_CARD_PRESENT(slot->bus, slot) ||
slot->power == 0 ||
slot->clock == 0) {
+ slot_printf(slot,
+ "Cannot issue a command (power=%d clock=%d)",
+ slot->power, slot->clock);
cmd->error = MMC_ERR_FAILED;
sdhci_req_done(slot);
return;
@@ -1103,10 +1602,20 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
/* Always wait for free CMD bus. */
mask = SDHCI_CMD_INHIBIT;
/* Wait for free DAT if we have data or busy signal. */
- if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
+ if (cmd->data != NULL || (cmd->flags & MMC_RSP_BUSY))
mask |= SDHCI_DAT_INHIBIT;
- /* We shouldn't wait for DAT for stop commands. */
- if (cmd == slot->req->stop)
+ /*
+ * We shouldn't wait for DAT for stop commands or CMD19/CMD21. Note
+ * that these latter are also special in that SDHCI_CMD_DATA should
+ * be set below but no actual data is ever read from the controller.
+ */
+#ifdef MMCCAM
+ if (cmd == &slot->ccb->mmcio.stop ||
+#else
+ if (cmd == slot->req->stop ||
+#endif
+ __predict_false(cmd->opcode == MMC_SEND_TUNING_BLOCK ||
+ cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))
mask &= ~SDHCI_DAT_INHIBIT;
/*
* Wait for bus no more then 250 ms. Typically there will be no wait
@@ -1145,7 +1654,7 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
flags |= SDHCI_CMD_CRC;
if (cmd->flags & MMC_RSP_OPCODE)
flags |= SDHCI_CMD_INDEX;
- if (cmd->data)
+ if (cmd->data != NULL)
flags |= SDHCI_CMD_DATA;
if (cmd->opcode == MMC_STOP_TRANSMISSION)
flags |= SDHCI_CMD_TYPE_ABORT;
@@ -1164,6 +1673,8 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
WR4(slot, SDHCI_ARGUMENT, cmd->arg);
/* Set data transfer mode. */
sdhci_set_transfer_mode(slot, cmd->data);
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "Starting command!\n");
/* Start command. */
WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff));
/* Start timeout callout. */
@@ -1178,15 +1689,23 @@ sdhci_finish_command(struct sdhci_slot *slot)
uint32_t val;
uint8_t extra;
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "%s: called, err %d flags %d\n",
+ __func__, slot->curcmd->error, slot->curcmd->flags);
slot->cmd_done = 1;
/*
* Interrupt aggregation: Restore command interrupt.
* Main restore point for the case when command interrupt
* happened first.
*/
- WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE);
+ if (__predict_true(slot->curcmd->opcode != MMC_SEND_TUNING_BLOCK &&
+ slot->curcmd->opcode != MMC_SEND_TUNING_BLOCK_HS200))
+ WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |=
+ SDHCI_INT_RESPONSE);
/* In case of error - reset host and return. */
if (slot->curcmd->error) {
+ if (slot->curcmd->error == MMC_ERR_BADCRC)
+ slot->retune_req |= SDHCI_RETUNE_REQ_RESET;
sdhci_reset(slot, SDHCI_RESET_CMD);
sdhci_reset(slot, SDHCI_RESET_DATA);
sdhci_start(slot);
@@ -1211,6 +1730,11 @@ sdhci_finish_command(struct sdhci_slot *slot)
} else
slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE);
}
+ if (__predict_false(sdhci_debug > 1))
+ printf("Resp: %02x %02x %02x %02x\n",
+ slot->curcmd->resp[0], slot->curcmd->resp[1],
+ slot->curcmd->resp[2], slot->curcmd->resp[3]);
+
/* If data ready - finish. */
if (slot->data_done)
sdhci_start(slot);
@@ -1291,6 +1815,11 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
(data->len < 512) ? data->len : 512));
/* Set block count. */
WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512);
+
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "Block size: %02x, count %lu\n",
+ (unsigned int)SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512) ? data->len : 512),
+ (unsigned long)(data->len + 511) / 512);
}
void
@@ -1322,6 +1851,8 @@ sdhci_finish_data(struct sdhci_slot *slot)
slot->data_done = 1;
/* If there was error - reset the host. */
if (slot->curcmd->error) {
+ if (slot->curcmd->error == MMC_ERR_BADCRC)
+ slot->retune_req |= SDHCI_RETUNE_REQ_RESET;
sdhci_reset(slot, SDHCI_RESET_CMD);
sdhci_reset(slot, SDHCI_RESET_DATA);
sdhci_start(slot);
@@ -1332,6 +1863,47 @@ sdhci_finish_data(struct sdhci_slot *slot)
sdhci_start(slot);
}
+#ifdef MMCCAM
+static void
+sdhci_start(struct sdhci_slot *slot)
+{
+ union ccb *ccb;
+
+ ccb = slot->ccb;
+ if (ccb == NULL)
+ return;
+
+ struct ccb_mmcio *mmcio;
+ mmcio = &ccb->mmcio;
+
+ if (!(slot->flags & CMD_STARTED)) {
+ slot->flags |= CMD_STARTED;
+ sdhci_start_command(slot, &mmcio->cmd);
+ return;
+ }
+
+ /*
+ * Old stack doesn't use this!
+ * Enabling this code causes significant performance degradation
+ * and IRQ storms on BBB, Wandboard behaves fine.
+ * Not using this code does no harm...
+ if (!(slot->flags & STOP_STARTED) && mmcio->stop.opcode != 0) {
+ slot->flags |= STOP_STARTED;
+ sdhci_start_command(slot, &mmcio->stop);
+ return;
+ }
+ */
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "result: %d\n", mmcio->cmd.error);
+ if (mmcio->cmd.error == 0 &&
+ (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
+ sdhci_reset(slot, SDHCI_RESET_CMD);
+ sdhci_reset(slot, SDHCI_RESET_DATA);
+ }
+
+ sdhci_req_done(slot);
+}
+#else
static void
sdhci_start(struct sdhci_slot *slot)
{
@@ -1352,7 +1924,7 @@ sdhci_start(struct sdhci_slot *slot)
sdhci_start_command(slot, req->stop);
return;
}
- if (sdhci_debug > 1)
+ if (__predict_false(sdhci_debug > 1))
slot_printf(slot, "result: %d\n", req->cmd->error);
if (!req->cmd->error &&
((slot->curcmd == req->stop &&
@@ -1364,6 +1936,7 @@ sdhci_start(struct sdhci_slot *slot)
sdhci_req_done(slot);
}
+#endif
int
sdhci_generic_request(device_t brdev __unused, device_t reqdev,
@@ -1376,7 +1949,7 @@ sdhci_generic_request(device_t brdev __unused, device_t reqdev,
SDHCI_UNLOCK(slot);
return (EBUSY);
}
- if (sdhci_debug > 1) {
+ if (__predict_false(sdhci_debug > 1)) {
slot_printf(slot,
"CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
req->cmd->opcode, req->cmd->arg, req->cmd->flags,
@@ -1495,6 +2068,15 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask)
goto done;
}
+ /* Handle tuning completion interrupt. */
+ if (__predict_false((intmask & SDHCI_INT_DATA_AVAIL) &&
+ (slot->curcmd->opcode == MMC_SEND_TUNING_BLOCK ||
+ slot->curcmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) {
+ slot->req->flags |= MMC_TUNE_DONE;
+ sdhci_finish_command(slot);
+ sdhci_finish_data(slot);
+ return;
+ }
/* Handle PIO interrupt. */
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) {
if ((slot->opt & SDHCI_PLATFORM_TRANSFER) &&
@@ -1587,9 +2169,21 @@ sdhci_generic_intr(struct sdhci_slot *slot)
SDHCI_UNLOCK(slot);
return;
}
- if (sdhci_debug > 2)
+ if (__predict_false(sdhci_debug > 2))
slot_printf(slot, "Interrupt %#x\n", intmask);
+ /* Handle tuning error interrupt. */
+ if (__predict_false(intmask & SDHCI_INT_TUNEERR)) {
+ slot_printf(slot, "Tuning error indicated\n");
+ slot->retune_req |= SDHCI_RETUNE_REQ_RESET;
+ if (slot->curcmd) {
+ slot->curcmd->error = MMC_ERR_BADCRC;
+ sdhci_finish_command(slot);
+ }
+ }
+ /* Handle re-tuning interrupt. */
+ if (__predict_false(intmask & SDHCI_INT_RETUNE))
+ slot->retune_req |= SDHCI_RETUNE_REQ_NEEDED;
/* Handle card presence interrupts. */
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
present = (intmask & SDHCI_INT_CARD_INSERT) != 0;
@@ -1602,7 +2196,6 @@ sdhci_generic_intr(struct sdhci_slot *slot)
WR4(slot, SDHCI_INT_STATUS, intmask &
(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE));
sdhci_handle_card_present_locked(slot, present);
- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
}
/* Handle command interrupts. */
if (intmask & SDHCI_INT_CMD_MASK) {
@@ -1621,16 +2214,14 @@ sdhci_generic_intr(struct sdhci_slot *slot)
WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR);
sdhci_acmd_irq(slot);
}
- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
- intmask &= ~SDHCI_INT_ACMD12ERR;
- intmask &= ~SDHCI_INT_ERROR;
/* Handle bus power interrupt. */
if (intmask & SDHCI_INT_BUS_POWER) {
WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_BUS_POWER);
- slot_printf(slot,
- "Card is consuming too much power!\n");
- intmask &= ~SDHCI_INT_BUS_POWER;
+ slot_printf(slot, "Card is consuming too much power!\n");
}
+ intmask &= ~(SDHCI_INT_ERROR | SDHCI_INT_TUNEERR | SDHCI_INT_RETUNE |
+ SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_MASK |
+ SDHCI_INT_DATA_MASK | SDHCI_INT_ACMD12ERR | SDHCI_INT_BUS_POWER);
/* The rest is unknown. */
if (intmask) {
WR4(slot, SDHCI_INT_STATUS, intmask);
@@ -1684,6 +2275,19 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which,
case MMCBR_IVAR_VDD:
*result = slot->host.ios.vdd;
break;
+ case MMCBR_IVAR_RETUNE_REQ:
+ if (slot->opt & SDHCI_TUNING_ENABLED) {
+ if (slot->retune_req & SDHCI_RETUNE_REQ_RESET) {
+ *result = retune_req_reset;
+ break;
+ }
+ if (slot->retune_req & SDHCI_RETUNE_REQ_NEEDED) {
+ *result = retune_req_normal;
+ break;
+ }
+ }
+ *result = retune_req_none;
+ break;
case MMCBR_IVAR_VCCQ:
*result = slot->host.ios.vccq;
break;
@@ -1694,6 +2298,16 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which,
*result = slot->host.ios.timing;
break;
case MMCBR_IVAR_MAX_DATA:
+ /*
+ * Re-tuning modes 1 and 2 restrict the maximum data length
+ * per read/write command to 4 MiB.
+ */
+ if (slot->opt & SDHCI_TUNING_ENABLED &&
+ (slot->retune_mode == SDHCI_RETUNE_MODE_1 ||
+ slot->retune_mode == SDHCI_RETUNE_MODE_2)) {
+ *result = 4 * 1024 * 1024 / MMC_SECTOR_SIZE;
+ break;
+ }
*result = 65535;
break;
case MMCBR_IVAR_MAX_BUSY_TIMEOUT:
@@ -1714,6 +2328,8 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which,
uint32_t clock, max_clock;
int i;
+ if (sdhci_debug > 1)
+ slot_printf(slot, "%s: var=%d\n", __func__, which);
switch (which) {
default:
return (EINVAL);
@@ -1774,9 +2390,324 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which,
case MMCBR_IVAR_F_MIN:
case MMCBR_IVAR_F_MAX:
case MMCBR_IVAR_MAX_DATA:
+ case MMCBR_IVAR_RETUNE_REQ:
return (EINVAL);
}
return (0);
}
+#ifdef MMCCAM
+void
+sdhci_cam_start_slot(struct sdhci_slot *slot)
+{
+ if ((slot->devq = cam_simq_alloc(1)) == NULL) {
+ goto fail;
+ }
+
+ mtx_init(&slot->sim_mtx, "sdhcisim", NULL, MTX_DEF);
+ slot->sim = cam_sim_alloc(sdhci_cam_action, sdhci_cam_poll,
+ "sdhci_slot", slot, device_get_unit(slot->bus),
+ &slot->sim_mtx, 1, 1, slot->devq);
+
+ if (slot->sim == NULL) {
+ cam_simq_free(slot->devq);
+ slot_printf(slot, "cannot allocate CAM SIM\n");
+ goto fail;
+ }
+
+ mtx_lock(&slot->sim_mtx);
+ if (xpt_bus_register(slot->sim, slot->bus, 0) != 0) {
+ slot_printf(slot,
+ "cannot register SCSI pass-through bus\n");
+ cam_sim_free(slot->sim, FALSE);
+ cam_simq_free(slot->devq);
+ mtx_unlock(&slot->sim_mtx);
+ goto fail;
+ }
+
+ mtx_unlock(&slot->sim_mtx);
+ /* End CAM-specific init */
+ slot->card_present = 0;
+ sdhci_card_task(slot, 0);
+ return;
+
+fail:
+ if (slot->sim != NULL) {
+ mtx_lock(&slot->sim_mtx);
+ xpt_bus_deregister(cam_sim_path(slot->sim));
+ cam_sim_free(slot->sim, FALSE);
+ mtx_unlock(&slot->sim_mtx);
+ }
+
+ if (slot->devq != NULL)
+ cam_simq_free(slot->devq);
+}
+
+static void
+sdhci_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+ struct sdhci_slot *slot;
+
+ slot = cam_sim_softc(sim);
+
+ sdhci_cam_request(slot, ccb);
+}
+
+void
+sdhci_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct sdhci_slot *slot;
+
+ slot = cam_sim_softc(sim);
+ if (slot == NULL) {
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ mtx_assert(&slot->sim_mtx, MA_OWNED);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi;
+
+ cpi = &ccb->cpi;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = 0;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 0;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 1;
+ cpi->maxio = MAXPHYS;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->base_transfer_speed = 100; /* XXX WTF? */
+ cpi->protocol = PROTO_MMCSD;
+ cpi->protocol_version = SCSI_REV_0;
+ cpi->transport = XPORT_MMCSD;
+ cpi->transport_version = 0;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &ccb->cts;
+
+ if (sdhci_debug > 1)
+ slot_printf(slot, "Got XPT_GET_TRAN_SETTINGS\n");
+
+ cts->protocol = PROTO_MMCSD;
+ cts->protocol_version = 1;
+ cts->transport = XPORT_MMCSD;
+ cts->transport_version = 1;
+ cts->xport_specific.valid = 0;
+ cts->proto_specific.mmc.host_ocr = slot->host.host_ocr;
+ cts->proto_specific.mmc.host_f_min = slot->host.f_min;
+ cts->proto_specific.mmc.host_f_max = slot->host.f_max;
+ cts->proto_specific.mmc.host_caps = slot->host.caps;
+ memcpy(&cts->proto_specific.mmc.ios, &slot->host.ios, sizeof(struct mmc_ios));
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ if (sdhci_debug > 1)
+ slot_printf(slot, "Got XPT_SET_TRAN_SETTINGS\n");
+ sdhci_cam_settran_settings(slot, ccb);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_RESET_BUS:
+ if (sdhci_debug > 1)
+ slot_printf(slot, "Got XPT_RESET_BUS, ACK it...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_MMC_IO:
+ /*
+ * Here is the HW-dependent part of
+ * sending the command to the underlying h/w
+ * At some point in the future an interrupt comes.
+ * Then the request will be marked as completed.
+ */
+ if (__predict_false(sdhci_debug > 1))
+ slot_printf(slot, "Got XPT_MMC_IO\n");
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+
+ sdhci_cam_handle_mmcio(sim, ccb);
+ return;
+ /* NOTREACHED */
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+ return;
+}
+
+void
+sdhci_cam_poll(struct cam_sim *sim)
+{
+ return;
+}
+
+int sdhci_cam_get_possible_host_clock(struct sdhci_slot *slot, int proposed_clock) {
+ int max_clock, clock, i;
+
+ if (proposed_clock == 0)
+ return 0;
+ max_clock = slot->max_clk;
+ clock = max_clock;
+
+ if (slot->version < SDHCI_SPEC_300) {
+ for (i = 0; i < SDHCI_200_MAX_DIVIDER;
+ i <<= 1) {
+ if (clock <= proposed_clock)
+ break;
+ clock >>= 1;
+ }
+ } else {
+ for (i = 0; i < SDHCI_300_MAX_DIVIDER;
+ i += 2) {
+ if (clock <= proposed_clock)
+ break;
+ clock = max_clock / (i + 2);
+ }
+ }
+ return clock;
+}
+
+int
+sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb)
+{
+ struct mmc_ios *ios;
+ struct mmc_ios *new_ios;
+ struct ccb_trans_settings_mmc *cts;
+
+ ios = &slot->host.ios;
+
+ cts = &ccb->cts.proto_specific.mmc;
+ new_ios = &cts->ios;
+
+ /* Update only requested fields */
+ if (cts->ios_valid & MMC_CLK) {
+ ios->clock = sdhci_cam_get_possible_host_clock(slot, new_ios->clock);
+ slot_printf(slot, "Clock => %d\n", ios->clock);
+ }
+ if (cts->ios_valid & MMC_VDD) {
+ ios->vdd = new_ios->vdd;
+ slot_printf(slot, "VDD => %d\n", ios->vdd);
+ }
+ if (cts->ios_valid & MMC_CS) {
+ ios->chip_select = new_ios->chip_select;
+ slot_printf(slot, "CS => %d\n", ios->chip_select);
+ }
+ if (cts->ios_valid & MMC_BW) {
+ ios->bus_width = new_ios->bus_width;
+ slot_printf(slot, "Bus width => %d\n", ios->bus_width);
+ }
+ if (cts->ios_valid & MMC_PM) {
+ ios->power_mode = new_ios->power_mode;
+ slot_printf(slot, "Power mode => %d\n", ios->power_mode);
+ }
+ if (cts->ios_valid & MMC_BT) {
+ ios->timing = new_ios->timing;
+ slot_printf(slot, "Timing => %d\n", ios->timing);
+ }
+ if (cts->ios_valid & MMC_BM) {
+ ios->bus_mode = new_ios->bus_mode;
+ slot_printf(slot, "Bus mode => %d\n", ios->bus_mode);
+ }
+
+ /* XXX Provide a way to call a chip-specific IOS update, required for TI */
+ return (sdhci_cam_update_ios(slot));
+}
+
+int
+sdhci_cam_update_ios(struct sdhci_slot *slot)
+{
+ struct mmc_ios *ios = &slot->host.ios;
+
+ slot_printf(slot, "%s: power_mode=%d, clk=%d, bus_width=%d, timing=%d\n",
+ __func__, ios->power_mode, ios->clock, ios->bus_width, ios->timing);
+ SDHCI_LOCK(slot);
+ /* Do full reset on bus power down to clear from any state. */
+ if (ios->power_mode == power_off) {
+ WR4(slot, SDHCI_SIGNAL_ENABLE, 0);
+ sdhci_init(slot);
+ }
+ /* Configure the bus. */
+ sdhci_set_clock(slot, ios->clock);
+ sdhci_set_power(slot, (ios->power_mode == power_off) ? 0 : ios->vdd);
+ if (ios->bus_width == bus_width_8) {
+ slot->hostctrl |= SDHCI_CTRL_8BITBUS;
+ slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
+ } else if (ios->bus_width == bus_width_4) {
+ slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
+ slot->hostctrl |= SDHCI_CTRL_4BITBUS;
+ } else if (ios->bus_width == bus_width_1) {
+ slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
+ slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
+ } else {
+ panic("Invalid bus width: %d", ios->bus_width);
+ }
+ if (ios->timing == bus_timing_hs &&
+ !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT))
+ slot->hostctrl |= SDHCI_CTRL_HISPD;
+ else
+ slot->hostctrl &= ~SDHCI_CTRL_HISPD;
+ WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl);
+ /* Some controllers like reset after bus changes. */
+ if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
+ sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+ SDHCI_UNLOCK(slot);
+ return (0);
+}
+
+int
+sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb)
+{
+ struct ccb_mmcio *mmcio;
+
+ mmcio = &ccb->mmcio;
+
+ SDHCI_LOCK(slot);
+/* if (slot->req != NULL) {
+ SDHCI_UNLOCK(slot);
+ return (EBUSY);
+ }
+*/
+ if (__predict_false(sdhci_debug > 1)) {
+ slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
+ mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags,
+ mmcio->cmd.data != NULL ? (unsigned int) mmcio->cmd.data->len : 0,
+ mmcio->cmd.data != NULL ? mmcio->cmd.data->flags: 0);
+ }
+ if (mmcio->cmd.data != NULL) {
+ if (mmcio->cmd.data->len == 0 || mmcio->cmd.data->flags == 0)
+ panic("data->len = %d, data->flags = %d -- something is b0rked",
+ (int)mmcio->cmd.data->len, mmcio->cmd.data->flags);
+ }
+ slot->ccb = ccb;
+ slot->flags = 0;
+ sdhci_start(slot);
+ SDHCI_UNLOCK(slot);
+ if (dumping) {
+ while (slot->ccb != NULL) {
+ sdhci_generic_intr(slot);
+ DELAY(10);
+ }
+ }
+ return (0);
+}
+#endif /* MMCCAM */
+
MODULE_VERSION(sdhci, 1);
diff --git a/freebsd/sys/dev/sdhci/sdhci.h b/freebsd/sys/dev/sdhci/sdhci.h
index 814f81ed..73aa84b6 100644
--- a/freebsd/sys/dev/sdhci/sdhci.h
+++ b/freebsd/sys/dev/sdhci/sdhci.h
@@ -28,6 +28,8 @@
#ifndef __SDHCI_H__
#define __SDHCI_H__
+#include <rtems/bsd/local/opt_mmccam.h>
+
#define DMA_BLOCK_SIZE 4096
#define DMA_BOUNDARY 0 /* DMA reload every 4K */
@@ -235,6 +237,11 @@
#define SDHCI_HOST_CONTROL2 0x3E
#define SDHCI_CTRL2_PRESET_VALUE 0x8000
#define SDHCI_CTRL2_ASYNC_INTR 0x4000
+#define SDHCI_CTRL2_64BIT_ENABLE 0x2000
+#define SDHCI_CTRL2_HOST_V4_ENABLE 0x1000
+#define SDHCI_CTRL2_CMD23_ENABLE 0x0800
+#define SDHCI_CTRL2_ADMA2_LENGTH_MODE 0x0400
+#define SDHCI_CTRL2_UHS2_IFACE_ENABLE 0x0100
#define SDHCI_CTRL2_SAMPLING_CLOCK 0x0080
#define SDHCI_CTRL2_EXEC_TUNING 0x0040
#define SDHCI_CTRL2_DRIVER_TYPE_MASK 0x0030
@@ -319,6 +326,8 @@
#define SDHCI_SPEC_200 1
#define SDHCI_SPEC_300 2
#define SDHCI_SPEC_400 3
+#define SDHCI_SPEC_410 4
+#define SDHCI_SPEC_420 5
SYSCTL_DECL(_hw_sdhci);
@@ -326,6 +335,7 @@ extern u_int sdhci_quirk_clear;
extern u_int sdhci_quirk_set;
struct sdhci_slot {
+ struct mtx mtx; /* Slot mutex */
u_int quirks; /* Chip specific quirks */
u_int caps; /* Override SDHCI_CAPABILITIES */
u_int caps2; /* Override SDHCI_CAPABILITIES2 */
@@ -336,6 +346,10 @@ struct sdhci_slot {
#define SDHCI_HAVE_DMA 0x01
#define SDHCI_PLATFORM_TRANSFER 0x02
#define SDHCI_NON_REMOVABLE 0x04
+#define SDHCI_TUNING_SUPPORTED 0x08
+#define SDHCI_TUNING_ENABLED 0x10
+#define SDHCI_SDR50_NEEDS_TUNING 0x20
+#define SDHCI_SLOT_EMBEDDED 0x40
u_char version;
int timeout; /* Transfer timeout */
uint32_t max_clk; /* Max possible freq */
@@ -349,14 +363,27 @@ struct sdhci_slot {
card_delayed_task;/* Card insert delayed task */
struct callout card_poll_callout;/* Card present polling callout */
struct callout timeout_callout;/* Card command/data response timeout */
+ struct callout retune_callout; /* Re-tuning mode 1 callout */
struct mmc_host host; /* Host parameters */
struct mmc_request *req; /* Current request */
struct mmc_command *curcmd; /* Current command of current request */
+ struct mmc_request *tune_req; /* Tuning request */
+ struct mmc_command *tune_cmd; /* Tuning command of tuning request */
+ struct mmc_data *tune_data; /* Tuning data of tuning command */
+ uint32_t retune_ticks; /* Re-tuning callout ticks [hz] */
uint32_t intmask; /* Current interrupt mask */
uint32_t clock; /* Current clock freq. */
size_t offset; /* Data buffer offset */
uint8_t hostctrl; /* Current host control register */
+ uint8_t retune_count; /* Controller re-tuning count [s] */
+ uint8_t retune_mode; /* Controller re-tuning mode */
+#define SDHCI_RETUNE_MODE_1 0x00
+#define SDHCI_RETUNE_MODE_2 0x01
+#define SDHCI_RETUNE_MODE_3 0x02
+ uint8_t retune_req; /* Re-tuning request status */
+#define SDHCI_RETUNE_REQ_NEEDED 0x01 /* Re-tuning w/o circuit reset needed */
+#define SDHCI_RETUNE_REQ_RESET 0x02 /* Re-tuning w/ circuit reset needed */
u_char power; /* Current power */
u_char bus_busy; /* Bus busy status */
u_char cmd_done; /* CMD command part done flag */
@@ -366,7 +393,15 @@ struct sdhci_slot {
#define STOP_STARTED 2
#define SDHCI_USE_DMA 4 /* Use DMA for this req. */
#define PLATFORM_DATA_STARTED 8 /* Data xfer is handled by platform */
- struct mtx mtx; /* Slot mutex */
+
+#ifdef MMCCAM
+ /* CAM stuff */
+ union ccb *ccb;
+ struct cam_devq *devq;
+ struct cam_sim *sim;
+ struct mtx sim_mtx;
+ u_char card_present; /* XXX Maybe derive this from elsewhere? */
+#endif
};
int sdhci_generic_read_ivar(device_t bus, device_t child, int which,
@@ -381,7 +416,9 @@ int sdhci_cleanup_slot(struct sdhci_slot *slot);
int sdhci_generic_suspend(struct sdhci_slot *slot);
int sdhci_generic_resume(struct sdhci_slot *slot);
int sdhci_generic_update_ios(device_t brdev, device_t reqdev);
+int sdhci_generic_tune(device_t brdev, device_t reqdev, bool hs400);
int sdhci_generic_switch_vccq(device_t brdev, device_t reqdev);
+int sdhci_generic_retune(device_t brdev, device_t reqdev, bool reset);
int sdhci_generic_request(device_t brdev, device_t reqdev,
struct mmc_request *req);
int sdhci_generic_get_ro(device_t brdev, device_t reqdev);
@@ -393,4 +430,9 @@ bool sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot);
void sdhci_generic_set_uhs_timing(device_t brdev, struct sdhci_slot *slot);
void sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present);
+#ifdef MMCCAM
+/* CAM-related */
+void sdhci_cam_start_slot(struct sdhci_slot *slot);
+#endif
+
#endif /* __SDHCI_H__ */
diff --git a/freebsd/sys/dev/tsec/if_tsec.c b/freebsd/sys/dev/tsec/if_tsec.c
index d76c8f10..b7edc948 100644
--- a/freebsd/sys/dev/tsec/if_tsec.c
+++ b/freebsd/sys/dev/tsec/if_tsec.c
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
-#include <sys/bus_dma.h>
#include <sys/endian.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
diff --git a/freebsd/sys/dev/usb/controller/saf1761_otg.c b/freebsd/sys/dev/usb/controller/saf1761_otg.c
index f9d28a63..e1ce5eb6 100644
--- a/freebsd/sys/dev/usb/controller/saf1761_otg.c
+++ b/freebsd/sys/dev/usb/controller/saf1761_otg.c
@@ -525,9 +525,6 @@ saf1761_host_bulk_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *t
DPRINTFN(5, "STATUS=0x%08x\n", status);
if (status & SOTG_PTD_DW3_ACTIVE) {
-#ifndef __rtems__
- goto busy;
-#else /* __rtems__ */
temp = saf1761_peek_host_status_le_4(sc,
pdt_addr + SOTG_PTD_DW0);
if (temp & SOTG_PTD_DW0_VALID) {
@@ -547,7 +544,6 @@ saf1761_host_bulk_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *t
goto complete;
}
}
-#endif /* __rtems__ */
} else if (status & SOTG_PTD_DW3_HALTED) {
if (!(status & SOTG_PTD_DW3_ERRORS))
td->error_stall = 1;
@@ -591,9 +587,7 @@ saf1761_host_bulk_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *t
}
saf1761_host_channel_free(sc, td);
}
-#ifdef __rtems__
retry:
-#endif /* __rtems__ */
if (saf1761_host_channel_alloc(sc, td))
goto busy;
@@ -1623,10 +1617,8 @@ saf1761_otg_filter_interrupt(void *arg)
(void) SAF1761_READ_LE_4(sc, SOTG_INT_PTD_DONE_PTD);
(void) SAF1761_READ_LE_4(sc, SOTG_ISO_PTD_DONE_PTD);
-#ifdef __rtems__
DPRINTFN(9, "HCINTERRUPT=0x%08x DCINTERRUPT=0x%08x\n", hcstat, status);
-#endif /* __rtems__ */
if (status & SOTG_DCINTERRUPT_IEPSOF) {
if ((sc->sc_host_async_busy_map[1] | sc->sc_host_async_busy_map[0] |
sc->sc_host_intr_busy_map[1] | sc->sc_host_intr_busy_map[0] |
@@ -2496,13 +2488,12 @@ saf1761_otg_init(struct saf1761_otg_softc *sc)
#ifdef __rtems__
SAF1761_WRITE_LE_4(sc, SOTG_CTRL_SET_CLR,
SOTG_CTRL_SET(SOTG_CTRL_SEL_CP_EXT | SOTG_CTRL_VBUS_DRV));
-#else /* __rtems__ */
+#else
SAF1761_WRITE_LE_4(sc, SOTG_CTRL_SET_CLR,
SOTG_CTRL_SET(SOTG_CTRL_SW_SEL_HC_DC |
SOTG_CTRL_BDIS_ACON_EN | SOTG_CTRL_SEL_CP_EXT |
SOTG_CTRL_VBUS_DRV));
-#endif /* __rtems__ */
-
+#endif
/* disable device address */
SAF1761_WRITE_LE_4(sc, SOTG_ADDRESS, 0);
diff --git a/freebsd/sys/dev/usb/wlan/if_rsu.c b/freebsd/sys/dev/usb/wlan/if_rsu.c
index 659e178a..2415d2f2 100644
--- a/freebsd/sys/dev/usb/wlan/if_rsu.c
+++ b/freebsd/sys/dev/usb/wlan/if_rsu.c
@@ -2036,6 +2036,8 @@ rsu_hwrssi_to_rssi(struct rsu_softc *sc, int hw_rssi)
return (v);
}
+CTASSERT(MCLBYTES > sizeof(struct ieee80211_frame));
+
static void
rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
{
@@ -2044,28 +2046,31 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
struct ndis_wlan_bssid_ex *bss;
struct ieee80211_rx_stats rxs;
struct mbuf *m;
- int pktlen;
+ uint32_t ieslen;
+ uint32_t pktlen;
if (__predict_false(len < sizeof(*bss)))
return;
bss = (struct ndis_wlan_bssid_ex *)buf;
- if (__predict_false(len < sizeof(*bss) + le32toh(bss->ieslen)))
+ ieslen = le32toh(bss->ieslen);
+ /* range check length of information element */
+ if (__predict_false(ieslen > (uint32_t)(len - sizeof(*bss))))
return;
RSU_DPRINTF(sc, RSU_DEBUG_SCAN,
"%s: found BSS %s: len=%d chan=%d inframode=%d "
"networktype=%d privacy=%d, RSSI=%d\n",
__func__,
- ether_sprintf(bss->macaddr), le32toh(bss->len),
+ ether_sprintf(bss->macaddr), ieslen,
le32toh(bss->config.dsconfig), le32toh(bss->inframode),
le32toh(bss->networktype), le32toh(bss->privacy),
le32toh(bss->rssi));
/* Build a fake beacon frame to let net80211 do all the parsing. */
/* XXX TODO: just call the new scan API methods! */
- pktlen = sizeof(*wh) + le32toh(bss->ieslen);
- if (__predict_false(pktlen > MCLBYTES))
+ if (__predict_false(ieslen > (size_t)(MCLBYTES - sizeof(*wh))))
return;
+ pktlen = sizeof(*wh) + ieslen;
m = m_get2(pktlen, M_NOWAIT, MT_DATA, M_PKTHDR);
if (__predict_false(m == NULL))
return;
@@ -2078,7 +2083,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len)
IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr);
IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr);
*(uint16_t *)wh->i_seq = 0;
- memcpy(&wh[1], (uint8_t *)&bss[1], le32toh(bss->ieslen));
+ memcpy(&wh[1], (uint8_t *)&bss[1], ieslen);
/* Finalize mbuf. */
m->m_pkthdr.len = m->m_len = pktlen;
@@ -3378,6 +3383,8 @@ rsu_fw_loadsection(struct rsu_softc *sc, const uint8_t *buf, int len)
return (0);
}
+CTASSERT(sizeof(size_t) >= sizeof(uint32_t));
+
static int
rsu_load_firmware(struct rsu_softc *sc)
{
@@ -3385,7 +3392,7 @@ rsu_load_firmware(struct rsu_softc *sc)
struct r92s_fw_priv *dmem;
struct ieee80211com *ic = &sc->sc_ic;
const uint8_t *imem, *emem;
- int imemsz, ememsz;
+ uint32_t imemsz, ememsz;
const struct firmware *fw;
size_t size;
uint32_t reg;
@@ -3437,7 +3444,8 @@ rsu_load_firmware(struct rsu_softc *sc)
imemsz = le32toh(hdr->imemsz);
ememsz = le32toh(hdr->sramsz);
/* Check that all FW sections fit in image. */
- if (size < sizeof(*hdr) + imemsz + ememsz) {
+ if (imemsz > (size_t)(size - sizeof(*hdr)) ||
+ ememsz > (size_t)(size - sizeof(*hdr) - imemsz)) {
device_printf(sc->sc_dev, "firmware too short\n");
error = EINVAL;
goto fail;
diff --git a/freebsd/sys/dev/usb/wlan/if_zyd.c b/freebsd/sys/dev/usb/wlan/if_zyd.c
index 3ae5616f..e4243d8f 100644
--- a/freebsd/sys/dev/usb/wlan/if_zyd.c
+++ b/freebsd/sys/dev/usb/wlan/if_zyd.c
@@ -650,11 +650,12 @@ zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct zyd_notif_retry *retry =
(struct zyd_notif_retry *)cmd->data;
+ uint16_t count = le16toh(retry->count);
DPRINTF(sc, ZYD_DEBUG_TX_PROC,
"retry intr: rate=0x%x addr=%s count=%d (0x%x)\n",
le16toh(retry->rate), ether_sprintf(retry->macaddr),
- le16toh(retry->count)&0xff, le16toh(retry->count));
+ count & 0xff, count);
/*
* Find the node to which the packet was sent and
@@ -666,13 +667,12 @@ zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
if (ni != NULL) {
struct ieee80211_ratectl_tx_status *txs =
&sc->sc_txs;
- int retrycnt =
- (int)(le16toh(retry->count) & 0xff);
+ int retrycnt = count & 0xff;
txs->flags =
IEEE80211_RATECTL_STATUS_LONG_RETRY;
txs->long_retries = retrycnt;
- if (le16toh(retry->count) & 0x100) {
+ if (count & 0x100) {
txs->status =
IEEE80211_RATECTL_TX_FAIL_LONG;
} else {
@@ -684,7 +684,7 @@ zyd_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
ieee80211_ratectl_tx_complete(ni, txs);
ieee80211_free_node(ni);
}
- if (le16toh(retry->count) & 0x100)
+ if (count & 0x100)
/* too many retries */
if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS,
1);
diff --git a/freebsd/sys/kern/init_main.c b/freebsd/sys/kern/init_main.c
index 467888b2..f211b363 100644
--- a/freebsd/sys/kern/init_main.c
+++ b/freebsd/sys/kern/init_main.c
@@ -384,8 +384,7 @@ SYSINIT(diagwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 2,
#endif
static int
-null_fetch_syscall_args(struct thread *td __unused,
- struct syscall_args *sa __unused)
+null_fetch_syscall_args(struct thread *td __unused)
{
panic("null_fetch_syscall_args");
diff --git a/freebsd/sys/kern/kern_event.c b/freebsd/sys/kern/kern_event.c
index 0a64adbe..2428182c 100644
--- a/freebsd/sys/kern/kern_event.c
+++ b/freebsd/sys/kern/kern_event.c
@@ -31,6 +31,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <rtems/bsd/local/opt_compat.h>
#include <rtems/bsd/local/opt_ktrace.h>
#include <rtems/bsd/local/opt_kqueue.h>
@@ -119,6 +120,10 @@ static int kqueue_scan(struct kqueue *kq, int maxevents,
static void kqueue_wakeup(struct kqueue *kq);
static struct filterops *kqueue_fo_find(int filt);
static void kqueue_fo_release(int filt);
+struct g_kevent_args;
+static int kern_kevent_generic(struct thread *td,
+ struct g_kevent_args *uap,
+ struct kevent_copyops *k_ops);
#ifndef __rtems__
static fo_rdwr_t kqueue_read;
@@ -640,12 +645,13 @@ knote_fork(struct knlist *list, int pid)
* interval timer support code.
*/
-#define NOTE_TIMER_PRECMASK (NOTE_SECONDS|NOTE_MSECONDS|NOTE_USECONDS| \
- NOTE_NSECONDS)
+#define NOTE_TIMER_PRECMASK \
+ (NOTE_SECONDS | NOTE_MSECONDS | NOTE_USECONDS | NOTE_NSECONDS)
static sbintime_t
timer2sbintime(intptr_t data, int flags)
{
+ int64_t secs;
/*
* Macros for converting to the fractional second portion of an
@@ -664,27 +670,27 @@ timer2sbintime(intptr_t data, int flags)
case NOTE_MSECONDS: /* FALLTHROUGH */
case 0:
if (data >= 1000) {
- int64_t secs = data / 1000;
+ secs = data / 1000;
#ifdef __LP64__
if (secs > (SBT_MAX / SBT_1S))
return (SBT_MAX);
#endif
return (secs << 32 | MS_TO_SBT(data % 1000));
}
- return MS_TO_SBT(data);
+ return (MS_TO_SBT(data));
case NOTE_USECONDS:
if (data >= 1000000) {
- int64_t secs = data / 1000000;
+ secs = data / 1000000;
#ifdef __LP64__
if (secs > (SBT_MAX / SBT_1S))
return (SBT_MAX);
#endif
return (secs << 32 | US_TO_SBT(data % 1000000));
}
- return US_TO_SBT(data);
+ return (US_TO_SBT(data));
case NOTE_NSECONDS:
if (data >= 1000000000) {
- int64_t secs = data / 1000000000;
+ secs = data / 1000000000;
#ifdef __LP64__
if (secs > (SBT_MAX / SBT_1S))
return (SBT_MAX);
@@ -701,7 +707,7 @@ timer2sbintime(intptr_t data, int flags)
struct kq_timer_cb_data {
struct callout c;
sbintime_t next; /* next timer event fires at */
- sbintime_t to; /* precalculated timer period */
+ sbintime_t to; /* precalculated timer period, 0 for abs */
};
static void
@@ -716,8 +722,9 @@ filt_timerexpire(void *knx)
if ((kn->kn_flags & EV_ONESHOT) != 0)
return;
-
kc = kn->kn_ptr.p_v;
+ if (kc->to == 0)
+ return;
kc->next += kc->to;
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
@@ -730,7 +737,8 @@ static int
filt_timerattach(struct knote *kn)
{
struct kq_timer_cb_data *kc;
- sbintime_t to;
+ struct bintime bt;
+ sbintime_t to, sbt;
unsigned int ncallouts;
if (kn->kn_sdata < 0)
@@ -738,10 +746,15 @@ filt_timerattach(struct knote *kn)
if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
kn->kn_sdata = 1;
/* Only precision unit are supported in flags so far */
- if ((kn->kn_sfflags & ~NOTE_TIMER_PRECMASK) != 0)
+ if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0)
return (EINVAL);
to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
+ if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
+ getboottimebin(&bt);
+ sbt = bttosbt(bt);
+ to -= sbt;
+ }
if (to < 0)
return (EINVAL);
@@ -751,12 +764,18 @@ filt_timerattach(struct knote *kn)
return (ENOMEM);
} while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1));
- kn->kn_flags |= EV_CLEAR; /* automatically set */
+ if ((kn->kn_sfflags & NOTE_ABSTIME) == 0)
+ kn->kn_flags |= EV_CLEAR; /* automatically set */
kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
callout_init(&kc->c, 1);
- kc->next = to + sbinuptime();
- kc->to = to;
+ if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
+ kc->next = to;
+ kc->to = 0;
+ } else {
+ kc->next = to + sbinuptime();
+ kc->to = to;
+ }
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
PCPU_GET(cpuid), C_ABSOLUTE);
@@ -970,25 +989,24 @@ kqueue(void)
#ifdef KTRACE
static size_t
-kev_iovlen(int n, u_int kgio)
+kev_iovlen(int n, u_int kgio, size_t kevent_size)
{
- if (n < 0 || n >= kgio / sizeof(struct kevent))
+ if (n < 0 || n >= kgio / kevent_size)
return (kgio);
- return (n * sizeof(struct kevent));
+ return (n * kevent_size);
}
#endif
-#ifndef _SYS_SYSPROTO_H_
-struct kevent_args {
+struct g_kevent_args {
int fd;
- const struct kevent *changelist;
+ void *changelist;
int nchanges;
- struct kevent *eventlist;
+ void *eventlist;
int nevents;
const struct timespec *timeout;
};
-#endif
+
#ifdef __rtems__
static int kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout);
@@ -1001,12 +1019,29 @@ static
int
sys_kevent(struct thread *td, struct kevent_args *uap)
{
- struct timespec ts, *tsp;
struct kevent_copyops k_ops = {
.arg = uap,
.k_copyout = kevent_copyout,
.k_copyin = kevent_copyin,
+ .kevent_size = sizeof(struct kevent),
};
+ struct g_kevent_args gk_args = {
+ .fd = uap->fd,
+ .changelist = uap->changelist,
+ .nchanges = uap->nchanges,
+ .eventlist = uap->eventlist,
+ .nevents = uap->nevents,
+ .timeout = uap->timeout,
+ };
+
+ return (kern_kevent_generic(td, &gk_args, &k_ops));
+}
+
+static int
+kern_kevent_generic(struct thread *td, struct g_kevent_args *uap,
+ struct kevent_copyops *k_ops)
+{
+ struct timespec ts, *tsp;
int error;
#ifdef KTRACE
struct uio ktruio;
@@ -1028,26 +1063,30 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
if (KTRPOINT(td, KTR_GENIO)) {
kgio = ktr_geniosize;
ktriov.iov_base = uap->changelist;
- ktriov.iov_len = kev_iovlen(uap->nchanges, kgio);
+ ktriov.iov_len = kev_iovlen(uap->nchanges, kgio,
+ k_ops->kevent_size);
ktruio = (struct uio){ .uio_iov = &ktriov, .uio_iovcnt = 1,
.uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ,
.uio_td = td };
ktruioin = cloneuio(&ktruio);
ktriov.iov_base = uap->eventlist;
- ktriov.iov_len = kev_iovlen(uap->nevents, kgio);
- ktriov.iov_len = uap->nevents * sizeof(struct kevent);
+ ktriov.iov_len = kev_iovlen(uap->nevents, kgio,
+ k_ops->kevent_size);
+ ktriov.iov_len = uap->nevents * k_ops->kevent_size;
ktruioout = cloneuio(&ktruio);
}
#endif
error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
- &k_ops, tsp);
+ k_ops, tsp);
#ifdef KTRACE
if (ktruioin != NULL) {
- ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio);
+ ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio,
+ k_ops->kevent_size);
ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0);
- ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio);
+ ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio,
+ k_ops->kevent_size);
ktrgenio(uap->fd, UIO_READ, ktruioout, error);
}
#endif
@@ -1123,6 +1162,94 @@ kevent_copyin(void *arg, struct kevent *kevp, int count)
return (error);
}
+#ifdef COMPAT_FREEBSD11
+struct kevent_freebsd11 {
+ __uintptr_t ident; /* identifier for this event */
+ short filter; /* filter for event */
+ unsigned short flags;
+ unsigned int fflags;
+ __intptr_t data;
+ void *udata; /* opaque user data identifier */
+};
+
+static int
+kevent11_copyout(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd11_kevent_args *uap;
+ struct kevent_freebsd11 kev11;
+ int error, i;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd11_kevent_args *)arg;
+
+ for (i = 0; i < count; i++) {
+ kev11.ident = kevp->ident;
+ kev11.filter = kevp->filter;
+ kev11.flags = kevp->flags;
+ kev11.fflags = kevp->fflags;
+ kev11.data = kevp->data;
+ kev11.udata = kevp->udata;
+ error = copyout(&kev11, uap->eventlist, sizeof(kev11));
+ if (error != 0)
+ break;
+ uap->eventlist++;
+ kevp++;
+ }
+ return (error);
+}
+
+/*
+ * Copy 'count' items from the list pointed to by uap->changelist.
+ */
+static int
+kevent11_copyin(void *arg, struct kevent *kevp, int count)
+{
+ struct freebsd11_kevent_args *uap;
+ struct kevent_freebsd11 kev11;
+ int error, i;
+
+ KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+ uap = (struct freebsd11_kevent_args *)arg;
+
+ for (i = 0; i < count; i++) {
+ error = copyin(uap->changelist, &kev11, sizeof(kev11));
+ if (error != 0)
+ break;
+ kevp->ident = kev11.ident;
+ kevp->filter = kev11.filter;
+ kevp->flags = kev11.flags;
+ kevp->fflags = kev11.fflags;
+ kevp->data = (uintptr_t)kev11.data;
+ kevp->udata = kev11.udata;
+ bzero(&kevp->ext, sizeof(kevp->ext));
+ uap->changelist++;
+ kevp++;
+ }
+ return (error);
+}
+
+int
+freebsd11_kevent(struct thread *td, struct freebsd11_kevent_args *uap)
+{
+ struct kevent_copyops k_ops = {
+ .arg = uap,
+ .k_copyout = kevent11_copyout,
+ .k_copyin = kevent11_copyin,
+ .kevent_size = sizeof(struct kevent_freebsd11),
+ };
+ struct g_kevent_args gk_args = {
+ .fd = uap->fd,
+ .changelist = uap->changelist,
+ .nchanges = uap->nchanges,
+ .eventlist = uap->eventlist,
+ .nevents = uap->nevents,
+ .timeout = uap->timeout,
+ };
+
+ return (kern_kevent_generic(td, &gk_args, &k_ops));
+}
+#endif
+
int
kern_kevent(struct thread *td, int fd, int nchanges, int nevents,
struct kevent_copyops *k_ops, const struct timespec *timeout)
diff --git a/freebsd/sys/kern/kern_linker.c b/freebsd/sys/kern/kern_linker.c
index 214554d3..1c81a61c 100644
--- a/freebsd/sys/kern/kern_linker.c
+++ b/freebsd/sys/kern/kern_linker.c
@@ -1259,8 +1259,8 @@ kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat)
/* Version 1 fields: */
namelen = strlen(lf->filename) + 1;
- if (namelen > MAXPATHLEN)
- namelen = MAXPATHLEN;
+ if (namelen > sizeof(stat->name))
+ namelen = sizeof(stat->name);
bcopy(lf->filename, &stat->name[0], namelen);
stat->refs = lf->refs;
stat->id = lf->id;
@@ -1268,8 +1268,8 @@ kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat)
stat->size = lf->size;
/* Version 2 fields: */
namelen = strlen(lf->pathname) + 1;
- if (namelen > MAXPATHLEN)
- namelen = MAXPATHLEN;
+ if (namelen > sizeof(stat->pathname))
+ namelen = sizeof(stat->pathname);
bcopy(lf->pathname, &stat->pathname[0], namelen);
sx_xunlock(&kld_sx);
diff --git a/freebsd/sys/kern/kern_uuid.c b/freebsd/sys/kern/kern_uuid.c
index b6a8915f..1ac19685 100644
--- a/freebsd/sys/kern/kern_uuid.c
+++ b/freebsd/sys/kern/kern_uuid.c
@@ -60,7 +60,7 @@ CTASSERT(sizeof(struct uuid) == 16);
/* We use an alternative, more convenient representation in the generator. */
struct uuid_private {
union {
- uint64_t ll; /* internal. */
+ uint64_t ll; /* internal, for uuid_last only */
struct {
uint32_t low;
uint16_t mid;
@@ -428,3 +428,10 @@ parse_uuid(const char *str, struct uuid *uuid)
(c[3] & 0xc0) != 0x80 && /* variant 1? */
(c[3] & 0xe0) != 0xc0) ? EINVAL : 0); /* variant 2? */
}
+
+int
+uuidcmp(const struct uuid *uuid1, const struct uuid *uuid2)
+{
+
+ return (memcmp(uuid1, uuid2, sizeof(struct uuid)));
+}
diff --git a/freebsd/sys/kern/subr_blist.c b/freebsd/sys/kern/subr_blist.c
index 5af51dd4..c8e32c5b 100644
--- a/freebsd/sys/kern/subr_blist.c
+++ b/freebsd/sys/kern/subr_blist.c
@@ -30,18 +30,18 @@
* BLIST.C - Bitmap allocator/deallocator, using a radix tree with hinting
*
* This module implements a general bitmap allocator/deallocator. The
- * allocator eats around 2 bits per 'block'. The module does not
- * try to interpret the meaning of a 'block' other than to return
+ * allocator eats around 2 bits per 'block'. The module does not
+ * try to interpret the meaning of a 'block' other than to return
* SWAPBLK_NONE on an allocation failure.
*
* A radix tree is used to maintain the bitmap. Two radix constants are
* involved: One for the bitmaps contained in the leaf nodes (typically
- * 32), and one for the meta nodes (typically 16). Both meta and leaf
+ * 64), and one for the meta nodes (typically 16). Both meta and leaf
* nodes have a hint field. This field gives us a hint as to the largest
* free contiguous range of blocks under the node. It may contain a
- * value that is too high, but will never contain a value that is too
+ * value that is too high, but will never contain a value that is too
* low. When the radix tree is searched, allocation failures in subtrees
- * update the hint.
+ * update the hint.
*
* The radix tree also implements two collapsed states for meta nodes:
* the ALL-ALLOCATED state and the ALL-FREE state. If a meta node is
@@ -51,7 +51,7 @@
*
* The hinting greatly increases code efficiency for allocations while
* the general radix structure optimizes both allocations and frees. The
- * radix tree should be able to operate well no matter how much
+ * radix tree should be able to operate well no matter how much
* fragmentation there is and no matter how large a bitmap is used.
*
* The blist code wires all necessary memory at creation time. Neither
@@ -63,18 +63,18 @@
* linear array. Each meta node is immediately followed (laid out
* sequentially in memory) by BLIST_META_RADIX lower level nodes. This
* is a recursive structure but one that can be easily scanned through
- * a very simple 'skip' calculation. In order to support large radixes,
- * portions of the tree may reside outside our memory allocation. We
- * handle this with an early-termination optimization (when bighint is
- * set to -1) on the scan. The memory allocation is only large enough
+ * a very simple 'skip' calculation. In order to support large radixes,
+ * portions of the tree may reside outside our memory allocation. We
+ * handle this with an early-termination optimization (when bighint is
+ * set to -1) on the scan. The memory allocation is only large enough
* to cover the number of blocks requested at creation time even if it
* must be encompassed in larger root-node radix.
*
- * NOTE: the allocator cannot currently allocate more than
- * BLIST_BMAP_RADIX blocks per call. It will panic with 'allocation too
- * large' if you try. This is an area that could use improvement. The
- * radix is large enough that this restriction does not effect the swap
- * system, though. Currently only the allocation code is effected by
+ * NOTE: the allocator cannot currently allocate more than
+ * BLIST_BMAP_RADIX blocks per call. It will panic with 'allocation too
+ * large' if you try. This is an area that could use improvement. The
+ * radix is large enough that this restriction does not effect the swap
+ * system, though. Currently only the allocation code is affected by
* this algorithmic unfeature. The freeing code can handle arbitrary
* ranges.
*
@@ -93,7 +93,7 @@ __FBSDID("$FreeBSD$");
#include <sys/blist.h>
#include <sys/malloc.h>
#include <sys/proc.h>
-#include <sys/mutex.h>
+#include <sys/mutex.h>
#else
@@ -101,19 +101,18 @@ __FBSDID("$FreeBSD$");
#define BLIST_DEBUG
#endif
-#define SWAPBLK_NONE ((daddr_t)-1)
-
#include <sys/types.h>
+#include <sys/malloc.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
+#define bitcount64(x) __bitcount64((uint64_t)(x))
#define malloc(a,b,c) calloc(a, 1)
#define free(a,b) free(a)
-typedef unsigned int u_daddr_t;
-
#include <sys/blist.h>
void panic(const char *ctl, ...);
@@ -123,23 +122,23 @@ void panic(const char *ctl, ...);
/*
* static support functions
*/
-
-static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count);
-static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t blk,
- daddr_t count, daddr_t radix, int skip);
+static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count,
+ daddr_t cursor);
+static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count,
+ daddr_t radix, daddr_t skip, daddr_t cursor);
static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count);
-static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count,
- daddr_t radix, int skip, daddr_t blk);
-static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix,
- daddr_t skip, blist_t dest, daddr_t count);
-static int blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count);
-static int blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count,
- daddr_t radix, int skip, daddr_t blk);
-static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix,
- int skip, daddr_t count);
+static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count,
+ daddr_t radix, daddr_t skip, daddr_t blk);
+static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix,
+ daddr_t skip, blist_t dest, daddr_t count);
+static daddr_t blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count);
+static daddr_t blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count,
+ daddr_t radix, daddr_t skip, daddr_t blk);
+static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip,
+ daddr_t count);
#ifndef _KERNEL
-static void blst_radix_print(blmeta_t *scan, daddr_t blk,
- daddr_t radix, int skip, int tab);
+static void blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix,
+ daddr_t skip, int tab);
#endif
#ifdef _KERNEL
@@ -153,35 +152,40 @@ static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space");
* blocks - must be greater than 0
* flags - malloc flags
*
- * The smallest blist consists of a single leaf node capable of
+ * The smallest blist consists of a single leaf node capable of
* managing BLIST_BMAP_RADIX blocks.
*/
-
-blist_t
+blist_t
blist_create(daddr_t blocks, int flags)
{
blist_t bl;
- int radix;
- int skip = 0;
+ daddr_t nodes, radix, skip;
/*
* Calculate radix and skip field used for scanning.
*/
radix = BLIST_BMAP_RADIX;
-
+ skip = 0;
while (radix < blocks) {
radix *= BLIST_META_RADIX;
skip = (skip + 1) * BLIST_META_RADIX;
}
+ nodes = 1 + blst_radix_init(NULL, radix, skip, blocks);
- bl = malloc(sizeof(struct blist), M_SWAP, flags | M_ZERO);
+ bl = malloc(sizeof(struct blist), M_SWAP, flags);
+ if (bl == NULL)
+ return (NULL);
bl->bl_blocks = blocks;
bl->bl_radix = radix;
bl->bl_skip = skip;
- bl->bl_rootblks = 1 +
- blst_radix_init(NULL, bl->bl_radix, bl->bl_skip, blocks);
- bl->bl_root = malloc(sizeof(blmeta_t) * bl->bl_rootblks, M_SWAP, flags);
+ bl->bl_cursor = 0;
+ bl->bl_root = malloc(nodes * sizeof(blmeta_t), M_SWAP, flags);
+ if (bl->bl_root == NULL) {
+ free(bl, M_SWAP);
+ return (NULL);
+ }
+ blst_radix_init(bl->bl_root, radix, skip, blocks);
#if defined(BLIST_DEBUG)
printf(
@@ -189,17 +193,16 @@ blist_create(daddr_t blocks, int flags)
", requiring %lldK of ram\n",
(long long)bl->bl_blocks,
(long long)bl->bl_blocks * 4 / 1024,
- (long long)(bl->bl_rootblks * sizeof(blmeta_t) + 1023) / 1024
+ (long long)(nodes * sizeof(blmeta_t) + 1023) / 1024
);
printf("BLIST raw radix tree contains %lld records\n",
- (long long)bl->bl_rootblks);
+ (long long)nodes);
#endif
- blst_radix_init(bl->bl_root, bl->bl_radix, bl->bl_skip, blocks);
- return(bl);
+ return (bl);
}
-void
+void
blist_destroy(blist_t bl)
{
free(bl->bl_root, M_SWAP);
@@ -207,25 +210,44 @@ blist_destroy(blist_t bl)
}
/*
- * blist_alloc() - reserve space in the block bitmap. Return the base
+ * blist_alloc() - reserve space in the block bitmap. Return the base
* of a contiguous region or SWAPBLK_NONE if space could
* not be allocated.
*/
-
-daddr_t
+daddr_t
blist_alloc(blist_t bl, daddr_t count)
{
- daddr_t blk = SWAPBLK_NONE;
+ daddr_t blk;
- if (bl) {
- if (bl->bl_radix == BLIST_BMAP_RADIX)
- blk = blst_leaf_alloc(bl->bl_root, 0, count);
- else
- blk = blst_meta_alloc(bl->bl_root, 0, count, bl->bl_radix, bl->bl_skip);
- if (blk != SWAPBLK_NONE)
- bl->bl_free -= count;
+ /*
+ * This loop iterates at most twice. An allocation failure in the
+ * first iteration leads to a second iteration only if the cursor was
+ * non-zero. When the cursor is zero, an allocation failure will
+ * reduce the hint, stopping further iterations.
+ */
+ while (count <= bl->bl_root->bm_bighint) {
+ blk = blst_meta_alloc(bl->bl_root, 0, count, bl->bl_radix,
+ bl->bl_skip, bl->bl_cursor);
+ if (blk != SWAPBLK_NONE) {
+ bl->bl_cursor = blk + count;
+ return (blk);
+ } else if (bl->bl_cursor != 0)
+ bl->bl_cursor = 0;
}
- return(blk);
+ return (SWAPBLK_NONE);
+}
+
+/*
+ * blist_avail() - return the number of free blocks.
+ */
+daddr_t
+blist_avail(blist_t bl)
+{
+
+ if (bl->bl_radix == BLIST_BMAP_RADIX)
+ return (bitcount64(bl->bl_root->u.bmu_bitmap));
+ else
+ return (bl->bl_root->u.bmu_avail);
}
/*
@@ -233,17 +255,11 @@ blist_alloc(blist_t bl, daddr_t count)
* of a contiguous region. Panic if an inconsistancy is
* found.
*/
-
-void
+void
blist_free(blist_t bl, daddr_t blkno, daddr_t count)
{
- if (bl) {
- if (bl->bl_radix == BLIST_BMAP_RADIX)
- blst_leaf_free(bl->bl_root, blkno, count);
- else
- blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0);
- bl->bl_free += count;
- }
+
+ blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0);
}
/*
@@ -252,22 +268,12 @@ blist_free(blist_t bl, daddr_t blkno, daddr_t count)
* existing allocations. Return the number of blocks
* actually filled that were free before the call.
*/
-
-int
+daddr_t
blist_fill(blist_t bl, daddr_t blkno, daddr_t count)
{
- int filled;
- if (bl) {
- if (bl->bl_radix == BLIST_BMAP_RADIX)
- filled = blst_leaf_fill(bl->bl_root, blkno, count);
- else
- filled = blst_meta_fill(bl->bl_root, blkno, count,
- bl->bl_radix, bl->bl_skip, 0);
- bl->bl_free -= filled;
- return filled;
- } else
- return 0;
+ return (blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix,
+ bl->bl_skip, 0));
}
/*
@@ -277,7 +283,6 @@ blist_fill(blist_t bl, daddr_t blkno, daddr_t count)
* one. When extending the tree you can specify whether
* the new blocks are to left allocated or freed.
*/
-
void
blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags)
{
@@ -303,7 +308,6 @@ blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags)
/*
* blist_print() - dump radix tree
*/
-
void
blist_print(blist_t bl)
{
@@ -318,7 +322,7 @@ blist_print(blist_t bl)
* ALLOCATION SUPPORT FUNCTIONS *
************************************************************************
*
- * These support functions do all the actual work. They may seem
+ * These support functions do all the actual work. They may seem
* rather longish, but that's because I've commented them up. The
* actual code is straight forward.
*
@@ -327,77 +331,91 @@ blist_print(blist_t bl)
/*
* blist_leaf_alloc() - allocate at a leaf in the radix tree (a bitmap).
*
- * This is the core of the allocator and is optimized for the 1 block
- * and the BLIST_BMAP_RADIX block allocation cases. Other cases are
- * somewhat slower. The 1 block allocation case is log2 and extremely
- * quick.
+ * This is the core of the allocator and is optimized for the
+ * BLIST_BMAP_RADIX block allocation case. Otherwise, execution
+ * time is proportional to log2(count) + log2(BLIST_BMAP_RADIX).
*/
-
static daddr_t
-blst_leaf_alloc(
- blmeta_t *scan,
- daddr_t blk,
- int count
-) {
- u_daddr_t orig = scan->u.bmu_bitmap;
-
- if (orig == 0) {
+blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, daddr_t cursor)
+{
+ u_daddr_t mask;
+ int count1, hi, lo, mid, num_shifts, range1, range_ext;
+
+ if (count == BLIST_BMAP_RADIX) {
/*
- * Optimize bitmap all-allocated case. Also, count = 1
- * case assumes at least 1 bit is free in the bitmap, so
- * we have to take care of this case here.
+ * Optimize allocation of BLIST_BMAP_RADIX bits. If this wasn't
+ * a special case, then forming the final value of 'mask' below
+ * would require special handling to avoid an invalid left shift
+ * when count equals the number of bits in mask.
*/
+ if (~scan->u.bmu_bitmap != 0) {
+ scan->bm_bighint = BLIST_BMAP_RADIX - 1;
+ return (SWAPBLK_NONE);
+ }
+ if (cursor != blk)
+ return (SWAPBLK_NONE);
+ scan->u.bmu_bitmap = 0;
scan->bm_bighint = 0;
- return(SWAPBLK_NONE);
+ return (blk);
}
- if (count == 1) {
+ range1 = 0;
+ count1 = count - 1;
+ num_shifts = fls(count1);
+ mask = scan->u.bmu_bitmap;
+ while (mask != 0 && num_shifts > 0) {
/*
- * Optimized code to allocate one bit out of the bitmap
+ * If bit i is set in mask, then bits in [i, i+range1] are set
+ * in scan->u.bmu_bitmap. The value of range1 is equal to
+ * count1 >> num_shifts. Grow range and reduce num_shifts to 0,
+ * while preserving these invariants. The updates to mask leave
+ * fewer bits set, but each bit that remains set represents a
+ * longer string of consecutive bits set in scan->u.bmu_bitmap.
*/
- u_daddr_t mask;
- int j = BLIST_BMAP_RADIX/2;
- int r = 0;
-
- mask = (u_daddr_t)-1 >> (BLIST_BMAP_RADIX/2);
-
- while (j) {
- if ((orig & mask) == 0) {
- r += j;
- orig >>= j;
- }
- j >>= 1;
- mask >>= j;
- }
- scan->u.bmu_bitmap &= ~(1 << r);
- return(blk + r);
+ num_shifts--;
+ range_ext = range1 + ((count1 >> num_shifts) & 1);
+ mask &= mask >> range_ext;
+ range1 += range_ext;
}
- if (count <= BLIST_BMAP_RADIX) {
+ if (mask == 0) {
/*
- * non-optimized code to allocate N bits out of the bitmap.
- * The more bits, the faster the code runs. It will run
- * the slowest allocating 2 bits, but since there aren't any
- * memory ops in the core loop (or shouldn't be, anyway),
- * you probably won't notice the difference.
+ * Update bighint. There is no allocation bigger than range1
+ * available in this leaf.
*/
- int j;
- int n = BLIST_BMAP_RADIX - count;
- u_daddr_t mask;
+ scan->bm_bighint = range1;
+ return (SWAPBLK_NONE);
+ }
- mask = (u_daddr_t)-1 >> n;
+ /*
+ * Discard any candidates that appear before the cursor.
+ */
+ lo = cursor - blk;
+ mask &= ~(u_daddr_t)0 << lo;
- for (j = 0; j <= n; ++j) {
- if ((orig & mask) == mask) {
- scan->u.bmu_bitmap &= ~mask;
- return(blk + j);
- }
- mask = (mask << 1);
- }
+ if (mask == 0)
+ return (SWAPBLK_NONE);
+
+ /*
+ * The least significant set bit in mask marks the start of the first
+ * available range of sufficient size. Clear all the bits but that one,
+ * and then perform a binary search to find its position.
+ */
+ mask &= -mask;
+ hi = BLIST_BMAP_RADIX - count1;
+ while (lo + 1 < hi) {
+ mid = (lo + hi) >> 1;
+ if ((mask >> mid) != 0)
+ lo = mid;
+ else
+ hi = mid;
}
+
/*
- * We couldn't allocate count in this subtree, update bighint.
+ * Set in mask exactly the bits being allocated, and clear them from
+ * the set of available bits.
*/
- scan->bm_bighint = count - 1;
- return(SWAPBLK_NONE);
+ mask = (mask << count) - mask;
+ scan->u.bmu_bitmap &= ~mask;
+ return (blk + lo);
}
/*
@@ -408,76 +426,75 @@ blst_leaf_alloc(
* calls that hit this node. We have to check for our collapse cases
* and we have a few optimizations strewn in as well.
*/
-
static daddr_t
-blst_meta_alloc(
- blmeta_t *scan,
- daddr_t blk,
- daddr_t count,
- daddr_t radix,
- int skip
-) {
- int i;
- int next_skip = ((u_int)skip / BLIST_META_RADIX);
+blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix,
+ daddr_t skip, daddr_t cursor)
+{
+ daddr_t i, next_skip, r;
+ int child;
+ bool scan_from_start;
- if (scan->u.bmu_avail == 0) {
+ if (radix == BLIST_BMAP_RADIX)
+ return (blst_leaf_alloc(scan, blk, count, cursor));
+ if (scan->u.bmu_avail < count) {
/*
- * ALL-ALLOCATED special case
+ * The meta node's hint must be too large if the allocation
+ * exceeds the number of free blocks. Reduce the hint, and
+ * return failure.
*/
- scan->bm_bighint = count;
- return(SWAPBLK_NONE);
+ scan->bm_bighint = scan->u.bmu_avail;
+ return (SWAPBLK_NONE);
}
+ next_skip = skip / BLIST_META_RADIX;
+ /*
+ * An ALL-FREE meta node requires special handling before allocating
+ * any of its blocks.
+ */
if (scan->u.bmu_avail == radix) {
radix /= BLIST_META_RADIX;
/*
- * ALL-FREE special case, initialize uninitialize
- * sublevel.
+ * Reinitialize each of the meta node's children. An ALL-FREE
+ * meta node cannot have a terminator in any subtree.
*/
for (i = 1; i <= skip; i += next_skip) {
- if (scan[i].bm_bighint == (daddr_t)-1)
- break;
- if (next_skip == 1) {
+ if (next_skip == 1)
scan[i].u.bmu_bitmap = (u_daddr_t)-1;
- scan[i].bm_bighint = BLIST_BMAP_RADIX;
- } else {
- scan[i].bm_bighint = radix;
+ else
scan[i].u.bmu_avail = radix;
- }
+ scan[i].bm_bighint = radix;
}
} else {
radix /= BLIST_META_RADIX;
}
- for (i = 1; i <= skip; i += next_skip) {
+ if (count > radix) {
+ /*
+ * The allocation exceeds the number of blocks that are
+ * managed by a subtree of this meta node.
+ */
+ panic("allocation too large");
+ }
+ scan_from_start = cursor == blk;
+ child = (cursor - blk) / radix;
+ blk += child * radix;
+ for (i = 1 + child * next_skip; i <= skip; i += next_skip) {
if (count <= scan[i].bm_bighint) {
/*
- * count fits in object
+ * The allocation might fit in the i'th subtree.
*/
- daddr_t r;
- if (next_skip == 1) {
- r = blst_leaf_alloc(&scan[i], blk, count);
- } else {
- r = blst_meta_alloc(&scan[i], blk, count, radix, next_skip - 1);
- }
+ r = blst_meta_alloc(&scan[i], blk, count, radix,
+ next_skip - 1, cursor > blk ? cursor : blk);
if (r != SWAPBLK_NONE) {
scan->u.bmu_avail -= count;
- if (scan->bm_bighint > scan->u.bmu_avail)
- scan->bm_bighint = scan->u.bmu_avail;
- return(r);
+ return (r);
}
} else if (scan[i].bm_bighint == (daddr_t)-1) {
/*
* Terminator
*/
break;
- } else if (count > radix) {
- /*
- * count does not fit in object even if it were
- * complete free.
- */
- panic("blist_meta_alloc: allocation too large");
}
blk += radix;
}
@@ -485,22 +502,19 @@ blst_meta_alloc(
/*
* We couldn't allocate count in this subtree, update bighint.
*/
- if (scan->bm_bighint >= count)
+ if (scan_from_start && scan->bm_bighint >= count)
scan->bm_bighint = count - 1;
- return(SWAPBLK_NONE);
+
+ return (SWAPBLK_NONE);
}
/*
* BLST_LEAF_FREE() - free allocated block from leaf bitmap
*
*/
-
static void
-blst_leaf_free(
- blmeta_t *scan,
- daddr_t blk,
- int count
-) {
+blst_leaf_free(blmeta_t *scan, daddr_t blk, int count)
+{
/*
* free some data in this bitmap
*
@@ -521,7 +535,7 @@ blst_leaf_free(
/*
* We could probably do a better job here. We are required to make
- * bighint at least as large as the biggest contiguous block of
+ * bighint at least as large as the biggest contiguous block of
* data. If we just shoehorn it, a little extra overhead will
* be incured on the next allocation (but only that one typically).
*/
@@ -538,25 +552,18 @@ blst_leaf_free(
* range whereas the allocation code cannot allocate an arbitrary
* range).
*/
+static void
+blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix,
+ daddr_t skip, daddr_t blk)
+{
+ daddr_t i, next_skip, v;
+ int child;
-static void
-blst_meta_free(
- blmeta_t *scan,
- daddr_t freeBlk,
- daddr_t count,
- daddr_t radix,
- int skip,
- daddr_t blk
-) {
- int i;
- int next_skip = ((u_int)skip / BLIST_META_RADIX);
-
-#if 0
- printf("free (%llx,%lld) FROM (%llx,%lld)\n",
- (long long)freeBlk, (long long)count,
- (long long)blk, (long long)radix
- );
-#endif
+ if (scan->bm_bighint == (daddr_t)-1)
+ panic("freeing invalid range");
+ if (radix == BLIST_BMAP_RADIX)
+ return (blst_leaf_free(scan, freeBlk, count));
+ next_skip = skip / BLIST_META_RADIX;
if (scan->u.bmu_avail == 0) {
/*
@@ -601,27 +608,16 @@ blst_meta_free(
radix /= BLIST_META_RADIX;
- i = (freeBlk - blk) / radix;
- blk += i * radix;
- i = i * next_skip + 1;
-
+ child = (freeBlk - blk) / radix;
+ blk += child * radix;
+ i = 1 + child * next_skip;
while (i <= skip && blk < freeBlk + count) {
- daddr_t v;
-
v = blk + radix - freeBlk;
if (v > count)
v = count;
-
- if (scan->bm_bighint == (daddr_t)-1)
- panic("blst_meta_free: freeing unexpected range");
-
- if (next_skip == 1) {
- blst_leaf_free(&scan[i], freeBlk, v);
- } else {
- blst_meta_free(&scan[i], freeBlk, v, radix, next_skip - 1, blk);
- }
+ blst_meta_free(&scan[i], freeBlk, v, radix, next_skip - 1, blk);
if (scan->bm_bighint < scan[i].bm_bighint)
- scan->bm_bighint = scan[i].bm_bighint;
+ scan->bm_bighint = scan[i].bm_bighint;
count -= v;
freeBlk += v;
blk += radix;
@@ -635,17 +631,11 @@ blst_meta_free(
* Locates free space in the source tree and frees it in the destination
* tree. The space may not already be free in the destination.
*/
-
-static void blst_copy(
- blmeta_t *scan,
- daddr_t blk,
- daddr_t radix,
- daddr_t skip,
- blist_t dest,
- daddr_t count
-) {
- int next_skip;
- int i;
+static void
+blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip,
+ blist_t dest, daddr_t count)
+{
+ daddr_t i, next_skip;
/*
* Leaf node
@@ -660,7 +650,7 @@ static void blst_copy(
int i;
for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) {
- if (v & (1 << i))
+ if (v & ((u_daddr_t)1 << i))
blist_free(dest, blk + i, 1);
}
}
@@ -676,7 +666,7 @@ static void blst_copy(
* Source all allocated, leave dest allocated
*/
return;
- }
+ }
if (scan->u.bmu_avail == radix) {
/*
* Source all free, free entire dest
@@ -690,32 +680,20 @@ static void blst_copy(
radix /= BLIST_META_RADIX;
- next_skip = ((u_int)skip / BLIST_META_RADIX);
+ next_skip = skip / BLIST_META_RADIX;
for (i = 1; count && i <= skip; i += next_skip) {
if (scan[i].bm_bighint == (daddr_t)-1)
break;
if (count >= radix) {
- blst_copy(
- &scan[i],
- blk,
- radix,
- next_skip - 1,
- dest,
- radix
- );
+ blst_copy(&scan[i], blk, radix, next_skip - 1, dest,
+ radix);
count -= radix;
} else {
if (count) {
- blst_copy(
- &scan[i],
- blk,
- radix,
- next_skip - 1,
- dest,
- count
- );
+ blst_copy(&scan[i], blk, radix, next_skip - 1,
+ dest, count);
}
count = 0;
}
@@ -730,24 +708,21 @@ static void blst_copy(
* regardless of any existing allocations in that range. Returns
* the number of blocks allocated by the call.
*/
-
-static int
+static daddr_t
blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count)
{
int n = blk & (BLIST_BMAP_RADIX - 1);
- int nblks;
- u_daddr_t mask, bitmap;
+ daddr_t nblks;
+ u_daddr_t mask;
mask = ((u_daddr_t)-1 << n) &
((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n));
- /* Count the number of blocks we're about to allocate */
- bitmap = scan->u.bmu_bitmap & mask;
- for (nblks = 0; bitmap != 0; nblks++)
- bitmap &= bitmap - 1;
+ /* Count the number of blocks that we are allocating. */
+ nblks = bitcount64(scan->u.bmu_bitmap & mask);
scan->u.bmu_bitmap &= ~mask;
- return nblks;
+ return (nblks);
}
/*
@@ -758,80 +733,74 @@ blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count)
* range must be within the extent of this node. Returns the
* number of blocks allocated by the call.
*/
-static int
-blst_meta_fill(
- blmeta_t *scan,
- daddr_t allocBlk,
- daddr_t count,
- daddr_t radix,
- int skip,
- daddr_t blk
-) {
- int i;
- int next_skip = ((u_int)skip / BLIST_META_RADIX);
- int nblks = 0;
+static daddr_t
+blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix,
+ daddr_t skip, daddr_t blk)
+{
+ daddr_t i, nblks, next_skip, v;
+ int child;
+ if (scan->bm_bighint == (daddr_t)-1)
+ panic("filling invalid range");
+ if (count > radix) {
+ /*
+ * The allocation exceeds the number of blocks that are
+ * managed by this node.
+ */
+ panic("fill too large");
+ }
+ if (radix == BLIST_BMAP_RADIX)
+ return (blst_leaf_fill(scan, allocBlk, count));
if (count == radix || scan->u.bmu_avail == 0) {
/*
* ALL-ALLOCATED special case
*/
nblks = scan->u.bmu_avail;
scan->u.bmu_avail = 0;
- scan->bm_bighint = count;
- return nblks;
+ scan->bm_bighint = 0;
+ return (nblks);
}
+ next_skip = skip / BLIST_META_RADIX;
+ /*
+ * An ALL-FREE meta node requires special handling before allocating
+ * any of its blocks.
+ */
if (scan->u.bmu_avail == radix) {
radix /= BLIST_META_RADIX;
/*
- * ALL-FREE special case, initialize sublevel
+ * Reinitialize each of the meta node's children. An ALL-FREE
+ * meta node cannot have a terminator in any subtree.
*/
for (i = 1; i <= skip; i += next_skip) {
- if (scan[i].bm_bighint == (daddr_t)-1)
- break;
- if (next_skip == 1) {
+ if (next_skip == 1)
scan[i].u.bmu_bitmap = (u_daddr_t)-1;
- scan[i].bm_bighint = BLIST_BMAP_RADIX;
- } else {
- scan[i].bm_bighint = radix;
+ else
scan[i].u.bmu_avail = radix;
- }
+ scan[i].bm_bighint = radix;
}
} else {
radix /= BLIST_META_RADIX;
}
- if (count > radix)
- panic("blist_meta_fill: allocation too large");
-
- i = (allocBlk - blk) / radix;
- blk += i * radix;
- i = i * next_skip + 1;
-
+ nblks = 0;
+ child = (allocBlk - blk) / radix;
+ blk += child * radix;
+ i = 1 + child * next_skip;
while (i <= skip && blk < allocBlk + count) {
- daddr_t v;
-
v = blk + radix - allocBlk;
if (v > count)
v = count;
-
- if (scan->bm_bighint == (daddr_t)-1)
- panic("blst_meta_fill: filling unexpected range");
-
- if (next_skip == 1) {
- nblks += blst_leaf_fill(&scan[i], allocBlk, v);
- } else {
- nblks += blst_meta_fill(&scan[i], allocBlk, v,
- radix, next_skip - 1, blk);
- }
+ nblks += blst_meta_fill(&scan[i], allocBlk, v, radix,
+ next_skip - 1, blk);
count -= v;
allocBlk += v;
blk += radix;
i += next_skip;
}
scan->u.bmu_avail -= nblks;
- return nblks;
+ return (nblks);
}
/*
@@ -842,13 +811,12 @@ blst_meta_fill(
* be considerably less than the calculated radix due to the large
* RADIX values we use.
*/
-
-static daddr_t
-blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count)
+static daddr_t
+blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, daddr_t count)
{
- int i;
- int next_skip;
- daddr_t memindex = 0;
+ daddr_t i, memindex, next_skip;
+
+ memindex = 0;
/*
* Leaf node
@@ -859,7 +827,7 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count)
scan->bm_bighint = 0;
scan->u.bmu_bitmap = 0;
}
- return(memindex);
+ return (memindex);
}
/*
@@ -874,30 +842,24 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count)
}
radix /= BLIST_META_RADIX;
- next_skip = ((u_int)skip / BLIST_META_RADIX);
+ next_skip = skip / BLIST_META_RADIX;
for (i = 1; i <= skip; i += next_skip) {
if (count >= radix) {
/*
* Allocate the entire object
*/
- memindex = i + blst_radix_init(
- ((scan) ? &scan[i] : NULL),
- radix,
- next_skip - 1,
- radix
- );
+ memindex = i +
+ blst_radix_init(((scan) ? &scan[i] : NULL), radix,
+ next_skip - 1, radix);
count -= radix;
} else if (count > 0) {
/*
* Allocate a partial object
*/
- memindex = i + blst_radix_init(
- ((scan) ? &scan[i] : NULL),
- radix,
- next_skip - 1,
- count
- );
+ memindex = i +
+ blst_radix_init(((scan) ? &scan[i] : NULL), radix,
+ next_skip - 1, count);
count = 0;
} else {
/*
@@ -910,21 +872,20 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, int skip, daddr_t count)
}
if (memindex < i)
memindex = i;
- return(memindex);
+ return (memindex);
}
#ifdef BLIST_DEBUG
-static void
-blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int skip, int tab)
+static void
+blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip,
+ int tab)
{
- int i;
- int next_skip;
- int lastState = 0;
+ daddr_t i, next_skip;
if (radix == BLIST_BMAP_RADIX) {
printf(
- "%*.*s(%08llx,%lld): bitmap %08llx big=%lld\n",
+ "%*.*s(%08llx,%lld): bitmap %016llx big=%lld\n",
tab, tab, "",
(long long)blk, (long long)radix,
(long long)scan->u.bmu_bitmap,
@@ -962,7 +923,7 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int skip, int tab)
);
radix /= BLIST_META_RADIX;
- next_skip = ((u_int)skip / BLIST_META_RADIX);
+ next_skip = skip / BLIST_META_RADIX;
tab += 4;
for (i = 1; i <= skip; i += next_skip) {
@@ -972,16 +933,9 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int skip, int tab)
tab, tab, "",
(long long)blk, (long long)radix
);
- lastState = 0;
break;
}
- blst_radix_print(
- &scan[i],
- blk,
- radix,
- next_skip - 1,
- tab
- );
+ blst_radix_print(&scan[i], blk, radix, next_skip - 1, tab);
blk += radix;
}
tab -= 4;
@@ -1018,11 +972,10 @@ main(int ac, char **av)
for (;;) {
char buf[1024];
- daddr_t da = 0;
- daddr_t count = 0;
-
+ long long da = 0;
+ long long count = 0;
- printf("%lld/%lld/%lld> ", (long long)bl->bl_free,
+ printf("%lld/%lld/%lld> ", (long long)blist_avail(bl),
(long long)size, (long long)bl->bl_radix);
fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
@@ -1030,7 +983,7 @@ main(int ac, char **av)
switch(buf[0]) {
case 'r':
if (sscanf(buf + 1, "%lld", &count) == 1) {
- blist_resize(&bl, count, 1);
+ blist_resize(&bl, count, 1, M_WAITOK);
} else {
printf("?\n");
}
@@ -1046,18 +999,16 @@ main(int ac, char **av)
}
break;
case 'f':
- if (sscanf(buf + 1, "%llx %lld",
- (long long *)&da, (long long *)&count) == 2) {
+ if (sscanf(buf + 1, "%llx %lld", &da, &count) == 2) {
blist_free(bl, da, count);
} else {
printf("?\n");
}
break;
case 'l':
- if (sscanf(buf + 1, "%llx %lld",
- (long long *)&da, (long long *)&count) == 2) {
- printf(" n=%d\n",
- blist_fill(bl, da, count));
+ if (sscanf(buf + 1, "%llx %lld", &da, &count) == 2) {
+ printf(" n=%jd\n",
+ (intmax_t)blist_fill(bl, da, count));
} else {
printf("?\n");
}
@@ -1094,4 +1045,3 @@ panic(const char *ctl, ...)
}
#endif
-
diff --git a/freebsd/sys/kern/subr_prf.c b/freebsd/sys/kern/subr_prf.c
index 39f5826d..0380cfec 100644
--- a/freebsd/sys/kern/subr_prf.c
+++ b/freebsd/sys/kern/subr_prf.c
@@ -411,7 +411,6 @@ log_console(struct uio *uio)
msgbuftrigger = 1;
free(uio, M_IOV);
free(consbuffer, M_TEMP);
- return;
}
#endif /* __rtems__ */
@@ -678,7 +677,7 @@ kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_lis
uintmax_t num;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int cflag, hflag, jflag, tflag, zflag;
- int dwidth, upper;
+ int bconv, dwidth, upper;
char padc;
int stop = 0, retval = 0;
@@ -704,7 +703,7 @@ kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_lis
}
percent = fmt - 1;
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
- sign = 0; dot = 0; dwidth = 0; upper = 0;
+ sign = 0; dot = 0; bconv = 0; dwidth = 0; upper = 0;
cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
reswitch: switch (ch = (u_char)*fmt++) {
case '.':
@@ -752,28 +751,9 @@ reswitch: switch (ch = (u_char)*fmt++) {
width = n;
goto reswitch;
case 'b':
- num = (u_int)va_arg(ap, int);
- p = va_arg(ap, char *);
- for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
- PCHAR(*q--);
-
- if (num == 0)
- break;
-
- for (tmp = 0; *p;) {
- n = *p++;
- if (num & (1 << (n - 1))) {
- PCHAR(tmp ? ',' : '<');
- for (; (n = *p) > ' '; ++p)
- PCHAR(n);
- tmp = 1;
- } else
- for (; *p > ' '; ++p)
- continue;
- }
- if (tmp)
- PCHAR('>');
- break;
+ ladjust = 1;
+ bconv = 1;
+ goto handle_nosign;
case 'c':
width -= 1;
@@ -919,6 +899,10 @@ handle_nosign:
num = (u_char)va_arg(ap, int);
else
num = va_arg(ap, u_int);
+ if (bconv) {
+ q = va_arg(ap, char *);
+ base = *q++;
+ }
goto number;
handle_sign:
if (jflag)
@@ -976,6 +960,26 @@ number:
while (*p)
PCHAR(*p--);
+ if (bconv && num != 0) {
+ /* %b conversion flag format. */
+ tmp = retval;
+ while (*q) {
+ n = *q++;
+ if (num & (1 << (n - 1))) {
+ PCHAR(retval != tmp ?
+ ',' : '<');
+ for (; (n = *q) > ' '; ++q)
+ PCHAR(n);
+ } else
+ for (; *q > ' '; ++q)
+ continue;
+ }
+ if (retval != tmp) {
+ PCHAR('>');
+ width -= retval - tmp;
+ }
+ }
+
if (ladjust)
while (width-- > 0)
PCHAR(' ');
diff --git a/freebsd/sys/kern/subr_sbuf.c b/freebsd/sys/kern/subr_sbuf.c
index 680613b1..8dd11b07 100644
--- a/freebsd/sys/kern/subr_sbuf.c
+++ b/freebsd/sys/kern/subr_sbuf.c
@@ -106,7 +106,7 @@ _assert_sbuf_integrity(const char *fun, struct sbuf *s)
("%s called with a NULL sbuf pointer", fun));
KASSERT(s->s_buf != NULL,
("%s called with uninitialized or corrupt sbuf", fun));
- if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
+ if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
KASSERT(s->s_len <= s->s_size,
("wrote past end of sbuf (%jd >= %jd)",
(intmax_t)s->s_len, (intmax_t)s->s_size));
diff --git a/freebsd/sys/kern/subr_taskqueue.c b/freebsd/sys/kern/subr_taskqueue.c
index 6f1ba19a..74b9cf59 100644
--- a/freebsd/sys/kern/subr_taskqueue.c
+++ b/freebsd/sys/kern/subr_taskqueue.c
@@ -316,8 +316,8 @@ taskqueue_timeout_func(void *arg)
}
int
-taskqueue_enqueue_timeout(struct taskqueue *queue,
- struct timeout_task *timeout_task, int ticks)
+taskqueue_enqueue_timeout_sbt(struct taskqueue *queue,
+ struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr, int flags)
{
int res;
@@ -333,7 +333,7 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
/* Do nothing */
TQ_UNLOCK(queue);
res = -1;
- } else if (ticks == 0) {
+ } else if (sbt == 0) {
taskqueue_enqueue_locked(queue, &timeout_task->t);
/* The lock is released inside. */
} else {
@@ -342,18 +342,27 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
} else {
queue->tq_callouts++;
timeout_task->f |= DT_CALLOUT_ARMED;
- if (ticks < 0)
- ticks = -ticks; /* Ignore overflow. */
+ if (sbt < 0)
+ sbt = -sbt; /* Ignore overflow. */
}
- if (ticks > 0) {
- callout_reset(&timeout_task->c, ticks,
- taskqueue_timeout_func, timeout_task);
+ if (sbt > 0) {
+ callout_reset_sbt(&timeout_task->c, sbt, pr,
+ taskqueue_timeout_func, timeout_task, flags);
}
TQ_UNLOCK(queue);
}
return (res);
}
+int
+taskqueue_enqueue_timeout(struct taskqueue *queue,
+ struct timeout_task *ttask, int ticks)
+{
+
+ return (taskqueue_enqueue_timeout_sbt(queue, ttask, ticks * tick_sbt,
+ 0, 0));
+}
+
static void
taskqueue_task_nop_fn(void *context, int pending)
{
diff --git a/freebsd/sys/kern/subr_uio.c b/freebsd/sys/kern/subr_uio.c
index 5740e667..904ef1f4 100644
--- a/freebsd/sys/kern/subr_uio.c
+++ b/freebsd/sys/kern/subr_uio.c
@@ -212,41 +212,37 @@ uiomove_nofault(void *cp, int n, struct uio *uio)
static int
uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault)
{
-#ifndef __rtems__
- struct thread *td;
-#endif /* __rtems__ */
struct iovec *iov;
size_t cnt;
- int error, newflags, save;
-
#ifndef __rtems__
- td = curthread;
+ int error, newflags, save;
+#else /* __rtems__ */
+ int error;
#endif /* __rtems__ */
+
error = 0;
+#ifndef __rtems__
KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
("uiomove: mode"));
-#ifndef __rtems__
- KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == td,
+ KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
("uiomove proc"));
-#endif /* __rtems__ */
- if (!nofault)
- WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
- "Calling uiomove()");
-#ifndef __rtems__
- /* XXX does it make a sense to set TDP_DEADLKTREAT for UIO_SYSSPACE ? */
- newflags = TDP_DEADLKTREAT;
- if (uio->uio_segflg == UIO_USERSPACE && nofault) {
- /*
- * Fail if a non-spurious page fault occurs.
- */
- newflags |= TDP_NOFAULTING | TDP_RESETSPUR;
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ newflags = TDP_DEADLKTREAT;
+ if (nofault) {
+ /*
+ * Fail if a non-spurious page fault occurs.
+ */
+ newflags |= TDP_NOFAULTING | TDP_RESETSPUR;
+ } else {
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+ "Calling uiomove()");
+ }
+ save = curthread_pflags_set(newflags);
+ } else {
+ KASSERT(nofault == 0, ("uiomove: nofault"));
}
- save = curthread_pflags_set(newflags);
-#else /* __rtems__ */
- (void) newflags;
- (void) save;
#endif /* __rtems__ */
while (n > 0 && uio->uio_resid) {
@@ -292,7 +288,8 @@ uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault)
}
out:
#ifndef __rtems__
- curthread_pflags_restore(save);
+ if (uio->uio_segflg == UIO_USERSPACE)
+ curthread_pflags_restore(save);
#endif /* __rtems__ */
return (error);
}
diff --git a/freebsd/sys/kern/sys_socket.c b/freebsd/sys/kern/sys_socket.c
index 8d87c51b..9dd458f1 100644
--- a/freebsd/sys/kern/sys_socket.c
+++ b/freebsd/sys/kern/sys_socket.c
@@ -318,32 +318,36 @@ soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred,
break;
case FIOASYNC:
- /*
- * XXXRW: This code separately acquires SOCK_LOCK(so) and
- * SOCKBUF_LOCK(&so->so_rcv) even though they are the same
- * mutex to avoid introducing the assumption that they are
- * the same.
- */
if (*(int *)data) {
SOCK_LOCK(so);
so->so_state |= SS_ASYNC;
+ if (SOLISTENING(so)) {
+ so->sol_sbrcv_flags |= SB_ASYNC;
+ so->sol_sbsnd_flags |= SB_ASYNC;
+ } else {
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_rcv.sb_flags |= SB_ASYNC;
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ SOCKBUF_LOCK(&so->so_snd);
+ so->so_snd.sb_flags |= SB_ASYNC;
+ SOCKBUF_UNLOCK(&so->so_snd);
+ }
SOCK_UNLOCK(so);
- SOCKBUF_LOCK(&so->so_rcv);
- so->so_rcv.sb_flags |= SB_ASYNC;
- SOCKBUF_UNLOCK(&so->so_rcv);
- SOCKBUF_LOCK(&so->so_snd);
- so->so_snd.sb_flags |= SB_ASYNC;
- SOCKBUF_UNLOCK(&so->so_snd);
} else {
SOCK_LOCK(so);
so->so_state &= ~SS_ASYNC;
+ if (SOLISTENING(so)) {
+ so->sol_sbrcv_flags &= ~SB_ASYNC;
+ so->sol_sbsnd_flags &= ~SB_ASYNC;
+ } else {
+ SOCKBUF_LOCK(&so->so_rcv);
+ so->so_rcv.sb_flags &= ~SB_ASYNC;
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ SOCKBUF_LOCK(&so->so_snd);
+ so->so_snd.sb_flags &= ~SB_ASYNC;
+ SOCKBUF_UNLOCK(&so->so_snd);
+ }
SOCK_UNLOCK(so);
- SOCKBUF_LOCK(&so->so_rcv);
- so->so_rcv.sb_flags &= ~SB_ASYNC;
- SOCKBUF_UNLOCK(&so->so_rcv);
- SOCKBUF_LOCK(&so->so_snd);
- so->so_snd.sb_flags &= ~SB_ASYNC;
- SOCKBUF_UNLOCK(&so->so_snd);
}
break;
@@ -477,7 +481,6 @@ static int
soo_stat(struct socket *so, struct stat *ub)
{
#endif /* __rtems__ */
- struct sockbuf *sb;
#ifdef MAC
int error;
#endif
@@ -491,22 +494,26 @@ soo_stat(struct socket *so, struct stat *ub)
if (error)
return (error);
#endif
- /*
- * If SBS_CANTRCVMORE is set, but there's still data left in the
- * receive buffer, the socket is still readable.
- */
- sb = &so->so_rcv;
- SOCKBUF_LOCK(sb);
- if ((sb->sb_state & SBS_CANTRCVMORE) == 0 || sbavail(sb))
- ub->st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
- ub->st_size = sbavail(sb) - sb->sb_ctl;
- SOCKBUF_UNLOCK(sb);
+ if (!SOLISTENING(so)) {
+ struct sockbuf *sb;
- sb = &so->so_snd;
- SOCKBUF_LOCK(sb);
- if ((sb->sb_state & SBS_CANTSENDMORE) == 0)
- ub->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
- SOCKBUF_UNLOCK(sb);
+ /*
+ * If SBS_CANTRCVMORE is set, but there's still data left
+ * in the receive buffer, the socket is still readable.
+ */
+ sb = &so->so_rcv;
+ SOCKBUF_LOCK(sb);
+ if ((sb->sb_state & SBS_CANTRCVMORE) == 0 || sbavail(sb))
+ ub->st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
+ ub->st_size = sbavail(sb) - sb->sb_ctl;
+ SOCKBUF_UNLOCK(sb);
+
+ sb = &so->so_snd;
+ SOCKBUF_LOCK(sb);
+ if ((sb->sb_state & SBS_CANTSENDMORE) == 0)
+ ub->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+ SOCKBUF_UNLOCK(sb);
+ }
#ifndef __rtems__
ub->st_uid = so->so_cred->cr_uid;
ub->st_gid = so->so_cred->cr_gid;
@@ -916,6 +923,7 @@ soaio_process_sb(struct socket *so, struct sockbuf *sb)
{
struct kaiocb *job;
+ CURVNET_SET(so->so_vnet);
SOCKBUF_LOCK(sb);
while (!TAILQ_EMPTY(&sb->sb_aiojobq) && soaio_ready(so, sb)) {
job = TAILQ_FIRST(&sb->sb_aiojobq);
@@ -936,9 +944,9 @@ soaio_process_sb(struct socket *so, struct sockbuf *sb)
sb->sb_flags &= ~SB_AIO_RUNNING;
SOCKBUF_UNLOCK(sb);
- ACCEPT_LOCK();
SOCK_LOCK(so);
sorele(so);
+ CURVNET_RESTORE();
}
void
diff --git a/freebsd/sys/kern/uipc_accf.c b/freebsd/sys/kern/uipc_accf.c
index a766adf8..8a0e14e3 100644
--- a/freebsd/sys/kern/uipc_accf.c
+++ b/freebsd/sys/kern/uipc_accf.c
@@ -132,8 +132,7 @@ accept_filt_generic_mod_event(module_t mod, int event, void *data)
switch (event) {
case MOD_LOAD:
- p = malloc(sizeof(*p), M_ACCF,
- M_WAITOK);
+ p = malloc(sizeof(*p), M_ACCF, M_WAITOK);
bcopy(accfp, p, sizeof(*p));
error = accept_filt_add(p);
break;
@@ -164,26 +163,25 @@ accept_filt_generic_mod_event(module_t mod, int event, void *data)
}
int
-do_getopt_accept_filter(struct socket *so, struct sockopt *sopt)
+accept_filt_getopt(struct socket *so, struct sockopt *sopt)
{
struct accept_filter_arg *afap;
int error;
error = 0;
- afap = malloc(sizeof(*afap), M_TEMP,
- M_WAITOK | M_ZERO);
+ afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK | M_ZERO);
SOCK_LOCK(so);
if ((so->so_options & SO_ACCEPTCONN) == 0) {
error = EINVAL;
goto out;
}
- if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ if (so->sol_accept_filter == NULL) {
error = EINVAL;
goto out;
}
- strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
- if (so->so_accf->so_accept_filter_str != NULL)
- strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
+ strcpy(afap->af_name, so->sol_accept_filter->accf_name);
+ if (so->sol_accept_filter_str != NULL)
+ strcpy(afap->af_arg, so->sol_accept_filter_str);
out:
SOCK_UNLOCK(so);
if (error == 0)
@@ -193,35 +191,61 @@ out:
}
int
-do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
+accept_filt_setopt(struct socket *so, struct sockopt *sopt)
{
struct accept_filter_arg *afap;
struct accept_filter *afp;
- struct so_accf *newaf;
- int error = 0;
+ char *accept_filter_str = NULL;
+ void *accept_filter_arg = NULL;
+ int error;
/*
* Handle the simple delete case first.
*/
if (sopt == NULL || sopt->sopt_val == NULL) {
+ struct socket *sp, *sp1;
+ int wakeup;
+
SOCK_LOCK(so);
if ((so->so_options & SO_ACCEPTCONN) == 0) {
SOCK_UNLOCK(so);
return (EINVAL);
}
- if (so->so_accf != NULL) {
- struct so_accf *af = so->so_accf;
- if (af->so_accept_filter != NULL &&
- af->so_accept_filter->accf_destroy != NULL) {
- af->so_accept_filter->accf_destroy(so);
- }
- if (af->so_accept_filter_str != NULL)
- free(af->so_accept_filter_str, M_ACCF);
- free(af, M_ACCF);
- so->so_accf = NULL;
+ if (so->sol_accept_filter == NULL) {
+ SOCK_UNLOCK(so);
+ return (0);
}
+ if (so->sol_accept_filter->accf_destroy != NULL)
+ so->sol_accept_filter->accf_destroy(so);
+ if (so->sol_accept_filter_str != NULL)
+ free(so->sol_accept_filter_str, M_ACCF);
+ so->sol_accept_filter = NULL;
+ so->sol_accept_filter_arg = NULL;
+ so->sol_accept_filter_str = NULL;
so->so_options &= ~SO_ACCEPTFILTER;
- SOCK_UNLOCK(so);
+
+ /*
+ * Move from incomplete queue to complete only those
+ * connections, that are blocked by us.
+ */
+ wakeup = 0;
+ TAILQ_FOREACH_SAFE(sp, &so->sol_incomp, so_list, sp1) {
+ SOCK_LOCK(sp);
+ if (sp->so_options & SO_ACCEPTFILTER) {
+ TAILQ_REMOVE(&so->sol_incomp, sp, so_list);
+ TAILQ_INSERT_TAIL(&so->sol_comp, sp, so_list);
+ sp->so_qstate = SQ_COMP;
+ sp->so_options &= ~SO_ACCEPTFILTER;
+ so->sol_incqlen--;
+ so->sol_qlen++;
+ wakeup = 1;
+ }
+ SOCK_UNLOCK(sp);
+ }
+ if (wakeup)
+ solisten_wakeup(so); /* unlocks */
+ else
+ SOLISTEN_UNLOCK(so);
return (0);
}
@@ -229,8 +253,7 @@ do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
* Pre-allocate any memory we may need later to avoid blocking at
* untimely moments. This does not optimize for invalid arguments.
*/
- afap = malloc(sizeof(*afap), M_TEMP,
- M_WAITOK);
+ afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK);
error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap);
afap->af_name[sizeof(afap->af_name)-1] = '\0';
afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
@@ -243,19 +266,10 @@ do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
free(afap, M_TEMP);
return (ENOENT);
}
- /*
- * Allocate the new accept filter instance storage. We may
- * have to free it again later if we fail to attach it. If
- * attached properly, 'newaf' is NULLed to avoid a free()
- * while in use.
- */
- newaf = malloc(sizeof(*newaf), M_ACCF, M_WAITOK |
- M_ZERO);
if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
size_t len = strlen(afap->af_name) + 1;
- newaf->so_accept_filter_str = malloc(len, M_ACCF,
- M_WAITOK);
- strcpy(newaf->so_accept_filter_str, afap->af_name);
+ accept_filter_str = malloc(len, M_ACCF, M_WAITOK);
+ strcpy(accept_filter_str, afap->af_name);
}
/*
@@ -263,8 +277,8 @@ do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
* without first removing it.
*/
SOCK_LOCK(so);
- if (((so->so_options & SO_ACCEPTCONN) == 0) ||
- (so->so_accf != NULL)) {
+ if ((so->so_options & SO_ACCEPTCONN) == 0 ||
+ so->sol_accept_filter != NULL) {
error = EINVAL;
goto out;
}
@@ -275,25 +289,20 @@ do_setopt_accept_filter(struct socket *so, struct sockopt *sopt)
* can't block.
*/
if (afp->accf_create != NULL) {
- newaf->so_accept_filter_arg =
- afp->accf_create(so, afap->af_arg);
- if (newaf->so_accept_filter_arg == NULL) {
+ accept_filter_arg = afp->accf_create(so, afap->af_arg);
+ if (accept_filter_arg == NULL) {
error = EINVAL;
goto out;
}
}
- newaf->so_accept_filter = afp;
- so->so_accf = newaf;
+ so->sol_accept_filter = afp;
+ so->sol_accept_filter_arg = accept_filter_arg;
+ so->sol_accept_filter_str = accept_filter_str;
so->so_options |= SO_ACCEPTFILTER;
- newaf = NULL;
out:
SOCK_UNLOCK(so);
- if (newaf != NULL) {
- if (newaf->so_accept_filter_str != NULL)
- free(newaf->so_accept_filter_str, M_ACCF);
- free(newaf, M_ACCF);
- }
- if (afap != NULL)
- free(afap, M_TEMP);
+ if (accept_filter_str != NULL)
+ free(accept_filter_str, M_ACCF);
+ free(afap, M_TEMP);
return (error);
}
diff --git a/freebsd/sys/kern/uipc_mbuf.c b/freebsd/sys/kern/uipc_mbuf.c
index ba8a2d48..abc30dd3 100644
--- a/freebsd/sys/kern/uipc_mbuf.c
+++ b/freebsd/sys/kern/uipc_mbuf.c
@@ -1519,7 +1519,7 @@ m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
* the total data supplied by the uio.
*/
if (len > 0)
- total = min(uio->uio_resid, len);
+ total = (uio->uio_resid < len) ? uio->uio_resid : len;
else
total = uio->uio_resid;
diff --git a/freebsd/sys/kern/uipc_sockbuf.c b/freebsd/sys/kern/uipc_sockbuf.c
index 04193c29..4b710a2c 100644
--- a/freebsd/sys/kern/uipc_sockbuf.c
+++ b/freebsd/sys/kern/uipc_sockbuf.c
@@ -316,14 +316,14 @@ sowakeup(struct socket *so, struct sockbuf *sb)
SOCKBUF_LOCK_ASSERT(sb);
- selwakeuppri(&sb->sb_sel, PSOCK);
- if (!SEL_WAITING(&sb->sb_sel))
+ selwakeuppri(sb->sb_sel, PSOCK);
+ if (!SEL_WAITING(sb->sb_sel))
sb->sb_flags &= ~SB_SEL;
if (sb->sb_flags & SB_WAIT) {
sb->sb_flags &= ~SB_WAIT;
wakeup(&sb->sb_acc);
}
- KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
+ KNOTE_LOCKED(&sb->sb_sel->si_note, 0);
if (sb->sb_upcall != NULL) {
ret = sb->sb_upcall(so, sb->sb_upcallarg, M_NOWAIT);
if (ret == SU_ISCONNECTED) {
@@ -336,7 +336,7 @@ sowakeup(struct socket *so, struct sockbuf *sb)
if (sb->sb_flags & SB_AIO)
sowakeup_aio(so, sb);
SOCKBUF_UNLOCK(sb);
- if (ret == SU_ISCONNECTED)
+ if (ret == SU_ISCONNECTED && !(so->so_state & SS_ISDISCONNECTED))
soisconnected(so);
if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
pgsigio(&so->so_sigio, SIGIO, 0);
@@ -457,14 +457,78 @@ sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so,
}
int
-sbreserve(struct sockbuf *sb, u_long cc, struct socket *so,
- struct thread *td)
+sbsetopt(struct socket *so, int cmd, u_long cc)
{
+ struct sockbuf *sb;
+ short *flags;
+ u_int *hiwat, *lowat;
int error;
- SOCKBUF_LOCK(sb);
- error = sbreserve_locked(sb, cc, so, td);
- SOCKBUF_UNLOCK(sb);
+ SOCK_LOCK(so);
+ if (SOLISTENING(so)) {
+ switch (cmd) {
+ case SO_SNDLOWAT:
+ case SO_SNDBUF:
+ lowat = &so->sol_sbsnd_lowat;
+ hiwat = &so->sol_sbsnd_hiwat;
+ flags = &so->sol_sbsnd_flags;
+ break;
+ case SO_RCVLOWAT:
+ case SO_RCVBUF:
+ lowat = &so->sol_sbrcv_lowat;
+ hiwat = &so->sol_sbrcv_hiwat;
+ flags = &so->sol_sbrcv_flags;
+ break;
+ }
+ } else {
+ switch (cmd) {
+ case SO_SNDLOWAT:
+ case SO_SNDBUF:
+ sb = &so->so_snd;
+ break;
+ case SO_RCVLOWAT:
+ case SO_RCVBUF:
+ sb = &so->so_rcv;
+ break;
+ }
+ flags = &sb->sb_flags;
+ hiwat = &sb->sb_hiwat;
+ lowat = &sb->sb_lowat;
+ SOCKBUF_LOCK(sb);
+ }
+
+ error = 0;
+ switch (cmd) {
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ if (SOLISTENING(so)) {
+ if (cc > sb_max_adj) {
+ error = ENOBUFS;
+ break;
+ }
+ *hiwat = cc;
+ if (*lowat > *hiwat)
+ *lowat = *hiwat;
+ } else {
+ if (!sbreserve_locked(sb, cc, so, curthread))
+ error = ENOBUFS;
+ }
+ if (error == 0)
+ *flags &= ~SB_AUTOSIZE;
+ break;
+ case SO_SNDLOWAT:
+ case SO_RCVLOWAT:
+ /*
+ * Make sure the low-water is never greater than the
+ * high-water.
+ */
+ *lowat = (cc > *hiwat) ? *hiwat : cc;
+ break;
+ }
+
+ if (!SOLISTENING(so))
+ SOCKBUF_UNLOCK(sb);
+ SOCK_UNLOCK(so);
return (error);
}
diff --git a/freebsd/sys/kern/uipc_socket.c b/freebsd/sys/kern/uipc_socket.c
index c52a543c..1773606d 100644
--- a/freebsd/sys/kern/uipc_socket.c
+++ b/freebsd/sys/kern/uipc_socket.c
@@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_compat.h>
+#include <rtems/bsd/local/opt_sctp.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -160,13 +161,21 @@ __FBSDID("$FreeBSD$");
static int soreceive_rcvoob(struct socket *so, struct uio *uio,
int flags);
+static void so_rdknl_lock(void *);
+static void so_rdknl_unlock(void *);
+static void so_rdknl_assert_locked(void *);
+static void so_rdknl_assert_unlocked(void *);
+static void so_wrknl_lock(void *);
+static void so_wrknl_unlock(void *);
+static void so_wrknl_assert_locked(void *);
+static void so_wrknl_assert_unlocked(void *);
static void filt_sordetach(struct knote *kn);
static int filt_soread(struct knote *kn, long hint);
static void filt_sowdetach(struct knote *kn);
static int filt_sowrite(struct knote *kn, long hint);
-static int inline hhook_run_socket(struct socket *so, void *hctx, int32_t h_id);
static int filt_soempty(struct knote *kn, long hint);
+static int inline hhook_run_socket(struct socket *so, void *hctx, int32_t h_id);
#ifdef __rtems__
static
#endif /* __rtems__ */
@@ -412,8 +421,16 @@ soalloc(struct vnet *vnet)
return (NULL);
}
+ /*
+ * The socket locking protocol allows to lock 2 sockets at a time,
+ * however, the first one must be a listening socket. WITNESS lacks
+ * a feature to change class of an existing lock, so we use DUPOK.
+ */
+ mtx_init(&so->so_lock, "socket", NULL, MTX_DEF | MTX_DUPOK);
SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd");
SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv");
+ so->so_rcv.sb_sel = &so->so_rdsel;
+ so->so_snd.sb_sel = &so->so_wrsel;
sx_init(&so->so_snd.sb_sx, "so_snd_sx");
sx_init(&so->so_rcv.sb_sx, "so_rcv_sx");
#ifndef __rtems__
@@ -465,15 +482,6 @@ sodealloc(struct socket *so)
so->so_vnet->vnet_sockcnt--;
#endif
mtx_unlock(&so_global_mtx);
- if (so->so_rcv.sb_hiwat)
- (void)chgsbsize(so->so_cred->cr_uidinfo,
- &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY);
- if (so->so_snd.sb_hiwat)
- (void)chgsbsize(so->so_cred->cr_uidinfo,
- &so->so_snd.sb_hiwat, 0, RLIM_INFINITY);
- /* remove accept filter if one is present. */
- if (so->so_accf != NULL)
- do_setopt_accept_filter(so, NULL);
#ifdef MAC
mac_socket_destroy(so);
#endif
@@ -481,10 +489,22 @@ sodealloc(struct socket *so)
crfree(so->so_cred);
khelp_destroy_osd(&so->osd);
- sx_destroy(&so->so_snd.sb_sx);
- sx_destroy(&so->so_rcv.sb_sx);
- SOCKBUF_LOCK_DESTROY(&so->so_snd);
- SOCKBUF_LOCK_DESTROY(&so->so_rcv);
+ if (SOLISTENING(so)) {
+ if (so->sol_accept_filter != NULL)
+ accept_filt_setopt(so, NULL);
+ } else {
+ if (so->so_rcv.sb_hiwat)
+ (void)chgsbsize(so->so_cred->cr_uidinfo,
+ &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY);
+ if (so->so_snd.sb_hiwat)
+ (void)chgsbsize(so->so_cred->cr_uidinfo,
+ &so->so_snd.sb_hiwat, 0, RLIM_INFINITY);
+ sx_destroy(&so->so_snd.sb_sx);
+ sx_destroy(&so->so_rcv.sb_sx);
+ SOCKBUF_LOCK_DESTROY(&so->so_snd);
+ SOCKBUF_LOCK_DESTROY(&so->so_rcv);
+ }
+ mtx_destroy(&so->so_lock);
uma_zfree(socket_zone, so);
}
@@ -527,8 +547,6 @@ socreate(int dom, struct socket **aso, int type, int proto,
if (so == NULL)
return (ENOBUFS);
- TAILQ_INIT(&so->so_incomp);
- TAILQ_INIT(&so->so_comp);
so->so_type = type;
so->so_cred = crhold(cred);
if ((prp->pr_domain->dom_family == PF_INET) ||
@@ -545,9 +563,10 @@ socreate(int dom, struct socket **aso, int type, int proto,
#ifdef MAC
mac_socket_create(cred, so);
#endif
- knlist_init_mtx(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv));
- knlist_init_mtx(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd));
- so->so_count = 1;
+ knlist_init(&so->so_rdsel.si_note, so, so_rdknl_lock, so_rdknl_unlock,
+ so_rdknl_assert_locked, so_rdknl_assert_unlocked);
+ knlist_init(&so->so_wrsel.si_note, so, so_wrknl_lock, so_wrknl_unlock,
+ so_wrknl_assert_locked, so_wrknl_assert_unlocked);
/*
* Auto-sizing of socket buffers is managed by the protocols and
* the appropriate flags must be set in the pru_attach function.
@@ -556,12 +575,10 @@ socreate(int dom, struct socket **aso, int type, int proto,
error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
CURVNET_RESTORE();
if (error) {
- KASSERT(so->so_count == 1, ("socreate: so_count %d",
- so->so_count));
- so->so_count = 0;
sodealloc(so);
return (error);
}
+ soref(so);
*aso = so;
return (0);
}
@@ -589,11 +606,11 @@ sonewconn(struct socket *head, int connstatus)
static int overcount;
struct socket *so;
- int over;
+ u_int over;
- ACCEPT_LOCK();
- over = (head->so_qlen > 3 * head->so_qlimit / 2);
- ACCEPT_UNLOCK();
+ SOLISTEN_LOCK(head);
+ over = (head->sol_qlen > 3 * head->sol_qlimit / 2);
+ SOLISTEN_UNLOCK(head);
#ifdef REGRESSION
if (regression_sonewconn_earlytest && over) {
#else
@@ -605,15 +622,15 @@ sonewconn(struct socket *head, int connstatus)
log(LOG_DEBUG, "%s: pcb %p: Listen queue overflow: "
"%i already in queue awaiting acceptance "
"(%d occurrences)\n",
- __func__, head->so_pcb, head->so_qlen, overcount);
+ __func__, head->so_pcb, head->sol_qlen, overcount);
overcount = 0;
}
return (NULL);
}
- VNET_ASSERT(head->so_vnet != NULL, ("%s:%d so_vnet is NULL, head=%p",
- __func__, __LINE__, head));
+ VNET_ASSERT(head->so_vnet != NULL, ("%s: so %p vnet is NULL",
+ __func__, head));
so = soalloc(head->so_vnet);
if (so == NULL) {
log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: "
@@ -621,11 +638,8 @@ sonewconn(struct socket *head, int connstatus)
__func__, head->so_pcb);
return (NULL);
}
- if ((head->so_options & SO_ACCEPTFILTER) != 0)
- connstatus = 0;
- so->so_head = head;
+ so->so_listen = head;
so->so_type = head->so_type;
- so->so_options = head->so_options &~ SO_ACCEPTCONN;
so->so_linger = head->so_linger;
so->so_state = head->so_state | SS_NOFDREF;
so->so_fibnum = head->so_fibnum;
@@ -634,10 +648,12 @@ sonewconn(struct socket *head, int connstatus)
#ifdef MAC
mac_socket_newconn(head, so);
#endif
- knlist_init_mtx(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv));
- knlist_init_mtx(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd));
+ knlist_init(&so->so_rdsel.si_note, so, so_rdknl_lock, so_rdknl_unlock,
+ so_rdknl_assert_locked, so_rdknl_assert_unlocked);
+ knlist_init(&so->so_wrsel.si_note, so, so_wrknl_lock, so_wrknl_unlock,
+ so_wrknl_assert_locked, so_wrknl_assert_unlocked);
VNET_SO_ASSERT(head);
- if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
+ if (soreserve(so, head->sol_sbsnd_hiwat, head->sol_sbrcv_hiwat)) {
sodealloc(so);
log(LOG_DEBUG, "%s: pcb %p: soreserve() failed\n",
__func__, head->so_pcb);
@@ -649,32 +665,24 @@ sonewconn(struct socket *head, int connstatus)
__func__, head->so_pcb);
return (NULL);
}
- so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
- so->so_snd.sb_lowat = head->so_snd.sb_lowat;
- so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
- so->so_snd.sb_timeo = head->so_snd.sb_timeo;
- so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE;
- so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE;
+ so->so_rcv.sb_lowat = head->sol_sbrcv_lowat;
+ so->so_snd.sb_lowat = head->sol_sbsnd_lowat;
+ so->so_rcv.sb_timeo = head->sol_sbrcv_timeo;
+ so->so_snd.sb_timeo = head->sol_sbsnd_timeo;
+ so->so_rcv.sb_flags |= head->sol_sbrcv_flags & SB_AUTOSIZE;
+ so->so_snd.sb_flags |= head->sol_sbsnd_flags & SB_AUTOSIZE;
+
+ SOLISTEN_LOCK(head);
+ if (head->sol_accept_filter != NULL)
+ connstatus = 0;
so->so_state |= connstatus;
- ACCEPT_LOCK();
- /*
- * The accept socket may be tearing down but we just
- * won a race on the ACCEPT_LOCK.
- * However, if sctp_peeloff() is called on a 1-to-many
- * style socket, the SO_ACCEPTCONN doesn't need to be set.
- */
- if (!(head->so_options & SO_ACCEPTCONN) &&
- ((head->so_proto->pr_protocol != IPPROTO_SCTP) ||
- (head->so_type != SOCK_SEQPACKET))) {
- SOCK_LOCK(so);
- so->so_head = NULL;
- sofree(so); /* NB: returns ACCEPT_UNLOCK'ed. */
- return (NULL);
- }
+ so->so_options = head->so_options & ~SO_ACCEPTCONN;
+ soref(head); /* A socket on (in)complete queue refs head. */
if (connstatus) {
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
- so->so_qstate |= SQ_COMP;
- head->so_qlen++;
+ TAILQ_INSERT_TAIL(&head->sol_comp, so, so_list);
+ so->so_qstate = SQ_COMP;
+ head->sol_qlen++;
+ solisten_wakeup(head); /* unlocks */
} else {
/*
* Keep removing sockets from the head until there's room for
@@ -683,28 +691,86 @@ sonewconn(struct socket *head, int connstatus)
* threads and soabort() requires dropping locks, we must
* loop waiting for the condition to be true.
*/
- while (head->so_incqlen > head->so_qlimit) {
+ while (head->sol_incqlen > head->sol_qlimit) {
struct socket *sp;
- sp = TAILQ_FIRST(&head->so_incomp);
- TAILQ_REMOVE(&head->so_incomp, sp, so_list);
- head->so_incqlen--;
- sp->so_qstate &= ~SQ_INCOMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
+
+ sp = TAILQ_FIRST(&head->sol_incomp);
+ TAILQ_REMOVE(&head->sol_incomp, sp, so_list);
+ head->sol_incqlen--;
+ SOCK_LOCK(sp);
+ sp->so_qstate = SQ_NONE;
+ sp->so_listen = NULL;
+ SOCK_UNLOCK(sp);
+ sorele(head); /* does SOLISTEN_UNLOCK, head stays */
soabort(sp);
- ACCEPT_LOCK();
+ SOLISTEN_LOCK(head);
}
- TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
- so->so_qstate |= SQ_INCOMP;
- head->so_incqlen++;
+ TAILQ_INSERT_TAIL(&head->sol_incomp, so, so_list);
+ so->so_qstate = SQ_INCOMP;
+ head->sol_incqlen++;
+ SOLISTEN_UNLOCK(head);
}
- ACCEPT_UNLOCK();
- if (connstatus) {
- sorwakeup(head);
- wakeup_one(&head->so_timeo);
+ return (so);
+}
+
+#ifdef SCTP
+/*
+ * Socket part of sctp_peeloff(). Detach a new socket from an
+ * association. The new socket is returned with a reference.
+ */
+struct socket *
+sopeeloff(struct socket *head)
+{
+ struct socket *so;
+
+ VNET_ASSERT(head->so_vnet != NULL, ("%s:%d so_vnet is NULL, head=%p",
+ __func__, __LINE__, head));
+ so = soalloc(head->so_vnet);
+ if (so == NULL) {
+ log(LOG_DEBUG, "%s: pcb %p: New socket allocation failure: "
+ "limit reached or out of memory\n",
+ __func__, head->so_pcb);
+ return (NULL);
}
+ so->so_type = head->so_type;
+ so->so_options = head->so_options;
+ so->so_linger = head->so_linger;
+ so->so_state = (head->so_state & SS_NBIO) | SS_ISCONNECTED;
+ so->so_fibnum = head->so_fibnum;
+ so->so_proto = head->so_proto;
+ so->so_cred = crhold(head->so_cred);
+#ifdef MAC
+ mac_socket_newconn(head, so);
+#endif
+ knlist_init(&so->so_rdsel.si_note, so, so_rdknl_lock, so_rdknl_unlock,
+ so_rdknl_assert_locked, so_rdknl_assert_unlocked);
+ knlist_init(&so->so_wrsel.si_note, so, so_wrknl_lock, so_wrknl_unlock,
+ so_wrknl_assert_locked, so_wrknl_assert_unlocked);
+ VNET_SO_ASSERT(head);
+ if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
+ sodealloc(so);
+ log(LOG_DEBUG, "%s: pcb %p: soreserve() failed\n",
+ __func__, head->so_pcb);
+ return (NULL);
+ }
+ if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
+ sodealloc(so);
+ log(LOG_DEBUG, "%s: pcb %p: pru_attach() failed\n",
+ __func__, head->so_pcb);
+ return (NULL);
+ }
+ so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
+ so->so_snd.sb_lowat = head->so_snd.sb_lowat;
+ so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
+ so->so_snd.sb_timeo = head->so_snd.sb_timeo;
+ so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE;
+ so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE;
+
+ soref(so);
+
return (so);
}
+#endif /* SCTP */
int
sobind(struct socket *so, struct sockaddr *nam, struct thread *td)
@@ -766,13 +832,140 @@ solisten_proto_check(struct socket *so)
void
solisten_proto(struct socket *so, int backlog)
{
+ int sbrcv_lowat, sbsnd_lowat;
+ u_int sbrcv_hiwat, sbsnd_hiwat;
+ short sbrcv_flags, sbsnd_flags;
+ sbintime_t sbrcv_timeo, sbsnd_timeo;
SOCK_LOCK_ASSERT(so);
+ if (SOLISTENING(so))
+ goto listening;
+
+ /*
+ * Change this socket to listening state.
+ */
+ sbrcv_lowat = so->so_rcv.sb_lowat;
+ sbsnd_lowat = so->so_snd.sb_lowat;
+ sbrcv_hiwat = so->so_rcv.sb_hiwat;
+ sbsnd_hiwat = so->so_snd.sb_hiwat;
+ sbrcv_flags = so->so_rcv.sb_flags;
+ sbsnd_flags = so->so_snd.sb_flags;
+ sbrcv_timeo = so->so_rcv.sb_timeo;
+ sbsnd_timeo = so->so_snd.sb_timeo;
+
+ sbdestroy(&so->so_snd, so);
+ sbdestroy(&so->so_rcv, so);
+ sx_destroy(&so->so_snd.sb_sx);
+ sx_destroy(&so->so_rcv.sb_sx);
+ SOCKBUF_LOCK_DESTROY(&so->so_snd);
+ SOCKBUF_LOCK_DESTROY(&so->so_rcv);
+
+#ifdef INVARIANTS
+ bzero(&so->so_rcv,
+ sizeof(struct socket) - offsetof(struct socket, so_rcv));
+#endif
+
+ so->sol_sbrcv_lowat = sbrcv_lowat;
+ so->sol_sbsnd_lowat = sbsnd_lowat;
+ so->sol_sbrcv_hiwat = sbrcv_hiwat;
+ so->sol_sbsnd_hiwat = sbsnd_hiwat;
+ so->sol_sbrcv_flags = sbrcv_flags;
+ so->sol_sbsnd_flags = sbsnd_flags;
+ so->sol_sbrcv_timeo = sbrcv_timeo;
+ so->sol_sbsnd_timeo = sbsnd_timeo;
+
+ so->sol_qlen = so->sol_incqlen = 0;
+ TAILQ_INIT(&so->sol_incomp);
+ TAILQ_INIT(&so->sol_comp);
+
+ so->sol_accept_filter = NULL;
+ so->sol_accept_filter_arg = NULL;
+ so->sol_accept_filter_str = NULL;
+
+ so->sol_upcall = NULL;
+ so->sol_upcallarg = NULL;
+
+ so->so_options |= SO_ACCEPTCONN;
+
+listening:
if (backlog < 0 || backlog > somaxconn)
backlog = somaxconn;
- so->so_qlimit = backlog;
- so->so_options |= SO_ACCEPTCONN;
+ so->sol_qlimit = backlog;
+}
+
+/*
+ * Wakeup listeners/subsystems once we have a complete connection.
+ * Enters with lock, returns unlocked.
+ */
+void
+solisten_wakeup(struct socket *sol)
+{
+
+ if (sol->sol_upcall != NULL)
+ (void )sol->sol_upcall(sol, sol->sol_upcallarg, M_NOWAIT);
+ else {
+ selwakeuppri(&sol->so_rdsel, PSOCK);
+ KNOTE_LOCKED(&sol->so_rdsel.si_note, 0);
+ }
+ SOLISTEN_UNLOCK(sol);
+ wakeup_one(&sol->sol_comp);
+}
+
+/*
+ * Return single connection off a listening socket queue. Main consumer of
+ * the function is kern_accept4(). Some modules, that do their own accept
+ * management also use the function.
+ *
+ * Listening socket must be locked on entry and is returned unlocked on
+ * return.
+ * The flags argument is set of accept4(2) flags and ACCEPT4_INHERIT.
+ */
+int
+solisten_dequeue(struct socket *head, struct socket **ret, int flags)
+{
+ struct socket *so;
+ int error;
+
+ SOLISTEN_LOCK_ASSERT(head);
+
+ while (!(head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->sol_comp) &&
+ head->so_error == 0) {
+ error = msleep(&head->sol_comp, &head->so_lock, PSOCK | PCATCH,
+ "accept", 0);
+ if (error != 0) {
+ SOLISTEN_UNLOCK(head);
+ return (error);
+ }
+ }
+ if (head->so_error) {
+ error = head->so_error;
+ head->so_error = 0;
+ SOLISTEN_UNLOCK(head);
+ return (error);
+ }
+ if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->sol_comp)) {
+ SOLISTEN_UNLOCK(head);
+ return (EWOULDBLOCK);
+ }
+ so = TAILQ_FIRST(&head->sol_comp);
+ SOCK_LOCK(so);
+ KASSERT(so->so_qstate == SQ_COMP,
+ ("%s: so %p not SQ_COMP", __func__, so));
+ soref(so);
+ head->sol_qlen--;
+ so->so_qstate = SQ_NONE;
+ so->so_listen = NULL;
+ TAILQ_REMOVE(&head->sol_comp, so, so_list);
+ if (flags & ACCEPT4_INHERIT)
+ so->so_state |= (head->so_state & SS_NBIO);
+ else
+ so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0;
+ SOCK_UNLOCK(so);
+ sorele(head);
+
+ *ret = so;
+ return (0);
}
/*
@@ -799,44 +992,62 @@ void
sofree(struct socket *so)
{
struct protosw *pr = so->so_proto;
- struct socket *head;
- ACCEPT_LOCK_ASSERT();
SOCK_LOCK_ASSERT(so);
if ((so->so_state & SS_NOFDREF) == 0 || so->so_count != 0 ||
- (so->so_state & SS_PROTOREF) || (so->so_qstate & SQ_COMP)) {
+ (so->so_state & SS_PROTOREF) || (so->so_qstate == SQ_COMP)) {
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
return;
}
- head = so->so_head;
- if (head != NULL) {
- KASSERT((so->so_qstate & SQ_COMP) != 0 ||
- (so->so_qstate & SQ_INCOMP) != 0,
- ("sofree: so_head != NULL, but neither SQ_COMP nor "
- "SQ_INCOMP"));
- KASSERT((so->so_qstate & SQ_COMP) == 0 ||
- (so->so_qstate & SQ_INCOMP) == 0,
- ("sofree: so->so_qstate is SQ_COMP and also SQ_INCOMP"));
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
- so->so_qstate &= ~SQ_INCOMP;
- so->so_head = NULL;
- }
- KASSERT((so->so_qstate & SQ_COMP) == 0 &&
- (so->so_qstate & SQ_INCOMP) == 0,
- ("sofree: so_head == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)",
- so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP));
- if (so->so_options & SO_ACCEPTCONN) {
- KASSERT((TAILQ_EMPTY(&so->so_comp)),
- ("sofree: so_comp populated"));
- KASSERT((TAILQ_EMPTY(&so->so_incomp)),
- ("sofree: so_incomp populated"));
+ if (!SOLISTENING(so) && so->so_qstate == SQ_INCOMP) {
+ struct socket *sol;
+
+ sol = so->so_listen;
+ KASSERT(sol, ("%s: so %p on incomp of NULL", __func__, so));
+
+ /*
+ * To solve race between close of a listening socket and
+ * a socket on its incomplete queue, we need to lock both.
+ * The order is first listening socket, then regular.
+ * Since we don't have SS_NOFDREF neither SS_PROTOREF, this
+ * function and the listening socket are the only pointers
+ * to so. To preserve so and sol, we reference both and then
+ * relock.
+ * After relock the socket may not move to so_comp since it
+ * doesn't have PCB already, but it may be removed from
+ * so_incomp. If that happens, we share responsiblity on
+ * freeing the socket, but soclose() has already removed
+ * it from queue.
+ */
+ soref(sol);
+ soref(so);
+ SOCK_UNLOCK(so);
+ SOLISTEN_LOCK(sol);
+ SOCK_LOCK(so);
+ if (so->so_qstate == SQ_INCOMP) {
+ KASSERT(so->so_listen == sol,
+ ("%s: so %p migrated out of sol %p",
+ __func__, so, sol));
+ TAILQ_REMOVE(&sol->sol_incomp, so, so_list);
+ sol->sol_incqlen--;
+ /* This is guarenteed not to be the last. */
+ refcount_release(&sol->so_count);
+ so->so_qstate = SQ_NONE;
+ so->so_listen = NULL;
+ } else
+ KASSERT(so->so_listen == NULL,
+ ("%s: so %p not on (in)comp with so_listen",
+ __func__, so));
+ sorele(sol);
+ KASSERT(so->so_count == 1,
+ ("%s: so %p count %u", __func__, so, so->so_count));
+ so->so_count = 0;
}
+ if (SOLISTENING(so))
+ so->so_error = ECONNABORTED;
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
VNET_SO_ASSERT(so);
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL)
@@ -858,12 +1069,14 @@ sofree(struct socket *so)
* before calling pru_detach. This means that protocols shold not
* assume they can perform socket wakeups, etc, in their detach code.
*/
- sbdestroy(&so->so_snd, so);
- sbdestroy(&so->so_rcv, so);
- seldrain(&so->so_snd.sb_sel);
- seldrain(&so->so_rcv.sb_sel);
- knlist_destroy(&so->so_rcv.sb_sel.si_note);
- knlist_destroy(&so->so_snd.sb_sel.si_note);
+ if (!SOLISTENING(so)) {
+ sbdestroy(&so->so_snd, so);
+ sbdestroy(&so->so_rcv, so);
+ }
+ seldrain(&so->so_rdsel);
+ seldrain(&so->so_wrsel);
+ knlist_destroy(&so->so_rdsel.si_note);
+ knlist_destroy(&so->so_wrsel.si_note);
sodealloc(so);
}
@@ -878,6 +1091,8 @@ sofree(struct socket *so)
int
soclose(struct socket *so)
{
+ struct accept_queue lqueue;
+ bool listening;
int error = 0;
KASSERT(!(so->so_state & SS_NOFDREF), ("soclose: SS_NOFDREF on enter"));
@@ -910,41 +1125,42 @@ soclose(struct socket *so)
drop:
if (so->so_proto->pr_usrreqs->pru_close != NULL)
(*so->so_proto->pr_usrreqs->pru_close)(so);
- ACCEPT_LOCK();
- if (so->so_options & SO_ACCEPTCONN) {
+
+ SOCK_LOCK(so);
+ if ((listening = (so->so_options & SO_ACCEPTCONN))) {
struct socket *sp;
- /*
- * Prevent new additions to the accept queues due
- * to ACCEPT_LOCK races while we are draining them.
- */
- so->so_options &= ~SO_ACCEPTCONN;
- while ((sp = TAILQ_FIRST(&so->so_incomp)) != NULL) {
- TAILQ_REMOVE(&so->so_incomp, sp, so_list);
- so->so_incqlen--;
- sp->so_qstate &= ~SQ_INCOMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
- soabort(sp);
- ACCEPT_LOCK();
- }
- while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) {
- TAILQ_REMOVE(&so->so_comp, sp, so_list);
- so->so_qlen--;
- sp->so_qstate &= ~SQ_COMP;
- sp->so_head = NULL;
- ACCEPT_UNLOCK();
- soabort(sp);
- ACCEPT_LOCK();
+
+ TAILQ_INIT(&lqueue);
+ TAILQ_SWAP(&lqueue, &so->sol_incomp, socket, so_list);
+ TAILQ_CONCAT(&lqueue, &so->sol_comp, so_list);
+
+ so->sol_qlen = so->sol_incqlen = 0;
+
+ TAILQ_FOREACH(sp, &lqueue, so_list) {
+ SOCK_LOCK(sp);
+ sp->so_qstate = SQ_NONE;
+ sp->so_listen = NULL;
+ SOCK_UNLOCK(sp);
+ /* Guaranteed not to be the last. */
+ refcount_release(&so->so_count);
}
- KASSERT((TAILQ_EMPTY(&so->so_comp)),
- ("%s: so_comp populated", __func__));
- KASSERT((TAILQ_EMPTY(&so->so_incomp)),
- ("%s: so_incomp populated", __func__));
}
- SOCK_LOCK(so);
KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF"));
so->so_state |= SS_NOFDREF;
- sorele(so); /* NB: Returns with ACCEPT_UNLOCK(). */
+ sorele(so);
+ if (listening) {
+ struct socket *sp;
+
+ TAILQ_FOREACH(sp, &lqueue, so_list) {
+ SOCK_LOCK(sp);
+ if (sp->so_count == 0) {
+ SOCK_UNLOCK(sp);
+ soabort(sp);
+ } else
+ /* sp is now in sofree() */
+ SOCK_UNLOCK(sp);
+ }
+ }
CURVNET_RESTORE();
return (error);
}
@@ -976,13 +1192,11 @@ soabort(struct socket *so)
KASSERT(so->so_count == 0, ("soabort: so_count"));
KASSERT((so->so_state & SS_PROTOREF) == 0, ("soabort: SS_PROTOREF"));
KASSERT(so->so_state & SS_NOFDREF, ("soabort: !SS_NOFDREF"));
- KASSERT((so->so_state & SQ_COMP) == 0, ("soabort: SQ_COMP"));
- KASSERT((so->so_state & SQ_INCOMP) == 0, ("soabort: SQ_INCOMP"));
+ KASSERT(so->so_qstate == SQ_NONE, ("soabort: !SQ_NONE"));
VNET_SO_ASSERT(so);
if (so->so_proto->pr_usrreqs->pru_abort != NULL)
(*so->so_proto->pr_usrreqs->pru_abort)(so);
- ACCEPT_LOCK();
SOCK_LOCK(so);
sofree(so);
}
@@ -1431,8 +1645,14 @@ sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,
int error;
CURVNET_SET(so->so_vnet);
- error = so->so_proto->pr_usrreqs->pru_sosend(so, addr, uio, top,
- control, flags, td);
+ if (!SOLISTENING(so))
+ error = so->so_proto->pr_usrreqs->pru_sosend(so, addr, uio,
+ top, control, flags, td);
+ else {
+ m_freem(top);
+ m_freem(control);
+ error = ENOTCONN;
+ }
CURVNET_RESTORE();
return (error);
}
@@ -2368,8 +2588,11 @@ soreceive(struct socket *so, struct sockaddr **psa, struct uio *uio,
int error;
CURVNET_SET(so->so_vnet);
- error = (so->so_proto->pr_usrreqs->pru_soreceive(so, psa, uio, mp0,
- controlp, flagsp));
+ if (!SOLISTENING(so))
+ error = (so->so_proto->pr_usrreqs->pru_soreceive(so, psa, uio,
+ mp0, controlp, flagsp));
+ else
+ error = ENOTCONN;
CURVNET_RESTORE();
return (error);
}
@@ -2565,7 +2788,7 @@ sosetopt(struct socket *so, struct sockopt *sopt)
} else {
switch (sopt->sopt_name) {
case SO_ACCEPTFILTER:
- error = do_setopt_accept_filter(so, sopt);
+ error = accept_filt_setopt(so, sopt);
if (error)
goto bad;
break;
@@ -2653,38 +2876,7 @@ sosetopt(struct socket *so, struct sockopt *sopt)
goto bad;
}
- switch (sopt->sopt_name) {
- case SO_SNDBUF:
- case SO_RCVBUF:
- if (sbreserve(sopt->sopt_name == SO_SNDBUF ?
- &so->so_snd : &so->so_rcv, (u_long)optval,
- so, curthread) == 0) {
- error = ENOBUFS;
- goto bad;
- }
- (sopt->sopt_name == SO_SNDBUF ? &so->so_snd :
- &so->so_rcv)->sb_flags &= ~SB_AUTOSIZE;
- break;
-
- /*
- * Make sure the low-water is never greater than the
- * high-water.
- */
- case SO_SNDLOWAT:
- SOCKBUF_LOCK(&so->so_snd);
- so->so_snd.sb_lowat =
- (optval > so->so_snd.sb_hiwat) ?
- so->so_snd.sb_hiwat : optval;
- SOCKBUF_UNLOCK(&so->so_snd);
- break;
- case SO_RCVLOWAT:
- SOCKBUF_LOCK(&so->so_rcv);
- so->so_rcv.sb_lowat =
- (optval > so->so_rcv.sb_hiwat) ?
- so->so_rcv.sb_hiwat : optval;
- SOCKBUF_UNLOCK(&so->so_rcv);
- break;
- }
+ error = sbsetopt(so, sopt->sopt_name, optval);
break;
case SO_SNDTIMEO:
@@ -2825,7 +3017,7 @@ sogetopt(struct socket *so, struct sockopt *sopt)
} else {
switch (sopt->sopt_name) {
case SO_ACCEPTFILTER:
- error = do_getopt_accept_filter(so, sopt);
+ error = accept_filt_getopt(so, sopt);
break;
case SO_LINGER:
@@ -2869,19 +3061,23 @@ integer:
goto integer;
case SO_SNDBUF:
- optval = so->so_snd.sb_hiwat;
+ optval = SOLISTENING(so) ? so->sol_sbsnd_hiwat :
+ so->so_snd.sb_hiwat;
goto integer;
case SO_RCVBUF:
- optval = so->so_rcv.sb_hiwat;
+ optval = SOLISTENING(so) ? so->sol_sbrcv_hiwat :
+ so->so_rcv.sb_hiwat;
goto integer;
case SO_SNDLOWAT:
- optval = so->so_snd.sb_lowat;
+ optval = SOLISTENING(so) ? so->sol_sbsnd_lowat :
+ so->so_snd.sb_lowat;
goto integer;
case SO_RCVLOWAT:
- optval = so->so_rcv.sb_lowat;
+ optval = SOLISTENING(so) ? so->sol_sbrcv_lowat :
+ so->so_rcv.sb_lowat;
goto integer;
case SO_SNDTIMEO:
@@ -2933,15 +3129,15 @@ integer:
break;
case SO_LISTENQLIMIT:
- optval = so->so_qlimit;
+ optval = SOLISTENING(so) ? so->sol_qlimit : 0;
goto integer;
case SO_LISTENQLEN:
- optval = so->so_qlen;
+ optval = SOLISTENING(so) ? so->sol_qlen : 0;
goto integer;
case SO_LISTENINCQLEN:
- optval = so->so_incqlen;
+ optval = SOLISTENING(so) ? so->sol_incqlen : 0;
goto integer;
case SO_TS_CLOCK:
@@ -3092,7 +3288,7 @@ sohasoutofband(struct socket *so)
if (so->so_sigio != NULL)
pgsigio(&so->so_sigio, SIGURG, 0);
#endif /* __rtems__ */
- selwakeuppri(&so->so_rcv.sb_sel, PSOCK);
+ selwakeuppri(&so->so_rdsel, PSOCK);
}
int
@@ -3112,44 +3308,54 @@ int
sopoll_generic(struct socket *so, int events, struct ucred *active_cred,
struct thread *td)
{
- int revents = 0;
-
- SOCKBUF_LOCK(&so->so_snd);
- SOCKBUF_LOCK(&so->so_rcv);
- if (events & (POLLIN | POLLRDNORM))
- if (soreadabledata(so))
- revents |= events & (POLLIN | POLLRDNORM);
+ int revents;
- if (events & (POLLOUT | POLLWRNORM))
- if (sowriteable(so))
- revents |= events & (POLLOUT | POLLWRNORM);
-
- if (events & (POLLPRI | POLLRDBAND))
- if (so->so_oobmark || (so->so_rcv.sb_state & SBS_RCVATMARK))
- revents |= events & (POLLPRI | POLLRDBAND);
-
- if ((events & POLLINIGNEOF) == 0) {
- if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
- revents |= events & (POLLIN | POLLRDNORM);
- if (so->so_snd.sb_state & SBS_CANTSENDMORE)
- revents |= POLLHUP;
+ SOCK_LOCK(so);
+ if (SOLISTENING(so)) {
+ if (!(events & (POLLIN | POLLRDNORM)))
+ revents = 0;
+ else if (!TAILQ_EMPTY(&so->sol_comp))
+ revents = events & (POLLIN | POLLRDNORM);
+ else {
+ selrecord(td, &so->so_rdsel);
+ revents = 0;
}
- }
-
- if (revents == 0) {
- if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
- selrecord(td, &so->so_rcv.sb_sel);
- so->so_rcv.sb_flags |= SB_SEL;
+ } else {
+ revents = 0;
+ SOCKBUF_LOCK(&so->so_snd);
+ SOCKBUF_LOCK(&so->so_rcv);
+ if (events & (POLLIN | POLLRDNORM))
+ if (soreadabledata(so))
+ revents |= events & (POLLIN | POLLRDNORM);
+ if (events & (POLLOUT | POLLWRNORM))
+ if (sowriteable(so))
+ revents |= events & (POLLOUT | POLLWRNORM);
+ if (events & (POLLPRI | POLLRDBAND))
+ if (so->so_oobmark ||
+ (so->so_rcv.sb_state & SBS_RCVATMARK))
+ revents |= events & (POLLPRI | POLLRDBAND);
+ if ((events & POLLINIGNEOF) == 0) {
+ if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
+ revents |= events & (POLLIN | POLLRDNORM);
+ if (so->so_snd.sb_state & SBS_CANTSENDMORE)
+ revents |= POLLHUP;
+ }
}
-
- if (events & (POLLOUT | POLLWRNORM)) {
- selrecord(td, &so->so_snd.sb_sel);
- so->so_snd.sb_flags |= SB_SEL;
+ if (revents == 0) {
+ if (events &
+ (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) {
+ selrecord(td, &so->so_rdsel);
+ so->so_rcv.sb_flags |= SB_SEL;
+ }
+ if (events & (POLLOUT | POLLWRNORM)) {
+ selrecord(td, &so->so_wrsel);
+ so->so_snd.sb_flags |= SB_SEL;
+ }
}
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ SOCKBUF_UNLOCK(&so->so_snd);
}
-
- SOCKBUF_UNLOCK(&so->so_rcv);
- SOCKBUF_UNLOCK(&so->so_snd);
+ SOCK_UNLOCK(so);
return (revents);
}
@@ -3158,28 +3364,38 @@ soo_kqfilter(struct file *fp, struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
struct sockbuf *sb;
+ struct knlist *knl;
switch (kn->kn_filter) {
case EVFILT_READ:
kn->kn_fop = &soread_filtops;
+ knl = &so->so_rdsel.si_note;
sb = &so->so_rcv;
break;
case EVFILT_WRITE:
kn->kn_fop = &sowrite_filtops;
+ knl = &so->so_wrsel.si_note;
sb = &so->so_snd;
break;
case EVFILT_EMPTY:
kn->kn_fop = &soempty_filtops;
+ knl = &so->so_wrsel.si_note;
sb = &so->so_snd;
break;
default:
return (EINVAL);
}
- SOCKBUF_LOCK(sb);
- knlist_add(&sb->sb_sel.si_note, kn, 1);
- sb->sb_flags |= SB_KNOTE;
- SOCKBUF_UNLOCK(sb);
+ SOCK_LOCK(so);
+ if (SOLISTENING(so)) {
+ knlist_add(knl, kn, 1);
+ } else {
+ SOCKBUF_LOCK(sb);
+ knlist_add(knl, kn, 1);
+ sb->sb_flags |= SB_KNOTE;
+ SOCKBUF_UNLOCK(sb);
+ }
+ SOCK_UNLOCK(so);
return (0);
}
#ifdef __rtems__
@@ -3367,11 +3583,11 @@ filt_sordetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- SOCKBUF_LOCK(&so->so_rcv);
- knlist_remove(&so->so_rcv.sb_sel.si_note, kn, 1);
- if (knlist_empty(&so->so_rcv.sb_sel.si_note))
+ so_rdknl_lock(so);
+ knlist_remove(&so->so_rdsel.si_note, kn, 1);
+ if (!SOLISTENING(so) && knlist_empty(&so->so_rdsel.si_note))
so->so_rcv.sb_flags &= ~SB_KNOTE;
- SOCKBUF_UNLOCK(&so->so_rcv);
+ so_rdknl_unlock(so);
}
/*ARGSUSED*/
@@ -3381,11 +3597,13 @@ filt_soread(struct knote *kn, long hint)
struct socket *so;
so = kn->kn_fp->f_data;
- if (so->so_options & SO_ACCEPTCONN) {
- kn->kn_data = so->so_qlen;
- return (!TAILQ_EMPTY(&so->so_comp));
+ if (SOLISTENING(so)) {
+ SOCK_LOCK_ASSERT(so);
+ kn->kn_data = so->sol_qlen;
+ return (!TAILQ_EMPTY(&so->sol_comp));
}
+
SOCKBUF_LOCK_ASSERT(&so->so_rcv);
kn->kn_data = sbavail(&so->so_rcv) - so->so_rcv.sb_ctl;
@@ -3411,11 +3629,11 @@ filt_sowdetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- SOCKBUF_LOCK(&so->so_snd);
- knlist_remove(&so->so_snd.sb_sel.si_note, kn, 1);
- if (knlist_empty(&so->so_snd.sb_sel.si_note))
+ so_wrknl_lock(so);
+ knlist_remove(&so->so_wrsel.si_note, kn, 1);
+ if (!SOLISTENING(so) && knlist_empty(&so->so_wrsel.si_note))
so->so_snd.sb_flags &= ~SB_KNOTE;
- SOCKBUF_UNLOCK(&so->so_snd);
+ so_wrknl_unlock(so);
}
/*ARGSUSED*/
@@ -3425,6 +3643,10 @@ filt_sowrite(struct knote *kn, long hint)
struct socket *so;
so = kn->kn_fp->f_data;
+
+ if (SOLISTENING(so))
+ return (0);
+
SOCKBUF_LOCK_ASSERT(&so->so_snd);
kn->kn_data = sbspace(&so->so_snd);
@@ -3451,6 +3673,10 @@ filt_soempty(struct knote *kn, long hint)
struct socket *so;
so = kn->kn_fp->f_data;
+
+ if (SOLISTENING(so))
+ return (1);
+
SOCKBUF_LOCK_ASSERT(&so->so_snd);
kn->kn_data = sbused(&so->so_snd);
@@ -3521,42 +3747,52 @@ soisconnected(struct socket *so)
struct socket *head;
int ret;
+ /*
+ * XXXGL: this is the only place where we acquire socket locks
+ * in reverse order: first child, then listening socket. To
+ * avoid possible LOR, use try semantics.
+ */
restart:
- ACCEPT_LOCK();
SOCK_LOCK(so);
+ if ((head = so->so_listen) != NULL &&
+ __predict_false(SOLISTEN_TRYLOCK(head) == 0)) {
+ SOCK_UNLOCK(so);
+ goto restart;
+ }
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
- head = so->so_head;
- if (head != NULL && (so->so_qstate & SQ_INCOMP)) {
+ if (head != NULL && (so->so_qstate == SQ_INCOMP)) {
+again:
if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ TAILQ_REMOVE(&head->sol_incomp, so, so_list);
+ head->sol_incqlen--;
+ TAILQ_INSERT_TAIL(&head->sol_comp, so, so_list);
+ head->sol_qlen++;
+ so->so_qstate = SQ_COMP;
SOCK_UNLOCK(so);
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
- so->so_qstate &= ~SQ_INCOMP;
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
- head->so_qlen++;
- so->so_qstate |= SQ_COMP;
- ACCEPT_UNLOCK();
- sorwakeup(head);
- wakeup_one(&head->so_timeo);
+ solisten_wakeup(head); /* unlocks */
} else {
- ACCEPT_UNLOCK();
+ SOCKBUF_LOCK(&so->so_rcv);
soupcall_set(so, SO_RCV,
- head->so_accf->so_accept_filter->accf_callback,
- head->so_accf->so_accept_filter_arg);
+ head->sol_accept_filter->accf_callback,
+ head->sol_accept_filter_arg);
so->so_options &= ~SO_ACCEPTFILTER;
- ret = head->so_accf->so_accept_filter->accf_callback(so,
- head->so_accf->so_accept_filter_arg, M_NOWAIT);
- if (ret == SU_ISCONNECTED)
+ ret = head->sol_accept_filter->accf_callback(so,
+ head->sol_accept_filter_arg, M_NOWAIT);
+ if (ret == SU_ISCONNECTED) {
soupcall_clear(so, SO_RCV);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ goto again;
+ }
+ SOCKBUF_UNLOCK(&so->so_rcv);
SOCK_UNLOCK(so);
- if (ret == SU_ISCONNECTED)
- goto restart;
+ SOLISTEN_UNLOCK(head);
}
return;
}
+ if (head != NULL)
+ SOLISTEN_UNLOCK(head);
SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
wakeup(&so->so_timeo);
sorwakeup(so);
sowwakeup(so);
@@ -3566,16 +3802,17 @@ void
soisdisconnecting(struct socket *so)
{
- /*
- * Note: This code assumes that SOCK_LOCK(so) and
- * SOCKBUF_LOCK(&so->so_rcv) are the same.
- */
- SOCKBUF_LOCK(&so->so_rcv);
+ SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= SS_ISDISCONNECTING;
- socantrcvmore_locked(so);
- SOCKBUF_LOCK(&so->so_snd);
- socantsendmore_locked(so);
+
+ if (!SOLISTENING(so)) {
+ SOCKBUF_LOCK(&so->so_rcv);
+ socantrcvmore_locked(so);
+ SOCKBUF_LOCK(&so->so_snd);
+ socantsendmore_locked(so);
+ }
+ SOCK_UNLOCK(so);
wakeup(&so->so_timeo);
}
@@ -3583,17 +3820,18 @@ void
soisdisconnected(struct socket *so)
{
- /*
- * Note: This code assumes that SOCK_LOCK(so) and
- * SOCKBUF_LOCK(&so->so_rcv) are the same.
- */
- SOCKBUF_LOCK(&so->so_rcv);
+ SOCK_LOCK(so);
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISDISCONNECTED;
- socantrcvmore_locked(so);
- SOCKBUF_LOCK(&so->so_snd);
- sbdrop_locked(&so->so_snd, sbused(&so->so_snd));
- socantsendmore_locked(so);
+
+ if (!SOLISTENING(so)) {
+ SOCKBUF_LOCK(&so->so_rcv);
+ socantrcvmore_locked(so);
+ SOCKBUF_LOCK(&so->so_snd);
+ sbdrop_locked(&so->so_snd, sbused(&so->so_snd));
+ socantsendmore_locked(so);
+ }
+ SOCK_UNLOCK(so);
wakeup(&so->so_timeo);
}
@@ -3615,11 +3853,12 @@ sodupsockaddr(const struct sockaddr *sa, int mflags)
* Register per-socket buffer upcalls.
*/
void
-soupcall_set(struct socket *so, int which,
- int (*func)(struct socket *, void *, int), void *arg)
+soupcall_set(struct socket *so, int which, so_upcall_t func, void *arg)
{
struct sockbuf *sb;
+ KASSERT(!SOLISTENING(so), ("%s: so %p listening", __func__, so));
+
switch (which) {
case SO_RCV:
sb = &so->so_rcv;
@@ -3631,10 +3870,6 @@ soupcall_set(struct socket *so, int which,
panic("soupcall_set: bad which");
}
SOCKBUF_LOCK_ASSERT(sb);
-#if 0
- /* XXX: accf_http actually wants to do this on purpose. */
- KASSERT(sb->sb_upcall == NULL, ("soupcall_set: overwriting upcall"));
-#endif
sb->sb_upcall = func;
sb->sb_upcallarg = arg;
sb->sb_flags |= SB_UPCALL;
@@ -3645,6 +3880,8 @@ soupcall_clear(struct socket *so, int which)
{
struct sockbuf *sb;
+ KASSERT(!SOLISTENING(so), ("%s: so %p listening", __func__, so));
+
switch (which) {
case SO_RCV:
sb = &so->so_rcv;
@@ -3656,12 +3893,110 @@ soupcall_clear(struct socket *so, int which)
panic("soupcall_clear: bad which");
}
SOCKBUF_LOCK_ASSERT(sb);
- KASSERT(sb->sb_upcall != NULL, ("soupcall_clear: no upcall to clear"));
+ KASSERT(sb->sb_upcall != NULL,
+ ("%s: so %p no upcall to clear", __func__, so));
sb->sb_upcall = NULL;
sb->sb_upcallarg = NULL;
sb->sb_flags &= ~SB_UPCALL;
}
+void
+solisten_upcall_set(struct socket *so, so_upcall_t func, void *arg)
+{
+
+ SOLISTEN_LOCK_ASSERT(so);
+ so->sol_upcall = func;
+ so->sol_upcallarg = arg;
+}
+
+static void
+so_rdknl_lock(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_LOCK(so);
+ else
+ SOCKBUF_LOCK(&so->so_rcv);
+}
+
+static void
+so_rdknl_unlock(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_UNLOCK(so);
+ else
+ SOCKBUF_UNLOCK(&so->so_rcv);
+}
+
+static void
+so_rdknl_assert_locked(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_LOCK_ASSERT(so);
+ else
+ SOCKBUF_LOCK_ASSERT(&so->so_rcv);
+}
+
+static void
+so_rdknl_assert_unlocked(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_UNLOCK_ASSERT(so);
+ else
+ SOCKBUF_UNLOCK_ASSERT(&so->so_rcv);
+}
+
+static void
+so_wrknl_lock(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_LOCK(so);
+ else
+ SOCKBUF_LOCK(&so->so_snd);
+}
+
+static void
+so_wrknl_unlock(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_UNLOCK(so);
+ else
+ SOCKBUF_UNLOCK(&so->so_snd);
+}
+
+static void
+so_wrknl_assert_locked(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_LOCK_ASSERT(so);
+ else
+ SOCKBUF_LOCK_ASSERT(&so->so_snd);
+}
+
+static void
+so_wrknl_assert_unlocked(void *arg)
+{
+ struct socket *so = arg;
+
+ if (SOLISTENING(so))
+ SOCK_UNLOCK_ASSERT(so);
+ else
+ SOCKBUF_UNLOCK_ASSERT(&so->so_snd);
+}
+
/*
* Create an external-format (``xsocket'') structure using the information in
* the kernel-format socket structure pointed to by so. This is done to
@@ -3683,36 +4018,28 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
xso->so_pcb = so->so_pcb;
xso->xso_protocol = so->so_proto->pr_protocol;
xso->xso_family = so->so_proto->pr_domain->dom_family;
- xso->so_qlen = so->so_qlen;
- xso->so_incqlen = so->so_incqlen;
- xso->so_qlimit = so->so_qlimit;
xso->so_timeo = so->so_timeo;
xso->so_error = so->so_error;
- xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0;
- xso->so_oobmark = so->so_oobmark;
- sbtoxsockbuf(&so->so_snd, &xso->so_snd);
- sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
#ifndef __rtems__
xso->so_uid = so->so_cred->cr_uid;
#else /* __rtems__ */
xso->so_uid = BSD_DEFAULT_UID;
#endif /* __rtems__ */
-}
-
-
-/*
- * Socket accessor functions to provide external consumers with
- * a safe interface to socket state
- *
- */
-
-void
-so_listeners_apply_all(struct socket *so, void (*func)(struct socket *, void *),
- void *arg)
-{
-
- TAILQ_FOREACH(so, &so->so_comp, so_list)
- func(so, arg);
+ xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0;
+ if (SOLISTENING(so)) {
+ xso->so_qlen = so->sol_qlen;
+ xso->so_incqlen = so->sol_incqlen;
+ xso->so_qlimit = so->sol_qlimit;
+ xso->so_oobmark = 0;
+ bzero(&xso->so_snd, sizeof(xso->so_snd));
+ bzero(&xso->so_rcv, sizeof(xso->so_rcv));
+ } else {
+ xso->so_state |= so->so_qstate;
+ xso->so_qlen = xso->so_incqlen = xso->so_qlimit = 0;
+ xso->so_oobmark = so->so_oobmark;
+ sbtoxsockbuf(&so->so_snd, &xso->so_snd);
+ sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
+ }
}
struct sockbuf *
diff --git a/freebsd/sys/kern/uipc_syscalls.c b/freebsd/sys/kern/uipc_syscalls.c
index f301c12c..5a9a381f 100644
--- a/freebsd/sys/kern/uipc_syscalls.c
+++ b/freebsd/sys/kern/uipc_syscalls.c
@@ -70,13 +70,6 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
-/*
- * Flags for accept1() and kern_accept4(), in addition to SOCK_CLOEXEC
- * and SOCK_NONBLOCK.
- */
-#define ACCEPT4_INHERIT 0x1
-#define ACCEPT4_COMPAT 0x2
-
static int sendit(struct thread *td, int s, struct msghdr *mp, int flags);
static int recvit(struct thread *td, int s, struct msghdr *mp, void *namelenp);
@@ -524,59 +517,22 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name,
(flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps);
if (error != 0)
goto done;
- ACCEPT_LOCK();
- if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
- ACCEPT_UNLOCK();
- error = EWOULDBLOCK;
- goto noconnection;
- }
- while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
- if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
- head->so_error = ECONNABORTED;
- break;
- }
- error = msleep(&head->so_timeo, &accept_mtx, PSOCK | PCATCH,
- "accept", 0);
- if (error != 0) {
- ACCEPT_UNLOCK();
- goto noconnection;
- }
- }
- if (head->so_error) {
- error = head->so_error;
- head->so_error = 0;
- ACCEPT_UNLOCK();
+ SOCK_LOCK(head);
+ if (!SOLISTENING(head)) {
+ SOCK_UNLOCK(head);
+ error = EINVAL;
goto noconnection;
}
- so = TAILQ_FIRST(&head->so_comp);
- KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
- KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));
- /*
- * Before changing the flags on the socket, we have to bump the
- * reference count. Otherwise, if the protocol calls sofree(),
- * the socket will be released due to a zero refcount.
- */
- SOCK_LOCK(so); /* soref() and so_state update */
- soref(so); /* file descriptor reference */
-
- TAILQ_REMOVE(&head->so_comp, so, so_list);
- head->so_qlen--;
- if (flags & ACCEPT4_INHERIT)
- so->so_state |= (head->so_state & SS_NBIO);
- else
- so->so_state |= (flags & SOCK_NONBLOCK) ? SS_NBIO : 0;
- so->so_qstate &= ~SQ_COMP;
- so->so_head = NULL;
-
- SOCK_UNLOCK(so);
- ACCEPT_UNLOCK();
+ error = solisten_dequeue(head, &so, flags);
+ if (error != 0)
+ goto noconnection;
/* An extra reference on `nfp' has been held for us by falloc(). */
td->td_retval[0] = fd;
- /* connection has been removed from the listen queue */
- KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
+ /* Connection has been removed from the listen queue. */
+ KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0);
if (flags & ACCEPT4_INHERIT) {
pgid = fgetown(&head->so_sigio);
@@ -594,7 +550,6 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name,
(void) fo_ioctl(nfp, FIONBIO, &tmp, td->td_ucred, td);
tmp = fflag & FASYNC;
(void) fo_ioctl(nfp, FIOASYNC, &tmp, td->td_ucred, td);
- sa = NULL;
error = soaccept(so, &sa);
if (error != 0)
goto noconnection;
@@ -769,7 +724,7 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
}
SOCK_LOCK(so);
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
- error = msleep(&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH,
+ error = msleep(&so->so_timeo, &so->so_lock, PSOCK | PCATCH,
"connec", 0);
if (error != 0) {
if (error == EINTR || error == ERESTART)
diff --git a/freebsd/sys/kern/uipc_usrreq.c b/freebsd/sys/kern/uipc_usrreq.c
index 8e60f227..7237956a 100644
--- a/freebsd/sys/kern/uipc_usrreq.c
+++ b/freebsd/sys/kern/uipc_usrreq.c
@@ -202,10 +202,9 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD,
/*
* Locking and synchronization:
*
- * Three types of locks exit in the local domain socket implementation: a
- * global list mutex, a global linkage rwlock, and per-unpcb mutexes. Of the
- * global locks, the list lock protects the socket count, global generation
- * number, and stream/datagram global lists. The linkage lock protects the
+ * Two types of locks exist in the local domain socket implementation: a
+ * a global linkage rwlock and per-unpcb mutexes. The linkage lock protects
+ * the socket count, global generation number, stream/datagram global lists and
* interconnection of unpcbs, the v_socket and unp_vnode pointers, and can be
* held exclusively over the acquisition of multiple unpcb locks to prevent
* deadlock.
@@ -246,7 +245,6 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD,
* to perform namei() and other file system operations.
*/
static struct rwlock unp_link_rwlock;
-static struct mtx unp_list_lock;
static struct mtx unp_defers_lock;
#define UNP_LINK_LOCK_INIT() rw_init(&unp_link_rwlock, \
@@ -263,11 +261,7 @@ static struct mtx unp_defers_lock;
#define UNP_LINK_WUNLOCK() rw_wunlock(&unp_link_rwlock)
#define UNP_LINK_WLOCK_ASSERT() rw_assert(&unp_link_rwlock, \
RA_WLOCKED)
-
-#define UNP_LIST_LOCK_INIT() mtx_init(&unp_list_lock, \
- "unp_list_lock", NULL, MTX_DEF)
-#define UNP_LIST_LOCK() mtx_lock(&unp_list_lock)
-#define UNP_LIST_UNLOCK() mtx_unlock(&unp_list_lock)
+#define UNP_LINK_WOWNED() rw_wowned(&unp_link_rwlock)
#define UNP_DEFERRED_LOCK_INIT() mtx_init(&unp_defers_lock, \
"unp_defer", NULL, MTX_DEF)
@@ -417,6 +411,7 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
u_long sendspace, recvspace;
struct unpcb *unp;
int error;
+ bool locked;
KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL"));
if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
@@ -451,10 +446,12 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
unp->unp_socket = so;
so->so_pcb = unp;
unp->unp_refcount = 1;
- if (so->so_head != NULL)
+ if (so->so_listen != NULL)
unp->unp_flags |= UNP_NASCENT;
- UNP_LIST_LOCK();
+ if ((locked = UNP_LINK_WOWNED()) == false)
+ UNP_LINK_WLOCK();
+
unp->unp_gencnt = ++unp_gencnt;
unp_count++;
switch (so->so_type) {
@@ -473,7 +470,9 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
default:
panic("uipc_attach");
}
- UNP_LIST_UNLOCK();
+
+ if (locked == false)
+ UNP_LINK_WUNLOCK();
return (0);
}
@@ -516,6 +515,14 @@ static const IMFS_node_control rtems_uipc_imfs_control =
static const IMFS_node_control rtems_uipc_imfs_zombi_control =
IMFS_GENERIC_INITIALIZER(&rtems_filesystem_handlers_default, NULL,
IMFS_node_destroy_default);
+
+static void
+VOP_UNP_DETACH(IMFS_generic_t *vp)
+{
+
+ vp->Node.control = &rtems_uipc_imfs_zombi_control;
+ vp->context = NULL;
+}
#endif /* __rtems__ */
static int
uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
@@ -630,7 +637,7 @@ restart:
UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
#ifndef __rtems__
- VOP_UNP_BIND(vp, unp->unp_socket);
+ VOP_UNP_BIND(vp, unp);
unp->unp_vnode = vp;
#endif /* __rtems__ */
unp->unp_addr = soun;
@@ -690,6 +697,11 @@ static void
uipc_close(struct socket *so)
{
struct unpcb *unp, *unp2;
+#ifndef __rtems__
+ struct vnode *vp;
+#else /* __rtems__ */
+ IMFS_generic_t *vp;
+#endif /* __rtems__ */
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_close: unp == NULL"));
@@ -702,8 +714,16 @@ uipc_close(struct socket *so)
unp_disconnect(unp, unp2);
UNP_PCB_UNLOCK(unp2);
}
+ if (SOLISTENING(so) && ((vp = unp->unp_vnode) != NULL)) {
+ VOP_UNP_DETACH(vp);
+ unp->unp_vnode = NULL;
+ }
UNP_PCB_UNLOCK(unp);
UNP_LINK_WUNLOCK();
+#ifndef __rtems__
+ if (vp)
+ vrele(vp);
+#endif /* __rtems__ */
}
static int
@@ -747,29 +767,16 @@ uipc_detach(struct socket *so)
local_unp_rights = 0;
#endif /* __rtems__ */
- UNP_LIST_LOCK();
+ UNP_LINK_WLOCK();
LIST_REMOVE(unp, unp_link);
unp->unp_gencnt = ++unp_gencnt;
--unp_count;
- UNP_LIST_UNLOCK();
-
- if ((unp->unp_flags & UNP_NASCENT) != 0) {
- UNP_PCB_LOCK(unp);
- goto teardown;
- }
- UNP_LINK_WLOCK();
UNP_PCB_LOCK(unp);
+ if ((unp->unp_flags & UNP_NASCENT) != 0)
+ goto teardown;
- /*
- * XXXRW: Should assert vp->v_socket == so.
- */
if ((vp = unp->unp_vnode) != NULL) {
-#ifndef __rtems__
VOP_UNP_DETACH(vp);
-#else /* __rtems__ */
- vp->Node.control = &rtems_uipc_imfs_zombi_control;
- vp->context = NULL;
-#endif /* __rtems__ */
unp->unp_vnode = NULL;
}
unp2 = unp->unp_conn;
@@ -793,8 +800,8 @@ uipc_detach(struct socket *so)
#ifndef __rtems__
local_unp_rights = unp_rights;
#endif /* __rtems__ */
- UNP_LINK_WUNLOCK();
teardown:
+ UNP_LINK_WUNLOCK();
unp->unp_socket->so_pcb = NULL;
saved_unp_addr = unp->unp_addr;
unp->unp_addr = NULL;
@@ -860,7 +867,6 @@ uipc_listen(struct socket *so, int backlog, struct thread *td)
error = solisten_proto_check(so);
if (error == 0) {
cru2x(td->td_ucred, &unp->unp_peercred);
- unp->unp_flags |= UNP_HAVEPCCACHED;
solisten_proto(so, backlog);
}
SOCK_UNLOCK(so);
@@ -1439,7 +1445,7 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
#else /* __rtems__ */
struct IMFS_jnode_tt *vp;
#endif /* __rtems__ */
- struct socket *so2, *so3;
+ struct socket *so2;
struct unpcb *unp, *unp2, *unp3;
#ifndef __rtems__
struct nameidata nd;
@@ -1450,7 +1456,9 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
const rtems_filesystem_location_info_t *currentloc;
#endif /* __rtems__ */
struct sockaddr *sa;
+#ifndef __rtems__
cap_rights_t rights;
+#endif /* __rtems__ */
int error, len;
if (nam->sa_family != AF_UNIX)
@@ -1535,34 +1543,38 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
*/
UNP_LINK_WLOCK();
#ifndef __rtems__
- VOP_UNP_CONNECT(vp, &so2);
+ VOP_UNP_CONNECT(vp, &unp2);
+ if (unp2 == NULL) {
+ error = ECONNREFUSED;
+ goto bad2;
+ }
+ so2 = unp2->unp_socket;
#else /* __rtems__ */
so2 = IMFS_generic_get_context_by_node(vp);
-#endif /* __rtems__ */
if (so2 == NULL) {
error = ECONNREFUSED;
goto bad2;
}
+ unp2 = sotounpcb(so2);
+#endif /* __rtems__ */
if (so->so_type != so2->so_type) {
error = EPROTOTYPE;
goto bad2;
}
+ UNP_PCB_LOCK(unp);
+ UNP_PCB_LOCK(unp2);
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
if (so2->so_options & SO_ACCEPTCONN) {
CURVNET_SET(so2->so_vnet);
- so3 = sonewconn(so2, 0);
+ so2 = sonewconn(so2, 0);
CURVNET_RESTORE();
} else
- so3 = NULL;
- if (so3 == NULL) {
+ so2 = NULL;
+ if (so2 == NULL) {
error = ECONNREFUSED;
- goto bad2;
+ goto bad3;
}
- unp = sotounpcb(so);
- unp2 = sotounpcb(so2);
- unp3 = sotounpcb(so3);
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+ unp3 = sotounpcb(so2);
UNP_PCB_LOCK(unp3);
if (unp2->unp_addr != NULL) {
bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len);
@@ -1583,30 +1595,24 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
* listen(); uipc_listen() cached that process's credentials
* at that time so we can use them now.
*/
- KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
- ("unp_connect: listener without cached peercred"));
memcpy(&unp->unp_peercred, &unp2->unp_peercred,
sizeof(unp->unp_peercred));
unp->unp_flags |= UNP_HAVEPC;
if (unp2->unp_flags & UNP_WANTCRED)
unp3->unp_flags |= UNP_WANTCRED;
- UNP_PCB_UNLOCK(unp3);
UNP_PCB_UNLOCK(unp2);
- UNP_PCB_UNLOCK(unp);
+ unp2 = unp3;
#ifdef MAC
- mac_socketpeer_set_from_socket(so, so3);
- mac_socketpeer_set_from_socket(so3, so);
+ mac_socketpeer_set_from_socket(so, so2);
+ mac_socketpeer_set_from_socket(so2, so);
#endif
-
- so2 = so3;
}
- unp = sotounpcb(so);
- KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
- unp2 = sotounpcb(so2);
- KASSERT(unp2 != NULL, ("unp_connect: unp2 == NULL"));
- UNP_PCB_LOCK(unp);
- UNP_PCB_LOCK(unp2);
+
+ KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 &&
+ sotounpcb(so2) == unp2,
+ ("%s: unp2 %p so2 %p", __func__, unp2, so2));
error = unp_connect2(so, so2, PRU_CONNECT);
+bad3:
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
bad2:
@@ -1750,10 +1756,10 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
* OK, now we're committed to doing something.
*/
xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK);
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
gencnt = unp_gencnt;
n = unp_count;
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
xug->xug_len = sizeof *xug;
xug->xug_count = n;
@@ -1767,7 +1773,7 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK);
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
for (unp = LIST_FIRST(head), i = 0; unp && i < n;
unp = LIST_NEXT(unp, unp_link)) {
UNP_PCB_LOCK(unp);
@@ -1782,7 +1788,7 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
}
UNP_PCB_UNLOCK(unp);
}
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
n = i; /* In case we lost some during malloc. */
error = 0;
@@ -2044,7 +2050,6 @@ unp_init(void)
TASK_INIT(&unp_defer_task, 0, unp_process_defers, NULL);
#endif /* __rtems__ */
UNP_LINK_LOCK_INIT();
- UNP_LIST_LOCK_INIT();
UNP_DEFERRED_LOCK_INIT();
}
@@ -2396,8 +2401,7 @@ unp_accessable(struct filedescent **fdep, int fdcount)
static void
unp_gc_process(struct unpcb *unp)
{
- struct socket *soa;
- struct socket *so;
+ struct socket *so, *soa;
struct file *fp;
/* Already processed. */
@@ -2417,28 +2421,30 @@ unp_gc_process(struct unpcb *unp)
return;
}
- /*
- * Mark all sockets we reference with RIGHTS.
- */
so = unp->unp_socket;
- if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
- SOCKBUF_LOCK(&so->so_rcv);
- unp_scan(so->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&so->so_rcv);
- }
-
- /*
- * Mark all sockets in our accept queue.
- */
- ACCEPT_LOCK();
- TAILQ_FOREACH(soa, &so->so_comp, so_list) {
- if ((sotounpcb(soa)->unp_gcflag & UNPGC_IGNORE_RIGHTS) != 0)
- continue;
- SOCKBUF_LOCK(&soa->so_rcv);
- unp_scan(soa->so_rcv.sb_mb, unp_accessable);
- SOCKBUF_UNLOCK(&soa->so_rcv);
+ SOCK_LOCK(so);
+ if (SOLISTENING(so)) {
+ /*
+ * Mark all sockets in our accept queue.
+ */
+ TAILQ_FOREACH(soa, &so->sol_comp, so_list) {
+ if (sotounpcb(soa)->unp_gcflag & UNPGC_IGNORE_RIGHTS)
+ continue;
+ SOCKBUF_LOCK(&soa->so_rcv);
+ unp_scan(soa->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&soa->so_rcv);
+ }
+ } else {
+ /*
+ * Mark all sockets we reference with RIGHTS.
+ */
+ if ((unp->unp_gcflag & UNPGC_IGNORE_RIGHTS) == 0) {
+ SOCKBUF_LOCK(&so->so_rcv);
+ unp_scan(so->so_rcv.sb_mb, unp_accessable);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ }
}
- ACCEPT_UNLOCK();
+ SOCK_UNLOCK(so);
unp->unp_gcflag |= UNPGC_SCANNED;
}
@@ -2461,7 +2467,7 @@ unp_gc(__unused void *arg, int pending)
int i, total;
unp_taskcount++;
- UNP_LIST_LOCK();
+ UNP_LINK_RLOCK();
/*
* First clear all gc flags from previous runs, apart from
* UNPGC_IGNORE_RIGHTS.
@@ -2484,7 +2490,7 @@ unp_gc(__unused void *arg, int pending)
LIST_FOREACH(unp, *head, unp_link)
unp_gc_process(unp);
} while (unp_marked);
- UNP_LIST_UNLOCK();
+ UNP_LINK_RUNLOCK();
if (unp_unreachable == 0)
return;
@@ -2499,7 +2505,6 @@ unp_gc(__unused void *arg, int pending)
* as as unreachable and store them locally.
*/
UNP_LINK_RLOCK();
- UNP_LIST_LOCK();
for (total = 0, head = heads; *head != NULL; head++)
LIST_FOREACH(unp, *head, unp_link)
if ((unp->unp_gcflag & UNPGC_DEAD) != 0) {
@@ -2512,7 +2517,6 @@ unp_gc(__unused void *arg, int pending)
KASSERT(total <= unp_unreachable,
("unp_gc: incorrect unreachable count."));
}
- UNP_LIST_UNLOCK();
UNP_LINK_RUNLOCK();
/*
@@ -2555,10 +2559,11 @@ unp_dispose(struct socket *so)
struct unpcb *unp;
unp = sotounpcb(so);
- UNP_LIST_LOCK();
+ UNP_LINK_WLOCK();
unp->unp_gcflag |= UNPGC_IGNORE_RIGHTS;
- UNP_LIST_UNLOCK();
- unp_dispose_mbuf(so->so_rcv.sb_mb);
+ UNP_LINK_WUNLOCK();
+ if (!SOLISTENING(so))
+ unp_dispose_mbuf(so->so_rcv.sb_mb);
}
static void
@@ -2613,7 +2618,6 @@ unp_scan(struct mbuf *m0, void (*op)(struct filedescent **, int))
void
vfs_unp_reclaim(struct vnode *vp)
{
- struct socket *so;
struct unpcb *unp;
int active;
@@ -2623,10 +2627,7 @@ vfs_unp_reclaim(struct vnode *vp)
active = 0;
UNP_LINK_WLOCK();
- VOP_UNP_CONNECT(vp, &so);
- if (so == NULL)
- goto done;
- unp = sotounpcb(so);
+ VOP_UNP_CONNECT(vp, &unp);
if (unp == NULL)
goto done;
UNP_PCB_LOCK(unp);
@@ -2663,10 +2664,6 @@ db_print_unpflags(int unp_flags)
db_printf("%sUNP_HAVEPC", comma ? ", " : "");
comma = 1;
}
- if (unp_flags & UNP_HAVEPCCACHED) {
- db_printf("%sUNP_HAVEPCCACHED", comma ? ", " : "");
- comma = 1;
- }
if (unp_flags & UNP_WANTCRED) {
db_printf("%sUNP_WANTCRED", comma ? ", " : "");
comma = 1;
diff --git a/freebsd/sys/net/bpf.c b/freebsd/sys/net/bpf.c
index d7a2abf7..b0ecb039 100644
--- a/freebsd/sys/net/bpf.c
+++ b/freebsd/sys/net/bpf.c
@@ -926,8 +926,6 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
return (error);
}
#else /* __rtems__ */
- u_int size;
-
d = malloc(sizeof(*d), M_BPF, M_NOWAIT | M_ZERO);
if (d == NULL) {
return (d);
@@ -1360,7 +1358,7 @@ bpfioctl(struct bpf_d *d, u_long cmd, caddr_t addr, int flags,
#endif
case BIOCGETIF:
case BIOCGRTIMEOUT:
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
case BIOCGRTIMEOUT32:
#endif
case BIOCGSTATS:
@@ -1372,7 +1370,7 @@ bpfioctl(struct bpf_d *d, u_long cmd, caddr_t addr, int flags,
case FIONREAD:
case BIOCLOCK:
case BIOCSRTIMEOUT:
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
case BIOCSRTIMEOUT32:
#endif
case BIOCIMMEDIATE:
@@ -1596,7 +1594,7 @@ bpfioctl(struct bpf_d *d, u_long cmd, caddr_t addr, int flags,
* Set read timeout.
*/
case BIOCSRTIMEOUT:
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
case BIOCSRTIMEOUT32:
#endif
{
@@ -1627,12 +1625,12 @@ bpfioctl(struct bpf_d *d, u_long cmd, caddr_t addr, int flags,
* Get read timeout.
*/
case BIOCGRTIMEOUT:
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
case BIOCGRTIMEOUT32:
#endif
{
struct timeval *tv;
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
struct timeval32 *tv32;
struct timeval tv64;
@@ -1644,7 +1642,7 @@ bpfioctl(struct bpf_d *d, u_long cmd, caddr_t addr, int flags,
tv->tv_sec = d->bd_rtout / hz;
tv->tv_usec = (d->bd_rtout % hz) * tick;
-#if defined(COMPAT_FREEBSD32) && !defined(__mips__)
+#if defined(COMPAT_FREEBSD32) && defined(__amd64__)
if (cmd == BIOCGRTIMEOUT32) {
tv32 = (struct timeval32 *)addr;
tv32->tv_sec = tv->tv_sec;
diff --git a/freebsd/sys/net/ethernet.h b/freebsd/sys/net/ethernet.h
index bc5fa9cb..5cd1dc50 100644
--- a/freebsd/sys/net/ethernet.h
+++ b/freebsd/sys/net/ethernet.h
@@ -406,6 +406,12 @@ void ether_vlan_mtap(struct bpf_if *, struct mbuf *,
void *, u_int);
struct mbuf *ether_vlanencap(struct mbuf *, uint16_t);
+#ifdef _SYS_EVENTHANDLER_H_
+/* new ethernet interface attached event */
+typedef void (*ether_ifattach_event_handler_t)(void *, struct ifnet *);
+EVENTHANDLER_DECLARE(ether_ifattach_event, ether_ifattach_event_handler_t);
+#endif
+
#else /* _KERNEL */
#include <sys/cdefs.h>
diff --git a/freebsd/sys/net/if_enc.c b/freebsd/sys/net/if_enc.c
index 42b399d2..2a0b17d3 100644
--- a/freebsd/sys/net/if_enc.c
+++ b/freebsd/sys/net/if_enc.c
@@ -286,7 +286,7 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data,
/* Make a packet looks like it was received on enc(4) */
rcvif = (*ctx->mp)->m_pkthdr.rcvif;
(*ctx->mp)->m_pkthdr.rcvif = ifp;
- if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, NULL) != 0 ||
+ if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != 0 ||
*ctx->mp == NULL) {
*ctx->mp = NULL; /* consumed by filter */
return (EACCES);
diff --git a/freebsd/sys/net/if_enc.h b/freebsd/sys/net/if_enc.h
index 941ed12a..616c621f 100644
--- a/freebsd/sys/net/if_enc.h
+++ b/freebsd/sys/net/if_enc.h
@@ -33,6 +33,7 @@
struct ipsec_ctx_data {
struct mbuf **mp;
struct secasvar *sav;
+ struct inpcb *inp;
uint8_t af;
#define IPSEC_ENC_BEFORE 0x01
#define IPSEC_ENC_AFTER 0x02
diff --git a/freebsd/sys/net/if_ethersubr.c b/freebsd/sys/net/if_ethersubr.c
index c3c89d24..c0064fc6 100644
--- a/freebsd/sys/net/if_ethersubr.c
+++ b/freebsd/sys/net/if_ethersubr.c
@@ -40,6 +40,8 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@@ -933,6 +935,11 @@ ether_ifattach(struct ifnet *ifp, const u_int8_t *lla)
if_printf(ifp, "Ethernet address: %6D\n", lla, ":");
uuid_ether_add(LLADDR(sdl));
+
+ /* Add necessary bits are setup; announce it now. */
+ EVENTHANDLER_INVOKE(ether_ifattach_event, ifp);
+ if (IS_DEFAULT_VNET(curvnet))
+ devctl_notify("ETHERNET", ifp->if_xname, "IFATTACH", NULL);
}
/*
diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c
index 4d6e919e..ce696fb2 100644
--- a/freebsd/sys/net/if_lagg.c
+++ b/freebsd/sys/net/if_lagg.c
@@ -740,15 +740,16 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
lagg_setmulti(lp);
+ LAGG_WUNLOCK(sc);
+
if ((error = lagg_proto_addport(sc, lp)) != 0) {
/* Remove the port, without calling pr_delport. */
+ LAGG_WLOCK(sc);
lagg_port_destroy(lp, 0);
LAGG_UNLOCK_ASSERT(sc);
return (error);
}
- LAGG_WUNLOCK(sc);
-
/* Update lagg capabilities */
lagg_capabilities(sc);
lagg_linkstate(sc);
diff --git a/freebsd/sys/net/if_stf.c b/freebsd/sys/net/if_stf.c
index 719dd1fa..b29c5f93 100644
--- a/freebsd/sys/net/if_stf.c
+++ b/freebsd/sys/net/if_stf.c
@@ -141,7 +141,6 @@ SYSCTL_INT(_net_link_stf, OID_AUTO, permit_rfc1918, CTLFLAG_RWTUN,
struct stf_softc {
struct ifnet *sc_ifp;
- struct mtx sc_ro_mtx;
u_int sc_fibnum;
const struct encaptab *encap_cookie;
};
@@ -149,10 +148,6 @@ struct stf_softc {
static const char stfname[] = "stf";
-/*
- * Note that mutable fields in the softc are not currently locked.
- * We do lock sc_ro in stf_output though.
- */
static MALLOC_DEFINE(M_STF, stfname, "6to4 Tunnel Interface");
static const int ip_stf_ttl = 40;
@@ -259,7 +254,6 @@ stf_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
ifp->if_dname = stfname;
ifp->if_dunit = IF_DUNIT_NONE;
- mtx_init(&(sc)->sc_ro_mtx, "stf ro", NULL, MTX_DEF);
sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6,
stf_encapcheck, &in_stf_protosw, sc);
if (sc->encap_cookie == NULL) {
@@ -286,7 +280,6 @@ stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
err = encap_detach(sc->encap_cookie);
KASSERT(err == 0, ("Unexpected error detaching encap_cookie"));
- mtx_destroy(&(sc)->sc_ro_mtx);
bpfdetach(ifp);
if_detach(ifp);
if_free(ifp);
diff --git a/freebsd/sys/net/iflib.h b/freebsd/sys/net/iflib.h
index 8bd20bfc..6ac75dbb 100644
--- a/freebsd/sys/net/iflib.h
+++ b/freebsd/sys/net/iflib.h
@@ -33,7 +33,6 @@
#include <sys/bus.h>
#include <sys/cpuset.h>
#include <machine/bus.h>
-#include <sys/bus_dma.h>
#include <sys/nv.h>
#include <sys/gtaskqueue.h>
@@ -201,8 +200,6 @@ typedef struct if_softc_ctx {
uint8_t isc_txd_size[8];
uint8_t isc_rxd_size[8];
- int isc_max_txqsets;
- int isc_max_rxqsets;
int isc_tx_tso_segments_max;
int isc_tx_tso_size_max;
int isc_tx_tso_segsize_max;
diff --git a/freebsd/sys/net/route.c b/freebsd/sys/net/route.c
index f7768737..a6a19cb0 100644
--- a/freebsd/sys/net/route.c
+++ b/freebsd/sys/net/route.c
@@ -61,7 +61,6 @@
#include <net/route.h>
#include <net/route_var.h>
#include <net/vnet.h>
-#include <net/flowtable.h>
#ifdef RADIX_MPATH
#include <net/radix_mpath.h>
@@ -486,18 +485,23 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags,
/*
* Look up the address in the table for that Address Family
*/
- RIB_RLOCK(rh);
+ if ((ignflags & RTF_RNH_LOCKED) == 0)
+ RIB_RLOCK(rh);
+#ifdef INVARIANTS
+ else
+ RIB_LOCK_ASSERT(rh);
+#endif
rn = rh->rnh_matchaddr(dst, &rh->head);
if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
newrt = RNTORT(rn);
RT_LOCK(newrt);
RT_ADDREF(newrt);
- RIB_RUNLOCK(rh);
+ if ((ignflags & RTF_RNH_LOCKED) == 0)
+ RIB_RUNLOCK(rh);
return (newrt);
- } else
+ } else if ((ignflags & RTF_RNH_LOCKED) == 0)
RIB_RUNLOCK(rh);
-
/*
* Either we hit the root or could not find any match,
* which basically means: "cannot get there from here".
@@ -780,7 +784,9 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway,
if (ifa == NULL)
ifa = ifa_ifwithnet(gateway, 0, fibnum);
if (ifa == NULL) {
- struct rtentry *rt = rtalloc1_fib(gateway, 0, 0, fibnum);
+ struct rtentry *rt;
+
+ rt = rtalloc1_fib(gateway, 0, flags, fibnum);
if (rt == NULL)
return (NULL);
/*
@@ -1529,79 +1535,12 @@ rt_mpath_unlink(struct rib_head *rnh, struct rt_addrinfo *info,
}
#endif
-#ifdef FLOWTABLE
-static struct rtentry *
-rt_flowtable_check_route(struct rib_head *rnh, struct rt_addrinfo *info)
-{
-#if defined(INET6) || defined(INET)
- struct radix_node *rn;
-#endif
- struct rtentry *rt0;
-
- rt0 = NULL;
- /* "flow-table" only supports IPv6 and IPv4 at the moment. */
- switch (dst->sa_family) {
-#ifdef INET6
- case AF_INET6:
-#endif
-#ifdef INET
- case AF_INET:
-#endif
-#if defined(INET6) || defined(INET)
- rn = rnh->rnh_matchaddr(dst, &rnh->head);
- if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
- struct sockaddr *mask;
- u_char *m, *n;
- int len;
-
- /*
- * compare mask to see if the new route is
- * more specific than the existing one
- */
- rt0 = RNTORT(rn);
- RT_LOCK(rt0);
- RT_ADDREF(rt0);
- RT_UNLOCK(rt0);
- /*
- * A host route is already present, so
- * leave the flow-table entries as is.
- */
- if (rt0->rt_flags & RTF_HOST) {
- RTFREE(rt0);
- rt0 = NULL;
- } else if (!(flags & RTF_HOST) && netmask) {
- mask = rt_mask(rt0);
- len = mask->sa_len;
- m = (u_char *)mask;
- n = (u_char *)netmask;
- while (len-- > 0) {
- if (*n != *m)
- break;
- n++;
- m++;
- }
- if (len == 0 || (*n < *m)) {
- RTFREE(rt0);
- rt0 = NULL;
- }
- }
- }
-#endif/* INET6 || INET */
- }
-
- return (rt0);
-}
-#endif
-
int
rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
u_int fibnum)
{
int error = 0;
struct rtentry *rt, *rt_old;
-#ifdef FLOWTABLE
- struct rtentry *rt0;
-#endif
struct radix_node *rn;
struct rib_head *rnh;
struct ifaddr *ifa;
@@ -1735,10 +1674,6 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
}
#endif
-#ifdef FLOWTABLE
- rt0 = rt_flowtable_check_route(rnh, info);
-#endif /* FLOWTABLE */
-
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
@@ -1773,18 +1708,8 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
ifa_free(rt->rt_ifa);
R_Free(rt_key(rt));
uma_zfree(V_rtzone, rt);
-#ifdef FLOWTABLE
- if (rt0 != NULL)
- RTFREE(rt0);
-#endif
return (EEXIST);
}
-#ifdef FLOWTABLE
- else if (rt0 != NULL) {
- flowtable_route_flush(dst->sa_family, rt0);
- RTFREE(rt0);
- }
-#endif
if (rt_old != NULL) {
rt_notifydelete(rt_old, info);
@@ -1870,8 +1795,13 @@ rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info,
info->rti_info[RTAX_IFP] != NULL ||
(info->rti_info[RTAX_IFA] != NULL &&
!sa_equal(info->rti_info[RTAX_IFA], rt->rt_ifa->ifa_addr))) {
-
+ /*
+ * XXX: Temporarily set RTF_RNH_LOCKED flag in the rti_flags
+ * to avoid rlock in the ifa_ifwithroute().
+ */
+ info->rti_flags |= RTF_RNH_LOCKED;
error = rt_getifa_fib(info, fibnum);
+ info->rti_flags &= ~RTF_RNH_LOCKED;
if (info->rti_ifa != NULL)
free_ifa = 1;
diff --git a/freebsd/sys/net/route.h b/freebsd/sys/net/route.h
index d4bc4056..444559b5 100644
--- a/freebsd/sys/net/route.h
+++ b/freebsd/sys/net/route.h
@@ -189,7 +189,7 @@ struct rtentry {
/* 0x8000000 and up unassigned */
#define RTF_STICKY 0x10000000 /* always route dst->src */
-#define RTF_RNH_LOCKED 0x40000000 /* unused */
+#define RTF_RNH_LOCKED 0x40000000 /* radix node head is locked */
#define RTF_GWFLAG_COMPAT 0x80000000 /* a compatibility bit for interacting
with existing routing apps */
diff --git a/freebsd/sys/net80211/ieee80211_amrr.c b/freebsd/sys/net80211/ieee80211_amrr.c
index 84cc0f9b..42e9ac1a 100644
--- a/freebsd/sys/net80211/ieee80211_amrr.c
+++ b/freebsd/sys/net80211/ieee80211_amrr.c
@@ -119,6 +119,7 @@ amrr_init(struct ieee80211vap *vap)
KASSERT(vap->iv_rs == NULL, ("%s called multiple times", __func__));
+ nrefs++; /* XXX locking */
amrr = vap->iv_rs = IEEE80211_MALLOC(sizeof(struct ieee80211_amrr),
M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
if (amrr == NULL) {
@@ -135,6 +136,8 @@ static void
amrr_deinit(struct ieee80211vap *vap)
{
IEEE80211_FREE(vap->iv_rs, M_80211_RATECTL);
+ KASSERT(nrefs > 0, ("imbalanced attach/detach"));
+ nrefs--; /* XXX locking */
}
/*
diff --git a/freebsd/sys/net80211/ieee80211_output.c b/freebsd/sys/net80211/ieee80211_output.c
index 5e67b82d..85bfeb0a 100644
--- a/freebsd/sys/net80211/ieee80211_output.c
+++ b/freebsd/sys/net80211/ieee80211_output.c
@@ -781,6 +781,9 @@ ieee80211_send_setup(
tap = &ni->ni_tx_ampdu[tid];
if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) {
m->m_flags |= M_AMPDU_MPDU;
+
+ /* NB: zero out i_seq field (for s/w encryption etc) */
+ *(uint16_t *)&wh->i_seq[0] = 0;
} else {
if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK,
type & IEEE80211_FC0_SUBTYPE_MASK))
@@ -1612,6 +1615,9 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
*(uint16_t *)wh->i_seq =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
M_SEQNO_SET(m, seqno);
+ } else {
+ /* NB: zero out i_seq field (for s/w encryption etc) */
+ *(uint16_t *)wh->i_seq = 0;
}
} else {
/*
diff --git a/freebsd/sys/net80211/ieee80211_rssadapt.c b/freebsd/sys/net80211/ieee80211_rssadapt.c
index e4421e6a..5d404fa1 100644
--- a/freebsd/sys/net80211/ieee80211_rssadapt.c
+++ b/freebsd/sys/net80211/ieee80211_rssadapt.c
@@ -132,7 +132,8 @@ rssadapt_init(struct ieee80211vap *vap)
KASSERT(vap->iv_rs == NULL, ("%s: iv_rs already initialized",
__func__));
-
+
+ nrefs++; /* XXX locking */
vap->iv_rs = rs = IEEE80211_MALLOC(sizeof(struct ieee80211_rssadapt),
M_80211_RATECTL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
if (rs == NULL) {
@@ -148,6 +149,8 @@ static void
rssadapt_deinit(struct ieee80211vap *vap)
{
IEEE80211_FREE(vap->iv_rs, M_80211_RATECTL);
+ KASSERT(nrefs > 0, ("imbalanced attach/detach"));
+ nrefs--; /* XXX locking */
}
static void
diff --git a/freebsd/sys/netinet/cc/cc_newreno.c b/freebsd/sys/netinet/cc/cc_newreno.c
index fb6c1087..474afcc9 100644
--- a/freebsd/sys/netinet/cc/cc_newreno.c
+++ b/freebsd/sys/netinet/cc/cc_newreno.c
@@ -184,42 +184,30 @@ newreno_after_idle(struct cc_var *ccv)
static void
newreno_cong_signal(struct cc_var *ccv, uint32_t type)
{
- uint32_t cwin, ssthresh_on_loss;
- u_int mss;
-
- cwin = CCV(ccv, snd_cwnd);
- mss = CCV(ccv, t_maxseg);
- ssthresh_on_loss =
- max((CCV(ccv, snd_max) - CCV(ccv, snd_una)) / 2 / mss, 2)
- * mss;
+ u_int win;
/* Catch algos which mistakenly leak private signal types. */
KASSERT((type & CC_SIGPRIVMASK) == 0,
("%s: congestion signal type 0x%08x is private\n", __func__, type));
- cwin = max(cwin / 2 / mss, 2) * mss;
+ win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) *
+ CCV(ccv, t_maxseg);
switch (type) {
case CC_NDUPACK:
if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
- if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
- CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
- CCV(ccv, snd_cwnd) = cwin;
- }
+ if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
+ CCV(ccv, snd_ssthresh) = win;
ENTER_RECOVERY(CCV(ccv, t_flags));
}
break;
case CC_ECN:
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
- CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
- CCV(ccv, snd_cwnd) = cwin;
+ CCV(ccv, snd_ssthresh) = win;
+ CCV(ccv, snd_cwnd) = win;
ENTER_CONGRECOVERY(CCV(ccv, t_flags));
}
break;
- case CC_RTO:
- CCV(ccv, snd_ssthresh) = ssthresh_on_loss;
- CCV(ccv, snd_cwnd) = mss;
- break;
}
}
diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c
index 234f19fd..d9a5c511 100644
--- a/freebsd/sys/netinet/ip_output.c
+++ b/freebsd/sys/netinet/ip_output.c
@@ -65,7 +65,6 @@ __FBSDID("$FreeBSD$");
#include <net/netisr.h>
#include <net/pfil.h>
#include <net/route.h>
-#include <net/flowtable.h>
#ifdef RADIX_MPATH
#include <net/radix_mpath.h>
#endif
@@ -246,11 +245,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
bzero(ro, sizeof (*ro));
}
-#ifdef FLOWTABLE
- if (ro->ro_rt == NULL)
- (void )flowtable_lookup(AF_INET, m, ro);
-#endif
-
if (opt) {
int len = 0;
m = ip_insertoptions(m, opt, &len);
diff --git a/freebsd/sys/netinet/sctp_asconf.c b/freebsd/sys/netinet/sctp_asconf.c
index 04a813d3..aa31e488 100644
--- a/freebsd/sys/netinet/sctp_asconf.c
+++ b/freebsd/sys/netinet/sctp_asconf.c
@@ -184,7 +184,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_port = stcb->rport;
@@ -207,7 +207,7 @@ sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *ap
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_port = stcb->rport;
@@ -334,7 +334,7 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_port = stcb->rport;
@@ -354,7 +354,7 @@ sctp_process_asconf_delete_ip(struct sockaddr *src,
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_port = stcb->rport;
@@ -463,7 +463,7 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
}
v4addr = (struct sctp_ipv4addr_param *)ph;
sin = &store.sin;
- bzero(sin, sizeof(*sin));
+ memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_addr.s_addr = v4addr->addr;
@@ -481,7 +481,7 @@ sctp_process_asconf_set_primary(struct sockaddr *src,
}
v6addr = (struct sctp_ipv6addr_param *)ph;
sin6 = &store.sin6;
- bzero(sin6, sizeof(*sin6));
+ memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
@@ -2606,7 +2606,7 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
SCTP_BUF_LEN(m_asconf) = 0;
acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
- bzero(acp, sizeof(struct sctp_asconf_chunk));
+ memset(acp, 0, sizeof(struct sctp_asconf_chunk));
/* save pointers to lookup address and asconf params */
lookup_ptr = (caddr_t)(acp + 1); /* after the header */
ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */
@@ -2739,7 +2739,7 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
/* XXX for now, we send a IPv4 address of 0.0.0.0 */
lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
- bzero(lookup->addr, sizeof(struct in_addr));
+ memset(lookup->addr, 0, sizeof(struct in_addr));
SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
}
}
diff --git a/freebsd/sys/netinet/sctp_auth.c b/freebsd/sys/netinet/sctp_auth.c
index 4bcb2459..b6dfdaf8 100644
--- a/freebsd/sys/netinet/sctp_auth.c
+++ b/freebsd/sys/netinet/sctp_auth.c
@@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
void
sctp_clear_chunklist(sctp_auth_chklist_t *chklist)
{
- bzero(chklist, sizeof(*chklist));
+ memset(chklist, 0, sizeof(*chklist));
/* chklist->num_chunks = 0; */
}
@@ -94,7 +94,7 @@ sctp_copy_chunklist(sctp_auth_chklist_t *list)
if (new_list == NULL)
return (NULL);
/* copy it */
- bcopy(list, new_list, sizeof(*new_list));
+ memcpy(new_list, list, sizeof(*new_list));
return (new_list);
}
@@ -340,7 +340,7 @@ sctp_set_key(uint8_t *key, uint32_t keylen)
/* out of memory */
return (NULL);
}
- bcopy(key, new_key->key, keylen);
+ memcpy(new_key->key, key, keylen);
return (new_key);
}
@@ -429,28 +429,28 @@ sctp_compute_hashkey(sctp_key_t *key1, sctp_key_t *key2, sctp_key_t *shared)
if (sctp_compare_key(key1, key2) <= 0) {
/* key is shared + key1 + key2 */
if (sctp_get_keylen(shared)) {
- bcopy(shared->key, key_ptr, shared->keylen);
+ memcpy(key_ptr, shared->key, shared->keylen);
key_ptr += shared->keylen;
}
if (sctp_get_keylen(key1)) {
- bcopy(key1->key, key_ptr, key1->keylen);
+ memcpy(key_ptr, key1->key, key1->keylen);
key_ptr += key1->keylen;
}
if (sctp_get_keylen(key2)) {
- bcopy(key2->key, key_ptr, key2->keylen);
+ memcpy(key_ptr, key2->key, key2->keylen);
}
} else {
/* key is shared + key2 + key1 */
if (sctp_get_keylen(shared)) {
- bcopy(shared->key, key_ptr, shared->keylen);
+ memcpy(key_ptr, shared->key, shared->keylen);
key_ptr += shared->keylen;
}
if (sctp_get_keylen(key2)) {
- bcopy(key2->key, key_ptr, key2->keylen);
+ memcpy(key_ptr, key2->key, key2->keylen);
key_ptr += key2->keylen;
}
if (sctp_get_keylen(key1)) {
- bcopy(key1->key, key_ptr, key1->keylen);
+ memcpy(key_ptr, key1->key, key1->keylen);
}
}
return (new_key);
@@ -766,7 +766,7 @@ sctp_serialize_hmaclist(sctp_hmaclist_t *list, uint8_t *ptr)
for (i = 0; i < list->num_algo; i++) {
hmac_id = htons(list->hmac[i]);
- bcopy(&hmac_id, ptr, sizeof(hmac_id));
+ memcpy(ptr, &hmac_id, sizeof(hmac_id));
ptr += sizeof(hmac_id);
}
return (list->num_algo * sizeof(hmac_id));
@@ -797,7 +797,7 @@ sctp_alloc_authinfo(void)
/* out of memory */
return (NULL);
}
- bzero(new_authinfo, sizeof(*new_authinfo));
+ memset(new_authinfo, 0, sizeof(*new_authinfo));
return (new_authinfo);
}
@@ -955,10 +955,10 @@ sctp_hmac(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
key = temp;
}
/* initialize the inner/outer pads with the key and "append" zeroes */
- bzero(ipad, blocklen);
- bzero(opad, blocklen);
- bcopy(key, ipad, keylen);
- bcopy(key, opad, keylen);
+ memset(ipad, 0, blocklen);
+ memset(opad, 0, blocklen);
+ memcpy(ipad, key, keylen);
+ memcpy(opad, key, keylen);
/* XOR the key with ipad and opad values */
for (i = 0; i < blocklen; i++) {
@@ -1015,10 +1015,10 @@ sctp_hmac_m(uint16_t hmac_algo, uint8_t *key, uint32_t keylen,
key = temp;
}
/* initialize the inner/outer pads with the key and "append" zeroes */
- bzero(ipad, blocklen);
- bzero(opad, blocklen);
- bcopy(key, ipad, keylen);
- bcopy(key, opad, keylen);
+ memset(ipad, 0, blocklen);
+ memset(opad, 0, blocklen);
+ memcpy(ipad, key, keylen);
+ memcpy(opad, key, keylen);
/* XOR the key with ipad and opad values */
for (i = 0; i < blocklen; i++) {
@@ -1126,7 +1126,7 @@ sctp_compute_hmac(uint16_t hmac_algo, sctp_key_t *key, uint8_t *text,
sctp_hmac_final(hmac_algo, &ctx, temp);
/* save the hashed key as the new key */
key->keylen = digestlen;
- bcopy(temp, key->key, key->keylen);
+ memcpy(key->key, temp, key->keylen);
}
return (sctp_hmac(hmac_algo, key->key, key->keylen, text, textlen,
digest));
@@ -1160,7 +1160,7 @@ sctp_compute_hmac_m(uint16_t hmac_algo, sctp_key_t *key, struct mbuf *m,
sctp_hmac_final(hmac_algo, &ctx, temp);
/* save the hashed key as the new key */
key->keylen = digestlen;
- bcopy(temp, key->key, key->keylen);
+ memcpy(key->key, temp, key->keylen);
}
return (sctp_hmac_m(hmac_algo, key->key, key->keylen, m, m_offset, digest, 0));
}
@@ -1436,7 +1436,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(random_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
+ (struct sctp_paramhdr *)random_store, plen);
if (phdr == NULL)
return;
/* save the random and length for the key */
@@ -1449,7 +1449,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(hmacs_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store)));
+ (struct sctp_paramhdr *)hmacs_store, plen);
if (phdr == NULL)
return;
/* save the hmacs list and num for the key */
@@ -1471,7 +1471,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(chunks_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store)));
+ (struct sctp_paramhdr *)chunks_store, plen);
if (phdr == NULL)
return;
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -1503,17 +1503,17 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
/* copy in the RANDOM */
if (p_random != NULL) {
keylen = sizeof(*p_random) + random_len;
- bcopy(p_random, new_key->key, keylen);
+ memcpy(new_key->key, p_random, keylen);
}
/* append in the AUTH chunks */
if (chunks != NULL) {
- bcopy(chunks, new_key->key + keylen,
+ memcpy(new_key->key + keylen, chunks,
sizeof(*chunks) + num_chunks);
keylen += sizeof(*chunks) + num_chunks;
}
/* append in the HMACs */
if (hmacs != NULL) {
- bcopy(hmacs, new_key->key + keylen,
+ memcpy(new_key->key + keylen, hmacs,
sizeof(*hmacs) + hmacs_len);
}
}
@@ -1552,7 +1552,7 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
/* zero the digest + chunk padding */
digestlen = sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id);
- bzero(auth->hmac, SCTP_SIZE32(digestlen));
+ memset(auth->hmac, 0, SCTP_SIZE32(digestlen));
/* is the desired key cached? */
if ((keyid != stcb->asoc.authinfo.assoc_keyid) ||
@@ -1590,7 +1590,7 @@ sctp_fill_hmac_digest_m(struct mbuf *m, uint32_t auth_offset,
static void
-sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
+sctp_zero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
{
struct mbuf *m_tmp;
uint8_t *data;
@@ -1609,10 +1609,10 @@ sctp_bzero_m(struct mbuf *m, uint32_t m_offset, uint32_t size)
while ((m_tmp != NULL) && (size > 0)) {
data = mtod(m_tmp, uint8_t *)+m_offset;
if (size > (uint32_t)SCTP_BUF_LEN(m_tmp)) {
- bzero(data, SCTP_BUF_LEN(m_tmp));
+ memset(data, 0, SCTP_BUF_LEN(m_tmp));
size -= SCTP_BUF_LEN(m_tmp);
} else {
- bzero(data, size);
+ memset(data, 0, size);
size = 0;
}
/* clear the offset since it's only for the first mbuf */
@@ -1729,8 +1729,8 @@ sctp_handle_auth(struct sctp_tcb *stcb, struct sctp_auth_chunk *auth,
return (-1);
}
/* save a copy of the digest, zero the pseudo header, and validate */
- bcopy(auth->hmac, digest, digestlen);
- sctp_bzero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
+ memcpy(digest, auth->hmac, digestlen);
+ sctp_zero_m(m, offset + sizeof(*auth), SCTP_SIZE32(digestlen));
(void)sctp_compute_hmac_m(hmac_id, stcb->asoc.authinfo.recv_key,
m, offset, computed_digest);
@@ -1799,8 +1799,8 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
@@ -1816,7 +1816,7 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
int
sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
{
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
uint16_t ptype, plen;
int peer_supports_asconf = 0;
int peer_supports_auth = 0;
@@ -1825,7 +1825,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
uint8_t saw_asconf_ack = 0;
/* go through each of the params. */
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
@@ -1839,11 +1839,15 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (ptype == SCTP_SUPPORTED_CHUNK_EXT) {
/* A supported extension chunk */
struct sctp_supported_chunk_types_param *pr_supported;
- uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
+ uint8_t local_store[SCTP_SMALL_CHUNK_STORE];
int num_ent, i;
+ if (plen > sizeof(local_store)) {
+ break;
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store)));
+ (struct sctp_paramhdr *)&local_store,
+ plen);
if (phdr == NULL) {
return (-1);
}
@@ -1861,7 +1865,6 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
}
}
} else if (ptype == SCTP_RANDOM) {
- got_random = 1;
/* enforce the random length */
if (plen != (sizeof(struct sctp_auth_random) +
SCTP_AUTH_RANDOM_SIZE_REQUIRED)) {
@@ -1869,20 +1872,23 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
"SCTP: invalid RANDOM len\n");
return (-1);
}
+ got_random = 1;
} else if (ptype == SCTP_HMAC_LIST) {
- uint8_t store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs;
+ uint8_t store[SCTP_PARAM_BUFFER_SIZE];
int num_hmacs;
- if (plen > sizeof(store))
+ if (plen > sizeof(store)) {
break;
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, min(plen, sizeof(store)));
- if (phdr == NULL)
+ (struct sctp_paramhdr *)store,
+ plen);
+ if (phdr == NULL) {
return (-1);
+ }
hmacs = (struct sctp_auth_hmac_algo *)phdr;
- num_hmacs = (plen - sizeof(*hmacs)) /
- sizeof(hmacs->hmac_ids[0]);
+ num_hmacs = (plen - sizeof(*hmacs)) / sizeof(hmacs->hmac_ids[0]);
/* validate the hmac list */
if (sctp_verify_hmac_param(hmacs, num_hmacs)) {
SCTPDBG(SCTP_DEBUG_AUTH1,
@@ -1891,18 +1897,19 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
}
got_hmacs = 1;
} else if (ptype == SCTP_CHUNK_LIST) {
- int i, num_chunks;
+ struct sctp_auth_chunk_list *chunks;
uint8_t chunks_store[SCTP_SMALL_CHUNK_STORE];
+ int i, num_chunks;
- /* did the peer send a non-empty chunk list? */
- struct sctp_auth_chunk_list *chunks = NULL;
-
+ if (plen > sizeof(chunks_store)) {
+ break;
+ }
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
- min(plen, sizeof(chunks_store)));
- if (phdr == NULL)
+ plen);
+ if (phdr == NULL) {
return (-1);
-
+ }
/*-
* Flip through the list and mark that the
* peer supports asconf/asconf_ack.
@@ -1924,8 +1931,8 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (offset >= limit) {
break;
}
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
/* validate authentication required parameters */
if (got_random && got_hmacs) {
diff --git a/freebsd/sys/netinet/sctp_constants.h b/freebsd/sys/netinet/sctp_constants.h
index e779051d..dca34cc5 100644
--- a/freebsd/sys/netinet/sctp_constants.h
+++ b/freebsd/sys/netinet/sctp_constants.h
@@ -758,7 +758,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEFAULT_SPLIT_POINT_MIN 2904
/* Maximum length of diagnostic information in error causes */
-#define SCTP_DIAG_INFO_LEN 64
+#define SCTP_DIAG_INFO_LEN 128
/* ABORT CODES and other tell-tale location
* codes are generated by adding the below
diff --git a/freebsd/sys/netinet/sctp_indata.c b/freebsd/sys/netinet/sctp_indata.c
index 57f13a13..1924aeab 100644
--- a/freebsd/sys/netinet/sctp_indata.c
+++ b/freebsd/sys/netinet/sctp_indata.c
@@ -61,7 +61,7 @@ __FBSDID("$FreeBSD$");
* This will cause sctp_service_queues() to get called on the top entry in
* the list.
*/
-static void
+static uint32_t
sctp_add_chk_to_control(struct sctp_queued_to_read *control,
struct sctp_stream_in *strm,
struct sctp_tcb *stcb,
@@ -94,6 +94,8 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
asoc->size_on_reasm_queue == 0 &&
asoc->size_on_all_streams == 0) {
/* Full rwnd granted */
+ KASSERT(asoc->cnt_on_reasm_queue == 0, ("cnt_on_reasm_queue is %u", asoc->cnt_on_reasm_queue));
+ KASSERT(asoc->cnt_on_all_streams == 0, ("cnt_on_all_streams is %u", asoc->cnt_on_all_streams));
calc = max(SCTP_SB_LIMIT_RCV(stcb->sctp_socket), SCTP_MINIMAL_RWND);
return (calc);
}
@@ -560,7 +562,15 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb,
}
/* EY it wont be queued if it could be delivered directly */
queue_needed = 0;
- asoc->size_on_all_streams -= control->length;
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
strm->last_mid_delivered++;
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
@@ -573,10 +583,18 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb,
nxt_todel = strm->last_mid_delivered + 1;
if (SCTP_MID_EQ(asoc->idata_supported, nxt_todel, control->mid) &&
(((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG)) {
- asoc->size_on_all_streams -= control->length;
- sctp_ucount_decr(asoc->cnt_on_all_streams);
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
#ifdef INVARIANTS
} else {
panic("Huh control: %p is on_strm_q: %d",
@@ -673,7 +691,7 @@ sctp_setup_tail_pointer(struct sctp_queued_to_read *control)
}
static void
-sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m)
+sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m, uint32_t *added)
{
struct mbuf *prev = NULL;
struct sctp_tcb *stcb;
@@ -717,6 +735,7 @@ sctp_add_to_tail_pointer(struct sctp_queued_to_read *control, struct mbuf *m)
*/
sctp_sballoc(stcb, &stcb->sctp_socket->so_rcv, m);
}
+ *added += SCTP_BUF_LEN(m);
atomic_add_int(&control->length, SCTP_BUF_LEN(m));
m = SCTP_BUF_NEXT(m);
}
@@ -817,7 +836,15 @@ restart:
tchk = TAILQ_FIRST(&control->reasm);
if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
TAILQ_REMOVE(&control->reasm, tchk, sctp_next);
- asoc->size_on_reasm_queue -= tchk->send_size;
+ if (asoc->size_on_reasm_queue >= tchk->send_size) {
+ asoc->size_on_reasm_queue -= tchk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, tchk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
nc->first_frag_seen = 1;
nc->fsn_included = tchk->rec.data.fsn;
@@ -1129,6 +1156,16 @@ done_un:
#endif
SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
}
if (strm->pd_api_started && control->pdapi_started) {
@@ -1175,6 +1212,16 @@ deliver_more:
#endif
SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
}
ret++;
@@ -1221,7 +1268,7 @@ out:
}
-void
+uint32_t
sctp_add_chk_to_control(struct sctp_queued_to_read *control,
struct sctp_stream_in *strm,
struct sctp_tcb *stcb, struct sctp_association *asoc,
@@ -1231,6 +1278,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
* Given a control and a chunk, merge the data from the chk onto the
* control and free up the chunk resources.
*/
+ uint32_t added = 0;
int i_locked = 0;
if (control->on_read_q && (hold_rlock == 0)) {
@@ -1244,7 +1292,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
control->data = chk->data;
sctp_setup_tail_pointer(control);
} else {
- sctp_add_to_tail_pointer(control, chk->data);
+ sctp_add_to_tail_pointer(control, chk->data, &added);
}
control->fsn_included = chk->rec.data.fsn;
asoc->size_on_reasm_queue -= chk->send_size;
@@ -1270,6 +1318,16 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
} else if (control->on_strm_q == SCTP_ON_ORDERED) {
/* Ordered */
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
#ifdef INVARIANTS
} else if (control->on_strm_q) {
@@ -1285,6 +1343,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control,
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
+ return (added);
}
/*
@@ -1304,6 +1363,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_tmit_chunk *at, *nat;
struct sctp_stream_in *strm;
int do_wakeup, unordered;
+ uint32_t lenadded;
strm = &asoc->strmin[control->sinfo_stream];
/*
@@ -1316,6 +1376,9 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
/* Must be added to the stream-in queue */
if (created_control) {
+ if (unordered == 0) {
+ sctp_ucount_incr(asoc->cnt_on_all_streams);
+ }
if (sctp_place_control_in_stream(strm, asoc, control)) {
/* Duplicate SSN? */
sctp_clean_up_control(stcb, control);
@@ -1375,6 +1438,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
chk->data = NULL;
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
sctp_setup_tail_pointer(control);
+ asoc->size_on_all_streams += control->length;
} else {
/* Place the chunk in our list */
int inserted = 0;
@@ -1531,7 +1595,8 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
at->rec.data.fsn,
next_fsn, control->fsn_included);
TAILQ_REMOVE(&control->reasm, at, sctp_next);
- sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
+ lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
+ asoc->size_on_all_streams += lenadded;
if (control->on_read_q) {
do_wakeup = 1;
}
@@ -1602,7 +1667,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
uint16_t sid;
struct mbuf *op_err;
char msg[SCTP_DIAG_INFO_LEN];
- struct sctp_queued_to_read *control = NULL;
+ struct sctp_queued_to_read *control, *ncontrol;
uint32_t ppid;
uint8_t chk_flags;
struct sctp_stream_reset_list *liste;
@@ -2008,7 +2073,12 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
return (0);
}
if ((chk_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ struct mbuf *mm;
+
control->data = dmbuf;
+ for (mm = control->data; mm; mm = mm->m_next) {
+ control->length += SCTP_BUF_LEN(mm);
+ }
control->tail_mbuf = NULL;
control->end_added = 1;
control->last_frag_seen = 1;
@@ -2118,16 +2188,16 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* first one on */
TAILQ_INSERT_TAIL(&asoc->pending_reply_queue, control, next);
} else {
- struct sctp_queued_to_read *ctlOn, *nctlOn;
+ struct sctp_queued_to_read *lcontrol, *nlcontrol;
unsigned char inserted = 0;
- TAILQ_FOREACH_SAFE(ctlOn, &asoc->pending_reply_queue, next, nctlOn) {
- if (SCTP_TSN_GT(control->sinfo_tsn, ctlOn->sinfo_tsn)) {
+ TAILQ_FOREACH_SAFE(lcontrol, &asoc->pending_reply_queue, next, nlcontrol) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, lcontrol->sinfo_tsn)) {
continue;
} else {
/* found it */
- TAILQ_INSERT_BEFORE(ctlOn, control, next);
+ TAILQ_INSERT_BEFORE(lcontrol, control, next);
inserted = 1;
break;
}
@@ -2218,8 +2288,6 @@ finish_express_del:
* pending_reply space 3: distribute any chunks in
* pending_reply_queue.
*/
- struct sctp_queued_to_read *ctl, *nctl;
-
sctp_reset_in_stream(stcb, liste->number_entries, liste->list_of_streams);
TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
sctp_send_deferred_reset_response(stcb, liste, SCTP_STREAM_RESET_RESULT_PERFORMED);
@@ -2228,34 +2296,34 @@ finish_express_del:
liste = TAILQ_FIRST(&asoc->resetHead);
if (TAILQ_EMPTY(&asoc->resetHead)) {
/* All can be removed */
- TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
+ TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
+ TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
+ sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
if (need_reasm_check) {
- (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
+ (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
need_reasm_check = 0;
}
}
} else {
- TAILQ_FOREACH_SAFE(ctl, &asoc->pending_reply_queue, next, nctl) {
- if (SCTP_TSN_GT(ctl->sinfo_tsn, liste->tsn)) {
+ TAILQ_FOREACH_SAFE(control, &asoc->pending_reply_queue, next, ncontrol) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, liste->tsn)) {
break;
}
/*
- * if ctl->sinfo_tsn is <= liste->tsn we can
- * process it which is the NOT of
- * ctl->sinfo_tsn > liste->tsn
+ * if control->sinfo_tsn is <= liste->tsn we
+ * can process it which is the NOT of
+ * control->sinfo_tsn > liste->tsn
*/
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag, &need_reasm_check);
+ TAILQ_REMOVE(&asoc->pending_reply_queue, control, next);
+ sctp_queue_data_to_stream(stcb, asoc, control, abort_flag, &need_reasm_check);
if (*abort_flag) {
return (0);
}
if (need_reasm_check) {
- (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[ctl->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
+ (void)sctp_deliver_reasm_check(stcb, asoc, &asoc->strmin[control->sinfo_stream], SCTP_READ_LOCK_NOT_HELD);
need_reasm_check = 0;
}
}
@@ -4226,47 +4294,44 @@ again:
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
+ if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ (asoc->stream_queue_cnt == 1) &&
+ (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+
+ *abort_now = 1;
+ /* XXX */
+ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
+ }
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- /* Need to abort here */
- struct mbuf *op_err;
+ struct sctp_nets *netp;
- abort_out_now:
- *abort_now = 1;
- /* XXX */
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- return;
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
+ SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ sctp_stop_timers_for_shutdown(stcb);
+ if (asoc->alternate) {
+ netp = asoc->alternate;
} else {
- struct sctp_nets *netp;
-
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- if (asoc->alternate) {
- netp = asoc->alternate;
- } else {
- netp = asoc->primary_destination;
- }
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
+ netp = asoc->primary_destination;
}
+ sctp_send_shutdown(stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
+ stcb->sctp_ep, stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, netp);
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- goto abort_out_now;
- }
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
@@ -4922,48 +4987,45 @@ hopeless_peer:
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
+ if (((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) &&
+ (asoc->stream_queue_cnt == 1) &&
+ (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
+ struct mbuf *op_err;
+
+ *abort_now = 1;
+ /* XXX */
+ op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
+ sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ return;
+ }
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- /* Need to abort here */
- struct mbuf *op_err;
+ struct sctp_nets *netp;
- abort_out_now:
- *abort_now = 1;
- /* XXX */
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31;
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
- return;
+ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
+ (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
+ SCTP_STAT_DECR_GAUGE32(sctps_currestab);
+ }
+ SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
+ SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
+ sctp_stop_timers_for_shutdown(stcb);
+ if (asoc->alternate) {
+ netp = asoc->alternate;
} else {
- struct sctp_nets *netp;
-
- if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
- SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_stop_timers_for_shutdown(stcb);
- if (asoc->alternate) {
- netp = asoc->alternate;
- } else {
- netp = asoc->primary_destination;
- }
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, netp);
+ netp = asoc->primary_destination;
}
+ sctp_send_shutdown(stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
+ stcb->sctp_ep, stcb, netp);
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, netp);
return;
} else if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) &&
(asoc->stream_queue_cnt == 0)) {
struct sctp_nets *netp;
- if (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT) {
- goto abort_out_now;
- }
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT);
SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
@@ -5183,7 +5245,7 @@ static void
sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
struct sctp_stream_in *strmin)
{
- struct sctp_queued_to_read *ctl, *nctl;
+ struct sctp_queued_to_read *control, *ncontrol;
struct sctp_association *asoc;
uint32_t mid;
int need_reasm_check = 0;
@@ -5194,43 +5256,51 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
* First deliver anything prior to and including the stream no that
* came in.
*/
- TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
- if (SCTP_MID_GE(asoc->idata_supported, mid, ctl->mid)) {
+ TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_GE(asoc->idata_supported, mid, control->mid)) {
/* this is deliverable now */
- if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
- if (ctl->on_strm_q) {
- if (ctl->on_strm_q == SCTP_ON_ORDERED) {
- TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
- } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
- TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
+ if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ if (control->on_strm_q) {
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
#ifdef INVARIANTS
} else {
panic("strmin: %p ctl: %p unknown %d",
- strmin, ctl, ctl->on_strm_q);
+ strmin, control, control->on_strm_q);
#endif
}
- ctl->on_strm_q = 0;
+ control->on_strm_q = 0;
}
/* subtract pending on streams */
- asoc->size_on_all_streams -= ctl->length;
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
/* deliver it to at least the delivery-q */
if (stcb->sctp_socket) {
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
+ sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
- ctl,
+ control,
&stcb->sctp_socket->so_rcv,
1, SCTP_READ_LOCK_HELD,
SCTP_SO_NOT_LOCKED);
}
} else {
/* Its a fragmented message */
- if (ctl->first_frag_seen) {
+ if (control->first_frag_seen) {
/*
* Make it so this is next to
* deliver, we restore later
*/
- strmin->last_mid_delivered = ctl->mid - 1;
+ strmin->last_mid_delivered = control->mid - 1;
need_reasm_check = 1;
break;
}
@@ -5259,32 +5329,40 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
* now ready.
*/
mid = strmin->last_mid_delivered + 1;
- TAILQ_FOREACH_SAFE(ctl, &strmin->inqueue, next_instrm, nctl) {
- if (SCTP_MID_EQ(asoc->idata_supported, mid, ctl->mid)) {
- if (((ctl->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
+ TAILQ_FOREACH_SAFE(control, &strmin->inqueue, next_instrm, ncontrol) {
+ if (SCTP_MID_EQ(asoc->idata_supported, mid, control->mid)) {
+ if (((control->sinfo_flags >> 8) & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) {
/* this is deliverable now */
- if (ctl->on_strm_q) {
- if (ctl->on_strm_q == SCTP_ON_ORDERED) {
- TAILQ_REMOVE(&strmin->inqueue, ctl, next_instrm);
- } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
- TAILQ_REMOVE(&strmin->uno_inqueue, ctl, next_instrm);
+ if (control->on_strm_q) {
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strmin->inqueue, control, next_instrm);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strmin->uno_inqueue, control, next_instrm);
#ifdef INVARIANTS
} else {
panic("strmin: %p ctl: %p unknown %d",
- strmin, ctl, ctl->on_strm_q);
+ strmin, control, control->on_strm_q);
#endif
}
- ctl->on_strm_q = 0;
+ control->on_strm_q = 0;
}
/* subtract pending on streams */
- asoc->size_on_all_streams -= ctl->length;
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
/* deliver it to at least the delivery-q */
- strmin->last_mid_delivered = ctl->mid;
+ strmin->last_mid_delivered = control->mid;
if (stcb->sctp_socket) {
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
+ sctp_mark_non_revokable(asoc, control->sinfo_tsn);
sctp_add_to_readq(stcb->sctp_ep, stcb,
- ctl,
+ control,
&stcb->sctp_socket->so_rcv, 1,
SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
@@ -5292,12 +5370,12 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
mid = strmin->last_mid_delivered + 1;
} else {
/* Its a fragmented message */
- if (ctl->first_frag_seen) {
+ if (control->first_frag_seen) {
/*
* Make it so this is next to
* deliver
*/
- strmin->last_mid_delivered = ctl->mid - 1;
+ strmin->last_mid_delivered = control->mid - 1;
need_reasm_check = 1;
break;
}
@@ -5349,7 +5427,15 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
}
cnt_removed++;
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
- asoc->size_on_reasm_queue -= chk->send_size;
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
+ asoc->size_on_reasm_queue -= chk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
if (chk->data) {
sctp_m_freem(chk->data);
@@ -5375,6 +5461,16 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
}
if (control->on_strm_q == SCTP_ON_ORDERED) {
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
control->on_strm_q = 0;
} else if (control->on_strm_q == SCTP_ON_UNORDERED) {
TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
@@ -5418,7 +5514,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
unsigned int i, fwd_sz, m_size;
uint32_t str_seq;
struct sctp_stream_in *strm;
- struct sctp_queued_to_read *ctl, *sv;
+ struct sctp_queued_to_read *control, *sv;
asoc = &stcb->asoc;
if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) {
@@ -5577,25 +5673,35 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
for (cur_mid = strm->last_mid_delivered; SCTP_MID_GE(asoc->idata_supported, mid, cur_mid); cur_mid++) {
sctp_flush_reassm_for_str_seq(stcb, asoc, sid, cur_mid, ordered, new_cum_tsn);
}
- TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
- if ((ctl->sinfo_stream == sid) &&
- (SCTP_MID_EQ(asoc->idata_supported, ctl->mid, mid))) {
+ TAILQ_FOREACH(control, &stcb->sctp_ep->read_queue, next) {
+ if ((control->sinfo_stream == sid) &&
+ (SCTP_MID_EQ(asoc->idata_supported, control->mid, mid))) {
str_seq = (sid << 16) | (0x0000ffff & mid);
- ctl->pdapi_aborted = 1;
+ control->pdapi_aborted = 1;
sv = stcb->asoc.control_pdapi;
- ctl->end_added = 1;
- if (ctl->on_strm_q == SCTP_ON_ORDERED) {
- TAILQ_REMOVE(&strm->inqueue, ctl, next_instrm);
- } else if (ctl->on_strm_q == SCTP_ON_UNORDERED) {
- TAILQ_REMOVE(&strm->uno_inqueue, ctl, next_instrm);
+ control->end_added = 1;
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
#ifdef INVARIANTS
- } else if (ctl->on_strm_q) {
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
+ sctp_ucount_decr(asoc->cnt_on_all_streams);
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+#ifdef INVARIANTS
+ } else if (control->on_strm_q) {
panic("strm: %p ctl: %p unknown %d",
- strm, ctl, ctl->on_strm_q);
+ strm, control, control->on_strm_q);
#endif
}
- ctl->on_strm_q = 0;
- stcb->asoc.control_pdapi = ctl;
+ control->on_strm_q = 0;
+ stcb->asoc.control_pdapi = control;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb,
SCTP_PARTIAL_DELIVERY_ABORTED,
@@ -5603,8 +5709,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
SCTP_SO_NOT_LOCKED);
stcb->asoc.control_pdapi = sv;
break;
- } else if ((ctl->sinfo_stream == sid) &&
- SCTP_MID_GT(asoc->idata_supported, ctl->mid, mid)) {
+ } else if ((control->sinfo_stream == sid) &&
+ SCTP_MID_GT(asoc->idata_supported, control->mid, mid)) {
/* We are past our victim SSN */
break;
}
diff --git a/freebsd/sys/netinet/sctp_input.c b/freebsd/sys/netinet/sctp_input.c
index be01c38a..2e844fb5 100644
--- a/freebsd/sys/netinet/sctp_input.c
+++ b/freebsd/sys/netinet/sctp_input.c
@@ -2151,23 +2151,23 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* cookie was in flight. Only recourse is to abort the
* association.
*/
- atomic_add_int(&stcb->asoc.refcnt, 1);
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
src, dst, sh, op_err,
mflowtype, mflowid,
vrf_id, port);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_18);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* process the INIT-ACK info (my info) */
@@ -2188,36 +2188,36 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
else
retval = 0;
if (retval < 0) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* load all addresses */
if (sctp_load_addresses_from_init(stcb, m,
init_offset + sizeof(struct sctp_init_chunk), initack_offset,
src, dst, init_src, port)) {
- atomic_add_int(&stcb->asoc.refcnt, 1);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/*
@@ -2236,35 +2236,24 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
/* auth HMAC failed, dump the assoc and packet */
SCTPDBG(SCTP_DEBUG_AUTH1,
"COOKIE-ECHO: AUTH failed\n");
- atomic_add_int(&stcb->asoc.refcnt, 1);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_21);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
} else {
/* remaining chunks checked... good to go */
stcb->asoc.authenticated = 1;
}
}
- /* update current state */
- SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
- SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
- if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, asoc->primary_destination);
- }
- sctp_stop_all_cookie_timers(stcb);
- SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
- SCTP_STAT_INCR_GAUGE32(sctps_currestab);
-
/*
* if we're doing ASCONFs, check to see if we have any new local
* addresses that need to get added to the peer (eg. addresses
@@ -2297,21 +2286,32 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
break;
#endif
default:
- atomic_add_int(&stcb->asoc.refcnt, 1);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_22);
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
+ /* update current state */
+ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n");
+ SCTP_SET_STATE(asoc, SCTP_STATE_OPEN);
+ if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
+ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
+ stcb->sctp_ep, stcb, asoc->primary_destination);
+ }
+ sctp_stop_all_cookie_timers(stcb);
+ SCTP_STAT_INCR_COUNTER32(sctps_passiveestab);
+ SCTP_STAT_INCR_GAUGE32(sctps_currestab);
+
/* set up to notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_UP;
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
@@ -2443,6 +2443,12 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
cookie_offset = offset + sizeof(struct sctp_chunkhdr);
cookie_len = ntohs(cp->ch.chunk_length);
+ if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) +
+ sizeof(struct sctp_init_chunk) +
+ sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) {
+ /* cookie too small */
+ return (NULL);
+ }
if ((cookie->peerport != sh->src_port) ||
(cookie->myport != sh->dest_port) ||
(cookie->my_vtag != sh->v_tag)) {
@@ -2455,12 +2461,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
*/
return (NULL);
}
- if (cookie_len < sizeof(struct sctp_cookie_echo_chunk) +
- sizeof(struct sctp_init_chunk) +
- sizeof(struct sctp_init_ack_chunk) + SCTP_SIGNATURE_SIZE) {
- /* cookie too small */
- return (NULL);
- }
/*
* split off the signature into its own mbuf (since it should not be
* calculated in the sctp_hmac_m() call).
@@ -3619,7 +3619,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
struct sctp_stream_reset_response *respin)
{
uint16_t type;
- int lparm_len;
+ int lparam_len;
struct sctp_association *asoc = &stcb->asoc;
struct sctp_tmit_chunk *chk;
struct sctp_stream_reset_request *req_param;
@@ -3636,12 +3636,12 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
if (req_param != NULL) {
stcb->asoc.str_reset_seq_out++;
type = ntohs(req_param->ph.param_type);
- lparm_len = ntohs(req_param->ph.param_length);
+ lparam_len = ntohs(req_param->ph.param_length);
if (type == SCTP_STR_RESET_OUT_REQUEST) {
int no_clear = 0;
req_out_param = (struct sctp_stream_reset_out_request *)req_param;
- number_entries = (lparm_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t);
+ number_entries = (lparam_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t);
asoc->stream_reset_out_is_outstanding = 0;
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
@@ -3667,7 +3667,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
}
} else if (type == SCTP_STR_RESET_IN_REQUEST) {
req_in_param = (struct sctp_stream_reset_in_request *)req_param;
- number_entries = (lparm_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t);
+ number_entries = (lparam_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t);
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
@@ -5196,17 +5196,27 @@ process_control_chunks:
return (NULL);
}
}
- /*
+ /*-
* First are we accepting? We do this again here
* since it is possible that a previous endpoint WAS
* listening responded to a INIT-ACK and then
* closed. We opened and bound.. and are now no
* longer listening.
+ *
+ * XXXGL: notes on checking listen queue length.
+ * 1) SCTP_IS_LISTENING() doesn't necessarily mean
+ * SOLISTENING(), because a listening "UDP type"
+ * socket isn't listening in terms of the socket
+ * layer. It is a normal data flow socket, that
+ * can fork off new connections. Thus, we should
+ * look into sol_qlen only in case we are !UDP.
+ * 2) Checking sol_qlen in general requires locking
+ * the socket, and this code lacks that.
*/
-
if ((stcb == NULL) &&
(!SCTP_IS_LISTENING(inp) ||
- inp->sctp_socket->so_qlen >= inp->sctp_socket->so_qlimit)) {
+ (!(inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
+ inp->sctp_socket->sol_qlen >= inp->sctp_socket->sol_qlimit))) {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(SCTP_BASE_SYSCTL(sctp_abort_if_one_2_one_hits_limit))) {
op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
diff --git a/freebsd/sys/netinet/sctp_os_bsd.h b/freebsd/sys/netinet/sctp_os_bsd.h
index f2bea00e..194a03ed 100644
--- a/freebsd/sys/netinet/sctp_os_bsd.h
+++ b/freebsd/sys/netinet/sctp_os_bsd.h
@@ -392,8 +392,8 @@ typedef struct callout sctp_os_timer_t;
(sb).sb_mb = NULL; \
(sb).sb_mbcnt = 0;
-#define SCTP_SB_LIMIT_RCV(so) so->so_rcv.sb_hiwat
-#define SCTP_SB_LIMIT_SND(so) so->so_snd.sb_hiwat
+#define SCTP_SB_LIMIT_RCV(so) (SOLISTENING(so) ? so->sol_sbrcv_hiwat : so->so_rcv.sb_hiwat)
+#define SCTP_SB_LIMIT_SND(so) (SOLISTENING(so) ? so->sol_sbsnd_hiwat : so->so_snd.sb_hiwat)
/*
* routes, output, etc.
diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c
index 221d0570..5e2fbbc2 100644
--- a/freebsd/sys/netinet/sctp_output.c
+++ b/freebsd/sys/netinet/sctp_output.c
@@ -1942,7 +1942,7 @@ static struct mbuf *
sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
{
#if defined(INET) || defined(INET6)
- struct sctp_paramhdr *parmh;
+ struct sctp_paramhdr *paramh;
struct mbuf *mret;
uint16_t plen;
#endif
@@ -1964,7 +1964,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
#if defined(INET) || defined(INET6)
if (M_TRAILINGSPACE(m) >= plen) {
/* easy side we just drop it on the end */
- parmh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
+ paramh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m)));
mret = m;
} else {
/* Need more space */
@@ -1978,7 +1978,7 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
return (m);
}
mret = SCTP_BUF_NEXT(mret);
- parmh = mtod(mret, struct sctp_paramhdr *);
+ paramh = mtod(mret, struct sctp_paramhdr *);
}
/* now add the parameter */
switch (ifa->address.sa.sa_family) {
@@ -1989,9 +1989,9 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
struct sockaddr_in *sin;
sin = &ifa->address.sin;
- ipv4p = (struct sctp_ipv4addr_param *)parmh;
- parmh->param_type = htons(SCTP_IPV4_ADDRESS);
- parmh->param_length = htons(plen);
+ ipv4p = (struct sctp_ipv4addr_param *)paramh;
+ paramh->param_type = htons(SCTP_IPV4_ADDRESS);
+ paramh->param_length = htons(plen);
ipv4p->addr = sin->sin_addr.s_addr;
SCTP_BUF_LEN(mret) += plen;
break;
@@ -2004,9 +2004,9 @@ sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len)
struct sockaddr_in6 *sin6;
sin6 = &ifa->address.sin6;
- ipv6p = (struct sctp_ipv6addr_param *)parmh;
- parmh->param_type = htons(SCTP_IPV6_ADDRESS);
- parmh->param_length = htons(plen);
+ ipv6p = (struct sctp_ipv6addr_param *)paramh;
+ paramh->param_type = htons(SCTP_IPV6_ADDRESS);
+ paramh->param_length = htons(plen);
memcpy(ipv6p->addr, &sin6->sin6_addr,
sizeof(ipv6p->addr));
/* clear embedded scope in the address */
@@ -4406,7 +4406,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* we can try their selection but it may not be
* bound.
*/
- bzero(&lsa6_tmp, sizeof(lsa6_tmp));
+ memset(&lsa6_tmp, 0, sizeof(lsa6_tmp));
lsa6_tmp.sin6_family = AF_INET6;
lsa6_tmp.sin6_len = sizeof(lsa6_tmp);
lsa6 = &lsa6_tmp;
@@ -4491,7 +4491,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* XXX: sa6 may not have a valid sin6_scope_id in
* the non-SCOPEDROUTING case.
*/
- bzero(&lsa6_storage, sizeof(lsa6_storage));
+ memset(&lsa6_storage, 0, sizeof(lsa6_storage));
lsa6_storage.sin6_family = AF_INET6;
lsa6_storage.sin6_len = sizeof(lsa6_storage);
lsa6_storage.sin6_addr = lsa6->sin6_addr;
@@ -5143,7 +5143,10 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
s.param_length = htons(sizeof(s) + plen);
m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
err_at += sizeof(s);
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
+ if (plen > sizeof(tempbuf)) {
+ plen = sizeof(tempbuf);
+ }
+ phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
@@ -5211,7 +5214,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
if (plen > sizeof(tempbuf)) {
plen = sizeof(tempbuf);
}
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
+ phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
@@ -5392,10 +5395,12 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
{
struct sctp_ipv4addr_param *p4, p4_buf;
+ if (plen != sizeof(struct sctp_ipv4addr_param)) {
+ return (1);
+ }
phdr = sctp_get_next_param(in_initpkt, offset,
(struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf));
- if (plen != sizeof(struct sctp_ipv4addr_param) ||
- phdr == NULL) {
+ if (phdr == NULL) {
return (1);
}
if (asoc->scope.ipv4_addr_legal) {
@@ -5411,10 +5416,12 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
{
struct sctp_ipv6addr_param *p6, p6_buf;
+ if (plen != sizeof(struct sctp_ipv6addr_param)) {
+ return (1);
+ }
phdr = sctp_get_next_param(in_initpkt, offset,
(struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf));
- if (plen != sizeof(struct sctp_ipv6addr_param) ||
- phdr == NULL) {
+ if (phdr == NULL) {
return (1);
}
if (asoc->scope.ipv6_addr_legal) {
@@ -6245,11 +6252,7 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
} else {
ovh = SCTP_MIN_V4_OVERHEAD;
}
- if (stcb->asoc.idata_supported) {
- ovh += sizeof(struct sctp_idata_chunk);
- } else {
- ovh += sizeof(struct sctp_data_chunk);
- }
+ ovh += SCTP_DATA_CHUNK_OVERHEAD(stcb);
if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
siz = asoc->smallest_mtu - ovh;
else
@@ -6754,7 +6757,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
}
}
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ (stcb->asoc.stream_queue_cnt * SCTP_DATA_CHUNK_OVERHEAD(stcb)));
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
@@ -7454,11 +7457,7 @@ dont_do_it:
} else {
atomic_subtract_int(&sp->length, to_move);
}
- if (stcb->asoc.idata_supported == 0) {
- leading = sizeof(struct sctp_data_chunk);
- } else {
- leading = sizeof(struct sctp_idata_chunk);
- }
+ leading = SCTP_DATA_CHUNK_OVERHEAD(stcb);
if (M_LEADINGSPACE(chk->data) < leading) {
/* Not enough room for a chunk header, get some */
struct mbuf *m;
@@ -7500,11 +7499,7 @@ dont_do_it:
M_ALIGN(chk->data, 4);
}
}
- if (stcb->asoc.idata_supported == 0) {
- SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_data_chunk), M_NOWAIT);
- } else {
- SCTP_BUF_PREPEND(chk->data, sizeof(struct sctp_idata_chunk), M_NOWAIT);
- }
+ SCTP_BUF_PREPEND(chk->data, SCTP_DATA_CHUNK_OVERHEAD(stcb), M_NOWAIT);
if (chk->data == NULL) {
/* HELP, TSNH since we assured it would not above? */
#ifdef INVARIANTS
@@ -7517,13 +7512,8 @@ dont_do_it:
to_move = 0;
goto out_of;
}
- if (stcb->asoc.idata_supported == 0) {
- sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
- chk->book_size = chk->send_size = (uint16_t)(to_move + sizeof(struct sctp_data_chunk));
- } else {
- sctp_snd_sb_alloc(stcb, sizeof(struct sctp_idata_chunk));
- chk->book_size = chk->send_size = (uint16_t)(to_move + sizeof(struct sctp_idata_chunk));
- }
+ sctp_snd_sb_alloc(stcb, SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ chk->book_size = chk->send_size = (uint16_t)(to_move + SCTP_DATA_CHUNK_OVERHEAD(stcb));
chk->book_size_scale = 0;
chk->sent = SCTP_DATAGRAM_UNSENT;
@@ -7723,11 +7713,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
break;
}
/* Need an allowance for the data chunk header too */
- if (stcb->asoc.idata_supported == 0) {
- space_left -= sizeof(struct sctp_data_chunk);
- } else {
- space_left -= sizeof(struct sctp_idata_chunk);
- }
+ space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
/* must make even word boundary */
space_left &= 0xfffffffc;
@@ -7744,18 +7730,10 @@ sctp_fill_outqueue(struct sctp_tcb *stcb,
strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
total_moved += moved;
space_left -= moved;
- if (stcb->asoc.idata_supported == 0) {
- if (space_left >= sizeof(struct sctp_data_chunk)) {
- space_left -= sizeof(struct sctp_data_chunk);
- } else {
- space_left = 0;
- }
+ if (space_left >= SCTP_DATA_CHUNK_OVERHEAD(stcb)) {
+ space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb);
} else {
- if (space_left >= sizeof(struct sctp_idata_chunk)) {
- space_left -= sizeof(struct sctp_idata_chunk);
- } else {
- space_left = 0;
- }
+ space_left = 0;
}
space_left &= 0xfffffffc;
}
@@ -9002,7 +8980,7 @@ sctp_send_cookie_echo(struct mbuf *m,
*/
int at;
struct mbuf *cookie;
- struct sctp_paramhdr parm, *phdr;
+ struct sctp_paramhdr param, *phdr;
struct sctp_chunkhdr *hdr;
struct sctp_tmit_chunk *chk;
uint16_t ptype, plen;
@@ -9012,7 +8990,7 @@ sctp_send_cookie_echo(struct mbuf *m,
cookie = NULL;
at = offset + sizeof(struct sctp_init_chunk);
for (;;) {
- phdr = sctp_get_next_param(m, at, &parm, sizeof(parm));
+ phdr = sctp_get_next_param(m, at, &param, sizeof(param));
if (phdr == NULL) {
return (-3);
}
@@ -10204,8 +10182,7 @@ do_it_again:
* and we have data in flight we stop, except if we
* are handling a fragmented user message.
*/
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) &&
(stcb->asoc.total_flight > 0)) {
/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
@@ -12443,7 +12420,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
sp->sender_all_done = 0;
sp->some_taken = 0;
sp->put_last_out = 0;
- resv_in_first = sizeof(struct sctp_data_chunk);
+ resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb);
sp->data = sp->tail_mbuf = NULL;
if (sp->length == 0) {
*error = 0;
@@ -12860,12 +12837,19 @@ sctp_lower_sosend(struct socket *so,
}
/* would we block? */
if (non_blocking) {
+ uint32_t amount;
+
if (hold_tcblock == 0) {
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
- if ((SCTP_SB_LIMIT_SND(so) < (sndlen + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (user_marks_eor == 0) {
+ amount = sndlen;
+ } else {
+ amount = 1;
+ }
+ if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
(stcb->asoc.chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
if (sndlen > SCTP_SB_LIMIT_SND(so))
@@ -13033,7 +13017,7 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked;
}
/* Calculate the maximum we can send */
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
if (non_blocking) {
/* we already checked for non-blocking above. */
@@ -13090,7 +13074,7 @@ sctp_lower_sosend(struct socket *so,
((stcb->asoc.chunks_on_out_queue + stcb->asoc.stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
/* No room right now ! */
SOCKBUF_LOCK(&so->so_snd);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) ||
((stcb->asoc.stream_queue_cnt + stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "pre_block limit:%u <(inq:%d + %d) || (%d+%d > %d)\n",
@@ -13126,7 +13110,7 @@ sctp_lower_sosend(struct socket *so,
SOCKBUF_UNLOCK(&so->so_snd);
goto out_unlocked;
}
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
}
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
@@ -13219,8 +13203,9 @@ skip_preblock:
/* How much room do we have? */
struct mbuf *new_tail, *mm;
- if (SCTP_SB_LIMIT_SND(so) > stcb->asoc.total_output_queue_size)
- max_len = SCTP_SB_LIMIT_SND(so) - stcb->asoc.total_output_queue_size;
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
+ max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
max_len = 0;
@@ -13296,8 +13281,8 @@ skip_preblock:
hold_tcblock = 1;
}
sctp_prune_prsctp(stcb, asoc, srcv, sndlen);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk));
- if (SCTP_SB_LIMIT_SND(so) > stcb->asoc.total_output_queue_size)
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
max_len = 0;
@@ -13338,8 +13323,7 @@ skip_preblock:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
(stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
@@ -13413,7 +13397,8 @@ skip_preblock:
* size we KNOW we will get to sleep safely with the
* wakeup flag in place.
*/
- if (SCTP_SB_LIMIT_SND(so) <= (stcb->asoc.total_output_queue_size +
+ inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes +
min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK,
@@ -13610,8 +13595,7 @@ skip_out_eof:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
- (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
+ un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
(stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
@@ -13750,7 +13734,7 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end,
SCTP_BUF_RESV_UF(m_auth, SCTP_MIN_OVERHEAD);
/* fill in the AUTH chunk details */
auth = mtod(m_auth, struct sctp_auth_chunk *);
- bzero(auth, sizeof(*auth));
+ memset(auth, 0, sizeof(*auth));
auth->ch.chunk_type = SCTP_AUTHENTICATION;
auth->ch.chunk_flags = 0;
chunk_len = sizeof(*auth) +
diff --git a/freebsd/sys/netinet/sctp_output.h b/freebsd/sys/netinet/sctp_output.h
index cd90b7d7..32f968c1 100644
--- a/freebsd/sys/netinet/sctp_output.h
+++ b/freebsd/sys/netinet/sctp_output.h
@@ -135,6 +135,11 @@ void sctp_fix_ecn_echo(struct sctp_association *);
void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net);
+
+#define SCTP_DATA_CHUNK_OVERHEAD(stcb) ((stcb)->asoc.idata_supported ? \
+ sizeof(struct sctp_idata_chunk) : \
+ sizeof(struct sctp_data_chunk))
+
int
sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct thread *, int);
diff --git a/freebsd/sys/netinet/sctp_pcb.c b/freebsd/sys/netinet/sctp_pcb.c
index e32e63f4..1907991e 100644
--- a/freebsd/sys/netinet/sctp_pcb.c
+++ b/freebsd/sys/netinet/sctp_pcb.c
@@ -704,7 +704,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
return (NULL);
}
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = sctp_ifap;
wi->action = SCTP_ADD_IP_ADDRESS;
@@ -813,7 +813,7 @@ out_now:
return;
}
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = sctp_ifap;
wi->action = SCTP_DEL_IP_ADDRESS;
@@ -2048,7 +2048,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
struct sctphdr *sh, struct sctp_inpcb **inp_p, struct sctp_nets **netp,
struct sockaddr *dst)
{
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
#if defined(INET) || defined(INET6)
struct sctp_tcb *stcb;
uint16_t ptype;
@@ -2076,7 +2076,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
offset += sizeof(struct sctp_init_chunk);
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr != NULL) {
/* now we must see if we want the parameter */
#if defined(INET) || defined(INET6)
@@ -2090,10 +2090,10 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
if (ptype == SCTP_IPV4_ADDRESS &&
plen == sizeof(struct sctp_ipv4addr_param)) {
/* Get the rest of the address */
- struct sctp_ipv4addr_param ip4_parm, *p4;
+ struct sctp_ipv4addr_param ip4_param, *p4;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip4_parm, min(plen, sizeof(ip4_parm)));
+ (struct sctp_paramhdr *)&ip4_param, sizeof(ip4_param));
if (phdr == NULL) {
return (NULL);
}
@@ -2111,10 +2111,10 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
if (ptype == SCTP_IPV6_ADDRESS &&
plen == sizeof(struct sctp_ipv6addr_param)) {
/* Get the rest of the address */
- struct sctp_ipv6addr_param ip6_parm, *p6;
+ struct sctp_ipv6addr_param ip6_param, *p6;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip6_parm, min(plen, sizeof(ip6_parm)));
+ (struct sctp_paramhdr *)&ip6_param, sizeof(ip6_param));
if (phdr == NULL) {
return (NULL);
}
@@ -2129,8 +2129,8 @@ sctp_findassociation_special_addr(struct mbuf *m, int offset,
}
#endif
offset += SCTP_SIZE32(plen);
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
return (NULL);
}
@@ -2303,7 +2303,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
{
struct sctp_tcb *stcb;
union sctp_sockstore remote_store;
- struct sctp_paramhdr parm_buf, *phdr;
+ struct sctp_paramhdr param_buf, *phdr;
int ptype;
int zero_address = 0;
#ifdef INET
@@ -2315,7 +2315,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
memset(&remote_store, 0, sizeof(remote_store));
phdr = sctp_get_next_param(m, offset + sizeof(struct sctp_asconf_chunk),
- &parm_buf, sizeof(struct sctp_paramhdr));
+ &param_buf, sizeof(struct sctp_paramhdr));
if (phdr == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf lookup addr\n",
__func__);
@@ -2335,7 +2335,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
}
p6 = (struct sctp_ipv6addr_param *)sctp_get_next_param(m,
offset + sizeof(struct sctp_asconf_chunk),
- &p6_buf.ph, sizeof(*p6));
+ &p6_buf.ph, sizeof(p6_buf));
if (p6 == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v6 lookup addr\n",
__func__);
@@ -2362,7 +2362,7 @@ sctp_findassociation_ep_asconf(struct mbuf *m, int offset,
}
p4 = (struct sctp_ipv4addr_param *)sctp_get_next_param(m,
offset + sizeof(struct sctp_asconf_chunk),
- &p4_buf.ph, sizeof(*p4));
+ &p4_buf.ph, sizeof(p4_buf));
if (p4 == NULL) {
SCTPDBG(SCTP_DEBUG_INPUT3, "%s: failed to get asconf v4 lookup addr\n",
__func__);
@@ -2431,7 +2431,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
return (ENOBUFS);
}
/* zap it */
- bzero(inp, sizeof(*inp));
+ memset(inp, 0, sizeof(*inp));
/* bump generations */
/* setup socket pointers */
@@ -2717,7 +2717,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
continue;
}
SCTP_INCR_LADDR_COUNT();
- bzero(laddr, sizeof(*laddr));
+ memset(laddr, 0, sizeof(*laddr));
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
laddr->ifa = oladdr->ifa;
atomic_add_int(&laddr->ifa->refcount, 1);
@@ -2767,7 +2767,7 @@ sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
return (EINVAL);
}
SCTP_INCR_LADDR_COUNT();
- bzero(laddr, sizeof(*laddr));
+ memset(laddr, 0, sizeof(*laddr));
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
laddr->ifa = ifa;
laddr->action = act;
@@ -3770,7 +3770,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
/* Invalid address */
return (-1);
}
- /* zero out the bzero area */
+ /* zero out the zero area */
memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
/* assure len is set */
@@ -3853,7 +3853,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
return (-1);
}
SCTP_INCR_RADDR_COUNT();
- bzero(net, sizeof(struct sctp_nets));
+ memset(net, 0, sizeof(struct sctp_nets));
(void)SCTP_GETTIME_TIMEVAL(&net->start_time);
memcpy(&net->ro._l_addr, newaddr, newaddr->sa_len);
switch (newaddr->sa_family) {
@@ -4289,7 +4289,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
}
SCTP_INCR_ASOC_COUNT();
- bzero(stcb, sizeof(*stcb));
+ memset(stcb, 0, sizeof(*stcb));
asoc = &stcb->asoc;
asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb);
@@ -4603,21 +4603,21 @@ void
sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh)
{
struct sctp_tmit_chunk *chk, *nchk;
- struct sctp_queued_to_read *ctl, *nctl;
+ struct sctp_queued_to_read *control, *ncontrol;
- TAILQ_FOREACH_SAFE(ctl, rh, next_instrm, nctl) {
- TAILQ_REMOVE(rh, ctl, next_instrm);
- ctl->on_strm_q = 0;
- if (ctl->on_read_q == 0) {
- sctp_free_remote_addr(ctl->whoFrom);
- if (ctl->data) {
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
+ TAILQ_FOREACH_SAFE(control, rh, next_instrm, ncontrol) {
+ TAILQ_REMOVE(rh, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->on_read_q == 0) {
+ sctp_free_remote_addr(control->whoFrom);
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
}
}
/* Reassembly free? */
- TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
- TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
@@ -4633,8 +4633,8 @@ sctp_clean_up_stream(struct sctp_tcb *stcb, struct sctp_readhead *rh)
* We don't free the address here since all the net's were
* freed above.
*/
- if (ctl->on_read_q == 0) {
- sctp_free_a_readq(stcb, ctl);
+ if (control->on_read_q == 0) {
+ sctp_free_a_readq(stcb, control);
}
}
}
@@ -4860,7 +4860,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED;
inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED;
if (so) {
- SOCK_LOCK(so);
+ SOCKBUF_LOCK(&so->so_rcv);
if (so->so_rcv.sb_cc == 0) {
so->so_state &= ~(SS_ISCONNECTING |
SS_ISDISCONNECTING |
@@ -5735,7 +5735,7 @@ sctp_pcb_init()
SCTP_BASE_VAR(sctp_pcb_initialized) = 1;
#if defined(SCTP_LOCAL_TRACE_BUF)
- bzero(&SCTP_BASE_SYSCTL(sctp_log), sizeof(struct sctp_log));
+ memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
#endif
#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
SCTP_MALLOC(SCTP_BASE_STATS, struct sctpstat *,
@@ -5744,11 +5744,11 @@ sctp_pcb_init()
#endif
(void)SCTP_GETTIME_TIMEVAL(&tv);
#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
- bzero(SCTP_BASE_STATS, (sizeof(struct sctpstat) * (mp_maxid + 1)));
+ memset(SCTP_BASE_STATS, 0, sizeof(struct sctpstat) * (mp_maxid + 1));
SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_sec = (uint32_t)tv.tv_sec;
SCTP_BASE_STATS[PCPU_GET(cpuid)].sctps_discontinuitytime.tv_usec = (uint32_t)tv.tv_usec;
#else
- bzero(&SCTP_BASE_STATS, sizeof(struct sctpstat));
+ memset(&SCTP_BASE_STATS, 0, sizeof(struct sctpstat));
SCTP_BASE_STAT(sctps_discontinuitytime).tv_sec = (uint32_t)tv.tv_sec;
SCTP_BASE_STAT(sctps_discontinuitytime).tv_usec = (uint32_t)tv.tv_usec;
#endif
@@ -6030,7 +6030,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
*/
struct sctp_inpcb *inp;
struct sctp_nets *net, *nnet, *net_tmp;
- struct sctp_paramhdr *phdr, parm_buf;
+ struct sctp_paramhdr *phdr, param_buf;
struct sctp_tcb *stcb_tmp;
uint16_t ptype, plen;
struct sockaddr *sa;
@@ -6140,7 +6140,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-4);
}
/* now we must go through each of the params. */
- phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf, sizeof(param_buf));
while (phdr) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
@@ -6378,7 +6378,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&lstore,
- min(plen, sizeof(lstore)));
+ plen);
if (phdr == NULL) {
return (-24);
}
@@ -6431,8 +6431,11 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
uint8_t local_store[SCTP_PARAM_BUFFER_SIZE];
int num_ent, i;
+ if (plen > sizeof(local_store)) {
+ return (-35);
+ }
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, min(sizeof(local_store), plen));
+ (struct sctp_paramhdr *)&local_store, plen);
if (phdr == NULL) {
return (-25);
}
@@ -6479,7 +6482,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)random_store,
- min(sizeof(random_store), plen));
+ plen);
if (phdr == NULL)
return (-26);
p_random = (struct sctp_auth_random *)phdr;
@@ -6502,7 +6505,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)hmacs_store,
- min(plen, sizeof(hmacs_store)));
+ plen);
if (phdr == NULL)
return (-28);
hmacs = (struct sctp_auth_hmac_algo *)phdr;
@@ -6533,7 +6536,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
- min(plen, sizeof(chunks_store)));
+ plen);
if (phdr == NULL)
return (-30);
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -6581,8 +6584,8 @@ next_param:
if (offset >= limit) {
break;
}
- phdr = sctp_get_next_param(m, offset, &parm_buf,
- sizeof(parm_buf));
+ phdr = sctp_get_next_param(m, offset, &param_buf,
+ sizeof(param_buf));
}
/* Now check to see if we need to purge any addresses */
TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
@@ -6657,17 +6660,17 @@ next_param:
/* copy in the RANDOM */
if (p_random != NULL) {
keylen = sizeof(*p_random) + random_len;
- bcopy(p_random, new_key->key, keylen);
+ memcpy(new_key->key, p_random, keylen);
}
/* append in the AUTH chunks */
if (chunks != NULL) {
- bcopy(chunks, new_key->key + keylen,
+ memcpy(new_key->key + keylen, chunks,
sizeof(*chunks) + num_chunks);
keylen += sizeof(*chunks) + num_chunks;
}
/* append in the HMACs */
if (hmacs != NULL) {
- bcopy(hmacs, new_key->key + keylen,
+ memcpy(new_key->key + keylen, hmacs,
sizeof(*hmacs) + hmacs_len);
}
} else {
@@ -6802,7 +6805,7 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
struct sctp_association *asoc;
struct sctp_tmit_chunk *chk, *nchk;
uint32_t cumulative_tsn_p1;
- struct sctp_queued_to_read *ctl, *nctl;
+ struct sctp_queued_to_read *control, *ncontrol;
int cnt, strmat;
uint32_t gap, i;
int fnd = 0;
@@ -6819,88 +6822,124 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
cnt = 0;
/* Ok that was fun, now we will drain all the inbound streams? */
for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
- TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next_instrm, nctl) {
+ TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].inqueue, next_instrm, ncontrol) {
#ifdef INVARIANTS
- if (ctl->on_strm_q != SCTP_ON_ORDERED) {
+ if (control->on_strm_q != SCTP_ON_ORDERED) {
panic("Huh control: %p on_q: %d -- not ordered?",
- ctl, ctl->on_strm_q);
+ control, control->on_strm_q);
}
#endif
- if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
- SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn);
- asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
+ SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
+ KASSERT(control->length > 0, ("control has zero length"));
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- if (ctl->on_read_q) {
- TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
- ctl->on_read_q = 0;
+ if (control->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
+ control->on_read_q = 0;
}
- TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next_instrm);
- ctl->on_strm_q = 0;
- if (ctl->data) {
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
+ TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
}
- sctp_free_remote_addr(ctl->whoFrom);
+ sctp_free_remote_addr(control->whoFrom);
/* Now its reasm? */
- TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
- asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
+ KASSERT(chk->send_size > 0, ("chunk has zero length"));
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
+ asoc->size_on_reasm_queue -= chk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
- sctp_free_a_readq(stcb, ctl);
+ sctp_free_a_readq(stcb, control);
}
}
- TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, next_instrm, nctl) {
+ TAILQ_FOREACH_SAFE(control, &asoc->strmin[strmat].uno_inqueue, next_instrm, ncontrol) {
#ifdef INVARIANTS
- if (ctl->on_strm_q != SCTP_ON_UNORDERED) {
+ if (control->on_strm_q != SCTP_ON_UNORDERED) {
panic("Huh control: %p on_q: %d -- not unordered?",
- ctl, ctl->on_strm_q);
+ control, control->on_strm_q);
}
#endif
- if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
+ if (SCTP_TSN_GT(control->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
- SCTP_CALC_TSN_TO_GAP(gap, ctl->sinfo_tsn, asoc->mapping_array_base_tsn);
- asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
+ SCTP_CALC_TSN_TO_GAP(gap, control->sinfo_tsn, asoc->mapping_array_base_tsn);
+ KASSERT(control->length > 0, ("control has zero length"));
+ if (asoc->size_on_all_streams >= control->length) {
+ asoc->size_on_all_streams -= control->length;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_all_streams = %u smaller than control length %u", asoc->size_on_all_streams, control->length);
+#else
+ asoc->size_on_all_streams = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- if (ctl->on_read_q) {
- TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
- ctl->on_read_q = 0;
+ if (control->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, control, next);
+ control->on_read_q = 0;
}
- TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, ctl, next_instrm);
- ctl->on_strm_q = 0;
- if (ctl->data) {
- sctp_m_freem(ctl->data);
- ctl->data = NULL;
+ TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
}
- sctp_free_remote_addr(ctl->whoFrom);
+ sctp_free_remote_addr(control->whoFrom);
/* Now its reasm? */
- TAILQ_FOREACH_SAFE(chk, &ctl->reasm, sctp_next, nchk) {
+ TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
cnt++;
SCTP_CALC_TSN_TO_GAP(gap, chk->rec.data.tsn, asoc->mapping_array_base_tsn);
- asoc->size_on_reasm_queue = sctp_sbspace_sub(asoc->size_on_reasm_queue, chk->send_size);
+ KASSERT(chk->send_size > 0, ("chunk has zero length"));
+ if (asoc->size_on_reasm_queue >= chk->send_size) {
+ asoc->size_on_reasm_queue -= chk->send_size;
+ } else {
+#ifdef INVARIANTS
+ panic("size_on_reasm_queue = %u smaller than chunk length %u", asoc->size_on_reasm_queue, chk->send_size);
+#else
+ asoc->size_on_reasm_queue = 0;
+#endif
+ }
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
- TAILQ_REMOVE(&ctl->reasm, chk, sctp_next);
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
- sctp_free_a_readq(stcb, ctl);
+ sctp_free_a_readq(stcb, control);
}
}
}
diff --git a/freebsd/sys/netinet/sctp_sysctl.c b/freebsd/sys/netinet/sctp_sysctl.c
index db150112..a2364431 100644
--- a/freebsd/sys/netinet/sctp_sysctl.c
+++ b/freebsd/sys/netinet/sctp_sysctl.c
@@ -417,12 +417,12 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS)
xinpcb.qlen = 0;
xinpcb.maxqlen = 0;
} else {
- xinpcb.qlen = so->so_qlen;
- xinpcb.qlen_old = so->so_qlen > USHRT_MAX ?
- USHRT_MAX : (uint16_t)so->so_qlen;
- xinpcb.maxqlen = so->so_qlimit;
- xinpcb.maxqlen_old = so->so_qlimit > USHRT_MAX ?
- USHRT_MAX : (uint16_t)so->so_qlimit;
+ xinpcb.qlen = so->sol_qlen;
+ xinpcb.qlen_old = so->sol_qlen > USHRT_MAX ?
+ USHRT_MAX : (uint16_t)so->sol_qlen;
+ xinpcb.maxqlen = so->sol_qlimit;
+ xinpcb.maxqlen_old = so->sol_qlimit > USHRT_MAX ?
+ USHRT_MAX : (uint16_t)so->sol_qlimit;
}
SCTP_INP_INCR_REF(inp);
SCTP_INP_RUNLOCK(inp);
diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c
index b65f74d1..fa136d4e 100644
--- a/freebsd/sys/netinet/sctp_usrreq.c
+++ b/freebsd/sys/netinet/sctp_usrreq.c
@@ -87,7 +87,7 @@ sctp_init(void)
#if defined(SCTP_PACKET_LOGGING)
SCTP_BASE_VAR(packet_log_writers) = 0;
SCTP_BASE_VAR(packet_log_end) = 0;
- bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
+ memset(&SCTP_BASE_VAR(packet_log_buffer), 0, SCTP_PACKET_LOG_SIZE);
#endif
}
@@ -7140,19 +7140,16 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
}
}
SCTP_INP_WLOCK(inp);
- SOCK_LOCK(so);
- /* It appears for 7.0 and on, we must always call this. */
- solisten_proto(so, backlog);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- /* remove the ACCEPTCONN flag for one-to-many sockets */
- so->so_options &= ~SO_ACCEPTCONN;
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) {
+ SOCK_LOCK(so);
+ solisten_proto(so, backlog);
+ SOCK_UNLOCK(so);
}
if (backlog > 0) {
inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
} else {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING;
}
- SOCK_UNLOCK(so);
SCTP_INP_WUNLOCK(inp);
return (error);
}
diff --git a/freebsd/sys/netinet/sctputil.c b/freebsd/sys/netinet/sctputil.c
index 4c6ba598..75c989d3 100644
--- a/freebsd/sys/netinet/sctputil.c
+++ b/freebsd/sys/netinet/sctputil.c
@@ -2595,7 +2595,7 @@ sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr)
/* else, it spans more than one mbuf, so save a temp copy... */
while ((m != NULL) && (len > 0)) {
count = min(SCTP_BUF_LEN(m) - off, len);
- bcopy(mtod(m, caddr_t)+off, ptr, count);
+ memcpy(ptr, mtod(m, caddr_t)+off, count);
len -= count;
ptr += count;
off = 0;
@@ -2756,9 +2756,9 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb,
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD,
@@ -2794,6 +2794,7 @@ set_error:
stcb->sctp_socket->so_error = ECONNABORTED;
}
}
+ SOCK_UNLOCK(stcb->sctp_socket);
}
/* Wake ANY sleepers */
#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
@@ -2813,7 +2814,7 @@ set_error:
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) {
- socantrcvmore_locked(stcb->sctp_socket);
+ socantrcvmore(stcb->sctp_socket);
}
sorwakeup(stcb->sctp_socket);
sowwakeup(stcb->sctp_socket);
@@ -3040,7 +3041,10 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error,
sctp_m_freem(m_notify);
return;
}
+ control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
@@ -3140,7 +3144,10 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
+ control->length = SCTP_BUF_LEN(m_notify);
control->spec_flags = M_NOTIFICATION;
+ /* not that we need this */
+ control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked);
@@ -3241,12 +3248,10 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->held_length = 0;
- control->length = 0;
sb = &stcb->sctp_socket->so_rcv;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
@@ -3255,7 +3260,6 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
}
- atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify));
control->end_added = 1;
if (stcb->asoc.control_pdapi)
TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next);
@@ -3350,8 +3354,8 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3457,8 +3461,8 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3507,8 +3511,8 @@ sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3572,8 +3576,8 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
sctp_m_freem(m_notify);
return;
}
- control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
@@ -3628,9 +3632,9 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro
m_notify);
if (control != NULL) {
control->length = SCTP_BUF_LEN(m_notify);
+ control->spec_flags = M_NOTIFICATION;
/* not that we need this */
control->tail_mbuf = m_notify;
- control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1,
@@ -6165,7 +6169,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
}
/* Now incr the count and int wi structure */
SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
+ memset(wi, 0, sizeof(*wi));
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
wi->ifa = ifa;
wi->action = SCTP_SET_PRIM_ADDR;
@@ -7241,8 +7245,6 @@ sctp_over_udp_start(void)
return (0);
}
-#if defined(INET6) || defined(INET)
-
/*
* sctp_min_mtu ()returns the minimum of all non-zero arguments.
* If all arguments are zero, zero is returned.
@@ -7326,4 +7328,3 @@ sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum)
}
return ((uint32_t)tcp_hc_getmtu(&inc));
}
-#endif
diff --git a/freebsd/sys/netinet/sctputil.h b/freebsd/sys/netinet/sctputil.h
index 50118b7a..97b33654 100644
--- a/freebsd/sys/netinet/sctputil.h
+++ b/freebsd/sys/netinet/sctputil.h
@@ -388,10 +388,8 @@ sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *,
void sctp_audit_log(uint8_t, uint8_t);
#endif
-#if defined(INET6) || defined(INET)
uint32_t sctp_min_mtu(uint32_t, uint32_t, uint32_t);
void sctp_hc_set_mtu(union sctp_sockstore *, uint16_t, uint32_t);
uint32_t sctp_hc_get_mtu(union sctp_sockstore *, uint16_t);
-#endif
#endif /* _KERNEL */
#endif
diff --git a/freebsd/sys/netinet/tcp_input.c b/freebsd/sys/netinet/tcp_input.c
index d7091928..2195a778 100644
--- a/freebsd/sys/netinet/tcp_input.c
+++ b/freebsd/sys/netinet/tcp_input.c
@@ -437,16 +437,9 @@ cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type)
tp->t_dupacks = 0;
tp->t_bytes_acked = 0;
EXIT_RECOVERY(tp->t_flags);
- if (CC_ALGO(tp)->cong_signal == NULL) {
- /*
- * RFC5681 Section 3.1
- * ssthresh = max (FlightSize / 2, 2*SMSS) eq (4)
- */
- tp->snd_ssthresh =
- max((tp->snd_max - tp->snd_una) / 2 / maxseg, 2)
- * maxseg;
- tp->snd_cwnd = maxseg;
- }
+ tp->snd_ssthresh = max(2, min(tp->snd_wnd, tp->snd_cwnd) / 2 /
+ maxseg) * maxseg;
+ tp->snd_cwnd = maxseg;
break;
case CC_RTO_ERR:
TCPSTAT_INC(tcps_sndrexmitbad);
@@ -2013,8 +2006,10 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
/*
* If the state is SYN_SENT:
- * if seg contains a RST, then drop the connection.
- * if seg does not contain SYN, then drop it.
+ * if seg contains a RST with valid ACK (SEQ.ACK has already
+ * been verified), then drop the connection.
+ * if seg contains a RST without an ACK, drop the seg.
+ * if seg does not contain SYN, then drop the seg.
* Otherwise this is an acceptable SYN segment
* initialize tp->rcv_nxt and tp->irs
* if seg contains ack then advance tp->snd_una
@@ -2613,15 +2608,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (awnd < tp->snd_ssthresh) {
tp->snd_cwnd += maxseg;
- /*
- * RFC5681 Section 3.2 talks about cwnd
- * inflation on additional dupacks and
- * deflation on recovering from loss.
- *
- * We keep cwnd into check so that
- * we don't have to 'deflate' it when we
- * get out of recovery.
- */
if (tp->snd_cwnd > tp->snd_ssthresh)
tp->snd_cwnd = tp->snd_ssthresh;
}
@@ -2661,22 +2647,19 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
TCPSTAT_INC(
tcps_sack_recovery_episode);
tp->sack_newdata = tp->snd_nxt;
- if (CC_ALGO(tp)->cong_signal == NULL)
- tp->snd_cwnd = maxseg;
+ tp->snd_cwnd = maxseg;
(void) tp->t_fb->tfb_tcp_output(tp);
goto drop;
}
tp->snd_nxt = th->th_ack;
- if (CC_ALGO(tp)->cong_signal == NULL)
- tp->snd_cwnd = maxseg;
+ tp->snd_cwnd = maxseg;
(void) tp->t_fb->tfb_tcp_output(tp);
KASSERT(tp->snd_limited <= 2,
("%s: tp->snd_limited too big",
__func__));
- if (CC_ALGO(tp)->cong_signal == NULL)
- tp->snd_cwnd = tp->snd_ssthresh +
- maxseg *
- (tp->t_dupacks - tp->snd_limited);
+ tp->snd_cwnd = tp->snd_ssthresh +
+ maxseg *
+ (tp->t_dupacks - tp->snd_limited);
if (SEQ_GT(onxt, tp->snd_nxt))
tp->snd_nxt = onxt;
goto drop;
diff --git a/freebsd/sys/netinet/tcp_output.c b/freebsd/sys/netinet/tcp_output.c
index d2606fb6..30ec34de 100644
--- a/freebsd/sys/netinet/tcp_output.c
+++ b/freebsd/sys/netinet/tcp_output.c
@@ -132,6 +132,12 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, sendbuf_max, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(tcp_autosndbuf_max), 0,
"Max size of automatic send buffer");
+VNET_DEFINE(int, tcp_sendbuf_auto_lowat) = 0;
+#define V_tcp_sendbuf_auto_lowat VNET(tcp_sendbuf_auto_lowat)
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, sendbuf_auto_lowat, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(tcp_sendbuf_auto_lowat), 0,
+ "Modify threshold for auto send buffer growth to account for SO_SNDLOWAT");
+
/*
* Make sure that either retransmit or persist timer is set for SYN, FIN and
* non-ACK.
@@ -382,7 +388,7 @@ after_sack_rexmit:
*/
if (sack_rxmit == 0) {
if (sack_bytes_rxmt == 0)
- len = ((int32_t)ulmin(sbavail(&so->so_snd), sendwin) -
+ len = ((int32_t)min(sbavail(&so->so_snd), sendwin) -
off);
else {
int32_t cwin;
@@ -523,8 +529,12 @@ after_sack_rexmit:
* XXXGL: should there be used sbused() or sbavail()?
*/
if (V_tcp_do_autosndbuf && so->so_snd.sb_flags & SB_AUTOSIZE) {
- if ((tp->snd_wnd / 4 * 5) >= so->so_snd.sb_hiwat &&
- sbused(&so->so_snd) >= (so->so_snd.sb_hiwat / 8 * 7) &&
+ int autosndbuf_mod = 0;
+ if (V_tcp_sendbuf_auto_lowat)
+ autosndbuf_mod = so->so_snd.sb_lowat;
+
+ if ((tp->snd_wnd / 4 * 5) >= so->so_snd.sb_hiwat - autosndbuf_mod &&
+ sbused(&so->so_snd) >= (so->so_snd.sb_hiwat / 8 * 7) - autosndbuf_mod &&
sbused(&so->so_snd) < V_tcp_autosndbuf_max &&
sendwin >= (sbused(&so->so_snd) -
(tp->snd_nxt - tp->snd_una))) {
diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c
index 30464e1b..dff41275 100644
--- a/freebsd/sys/netinet/tcp_subr.c
+++ b/freebsd/sys/netinet/tcp_subr.c
@@ -281,7 +281,7 @@ find_tcp_functions_locked(struct tcp_function_set *fs)
struct tcp_function_block *blk=NULL;
TAILQ_FOREACH(f, &t_functions, tf_next) {
- if (strcmp(f->tf_fb->tfb_tcp_block_name, fs->function_set_name) == 0) {
+ if (strcmp(f->tf_name, fs->function_set_name) == 0) {
blk = f->tf_fb;
break;
}
@@ -382,6 +382,7 @@ sysctl_net_inet_list_available(SYSCTL_HANDLER_ARGS)
struct tcp_function *f;
char *buffer, *cp;
size_t bufsz, outsz;
+ bool alias;
cnt = 0;
rw_rlock(&tcp_function_lock);
@@ -390,22 +391,25 @@ sysctl_net_inet_list_available(SYSCTL_HANDLER_ARGS)
}
rw_runlock(&tcp_function_lock);
- bufsz = (cnt+2) * (TCP_FUNCTION_NAME_LEN_MAX + 12) + 1;
+ bufsz = (cnt+2) * ((TCP_FUNCTION_NAME_LEN_MAX * 2) + 13) + 1;
buffer = malloc(bufsz, M_TEMP, M_WAITOK);
error = 0;
cp = buffer;
- linesz = snprintf(cp, bufsz, "\n%-32s%c %s\n", "Stack", 'D', "PCB count");
+ linesz = snprintf(cp, bufsz, "\n%-32s%c %-32s %s\n", "Stack", 'D',
+ "Alias", "PCB count");
cp += linesz;
bufsz -= linesz;
outsz = linesz;
rw_rlock(&tcp_function_lock);
TAILQ_FOREACH(f, &t_functions, tf_next) {
- linesz = snprintf(cp, bufsz, "%-32s%c %u\n",
+ alias = (f->tf_name != f->tf_fb->tfb_tcp_block_name);
+ linesz = snprintf(cp, bufsz, "%-32s%c %-32s %u\n",
f->tf_fb->tfb_tcp_block_name,
(f->tf_fb == tcp_func_set_ptr) ? '*' : ' ',
+ alias ? f->tf_name : "-",
f->tf_fb->tfb_refcnt);
if (linesz >= bufsz) {
error = EOVERFLOW;
@@ -506,12 +510,31 @@ maketcp_hashsize(int size)
return (hashsize);
}
+/*
+ * Register a TCP function block with the name provided in the names
+ * array. (Note that this function does NOT automatically register
+ * blk->tfb_tcp_block_name as a stack name. Therefore, you should
+ * explicitly include blk->tfb_tcp_block_name in the list of names if
+ * you wish to register the stack with that name.)
+ *
+ * Either all name registrations will succeed or all will fail. If
+ * a name registration fails, the function will update the num_names
+ * argument to point to the array index of the name that encountered
+ * the failure.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
int
-register_tcp_functions(struct tcp_function_block *blk, int wait)
+register_tcp_functions_as_names(struct tcp_function_block *blk, int wait,
+ const char *names[], int *num_names)
{
- struct tcp_function_block *lblk;
struct tcp_function *n;
struct tcp_function_set fs;
+ int error, i;
+
+ KASSERT(names != NULL && *num_names > 0,
+ ("%s: Called with 0-length name list", __func__));
+ KASSERT(names != NULL, ("%s: Called with NULL name list", __func__));
if (t_functions_inited == 0) {
init_tcp_functions();
@@ -524,6 +547,7 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
* These functions are required and you
* need a name.
*/
+ *num_names = 0;
return (EINVAL);
}
if (blk->tfb_tcp_timer_stop_all ||
@@ -538,34 +562,99 @@ register_tcp_functions(struct tcp_function_block *blk, int wait)
(blk->tfb_tcp_timer_activate == NULL) ||
(blk->tfb_tcp_timer_active == NULL) ||
(blk->tfb_tcp_timer_stop == NULL)) {
- return (EINVAL);
+ *num_names = 0;
+ return (EINVAL);
}
- }
- n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait);
- if (n == NULL) {
- return (ENOMEM);
- }
- n->tf_fb = blk;
- strcpy(fs.function_set_name, blk->tfb_tcp_block_name);
- rw_wlock(&tcp_function_lock);
- lblk = find_tcp_functions_locked(&fs);
- if (lblk) {
- /* Duplicate name space not allowed */
- rw_wunlock(&tcp_function_lock);
- free(n, M_TCPFUNCTIONS);
- return (EALREADY);
}
+
refcount_init(&blk->tfb_refcnt, 0);
blk->tfb_flags = 0;
- TAILQ_INSERT_TAIL(&t_functions, n, tf_next);
- rw_wunlock(&tcp_function_lock);
+ for (i = 0; i < *num_names; i++) {
+ n = malloc(sizeof(struct tcp_function), M_TCPFUNCTIONS, wait);
+ if (n == NULL) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+ n->tf_fb = blk;
+
+ (void)strncpy(fs.function_set_name, names[i],
+ TCP_FUNCTION_NAME_LEN_MAX);
+ fs.function_set_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0';
+ rw_wlock(&tcp_function_lock);
+ if (find_tcp_functions_locked(&fs) != NULL) {
+ /* Duplicate name space not allowed */
+ rw_wunlock(&tcp_function_lock);
+ free(n, M_TCPFUNCTIONS);
+ error = EALREADY;
+ goto cleanup;
+ }
+ (void)strncpy(n->tf_name, names[i], TCP_FUNCTION_NAME_LEN_MAX);
+ n->tf_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0';
+ TAILQ_INSERT_TAIL(&t_functions, n, tf_next);
+ rw_wunlock(&tcp_function_lock);
+ }
return(0);
-}
+
+cleanup:
+ /*
+ * Deregister the names we just added. Because registration failed
+ * for names[i], we don't need to deregister that name.
+ */
+ *num_names = i;
+ rw_wlock(&tcp_function_lock);
+ while (--i >= 0) {
+ TAILQ_FOREACH(n, &t_functions, tf_next) {
+ if (!strncmp(n->tf_name, names[i],
+ TCP_FUNCTION_NAME_LEN_MAX)) {
+ TAILQ_REMOVE(&t_functions, n, tf_next);
+ n->tf_fb = NULL;
+ free(n, M_TCPFUNCTIONS);
+ break;
+ }
+ }
+ }
+ rw_wunlock(&tcp_function_lock);
+ return (error);
+}
+
+/*
+ * Register a TCP function block using the name provided in the name
+ * argument.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
+int
+register_tcp_functions_as_name(struct tcp_function_block *blk, const char *name,
+ int wait)
+{
+ const char *name_list[1];
+ int num_names, rv;
+
+ num_names = 1;
+ if (name != NULL)
+ name_list[0] = name;
+ else
+ name_list[0] = blk->tfb_tcp_block_name;
+ rv = register_tcp_functions_as_names(blk, wait, name_list, &num_names);
+ return (rv);
+}
+
+/*
+ * Register a TCP function block using the name defined in
+ * blk->tfb_tcp_block_name.
+ *
+ * Returns 0 on success, or an error code on failure.
+ */
+int
+register_tcp_functions(struct tcp_function_block *blk, int wait)
+{
+
+ return (register_tcp_functions_as_name(blk, NULL, wait));
+}
int
deregister_tcp_functions(struct tcp_function_block *blk)
{
- struct tcp_function_block *lblk;
struct tcp_function *f;
int error=ENOENT;
@@ -585,8 +674,7 @@ deregister_tcp_functions(struct tcp_function_block *blk)
rw_wunlock(&tcp_function_lock);
return (EBUSY);
}
- lblk = find_tcp_fb_locked(blk, &f);
- if (lblk) {
+ while (find_tcp_fb_locked(blk, &f) != NULL) {
/* Found */
TAILQ_REMOVE(&t_functions, f, tf_next);
f->tf_fb = NULL;
@@ -1582,7 +1670,6 @@ tcp_close(struct tcpcb *tp)
("tcp_close: !SS_PROTOREF"));
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
sofree(so);
@@ -1969,16 +2056,16 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ icmp_tcp_seq = th->th_seq;
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -1986,7 +2073,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
* in the route to the suggested new
* value (if given) and then notify.
*/
- mtu = ntohs(icp->icmp_nextmtu);
+ mtu = ntohs(icp->icmp_nextmtu);
/*
* If no alternative MTU was
* proposed, try the next smaller
@@ -2017,16 +2104,17 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
inetctlerrmap[cmd]);
}
}
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fport = th->th_dport;
inc.inc_lport = th->th_sport;
inc.inc_faddr = faddr;
inc.inc_laddr = ip->ip_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET */
@@ -2036,7 +2124,6 @@ void
tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
{
struct in6_addr *dst;
- struct tcphdr *th;
struct inpcb *(*notify)(struct inpcb *, int) = tcp_notify;
struct ip6_hdr *ip6;
struct mbuf *m;
@@ -2046,11 +2133,14 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
struct ip6ctlparam *ip6cp = NULL;
const struct sockaddr_in6 *sa6_src = NULL;
struct in_conninfo inc;
+ struct tcp_ports {
+ uint16_t th_sport;
+ uint16_t th_dport;
+ } t_ports;
tcp_seq icmp_tcp_seq;
unsigned int mtu;
unsigned int off;
-
if (sa->sa_family != AF_INET6 ||
sa->sa_len != sizeof(struct sockaddr_in6))
return;
@@ -2099,27 +2189,31 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
/* Check if we can safely get the ports from the tcp hdr */
if (m == NULL ||
(m->m_pkthdr.len <
- (int32_t) (off + offsetof(struct tcphdr, th_seq)))) {
+ (int32_t) (off + sizeof(struct tcp_ports)))) {
return;
}
-
- th = (struct tcphdr *) mtodo(ip6cp->ip6c_m, ip6cp->ip6c_off);
+ bzero(&t_ports, sizeof(struct tcp_ports));
+ m_copydata(m, off, sizeof(struct tcp_ports), (caddr_t)&t_ports);
INP_INFO_RLOCK(&V_tcbinfo);
- inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, th->th_dport,
- &ip6->ip6_src, th->th_sport, INPLOOKUP_WLOCKPCB, NULL);
+ inp = in6_pcblookup(&V_tcbinfo, &ip6->ip6_dst, t_ports.th_dport,
+ &ip6->ip6_src, t_ports.th_sport, INPLOOKUP_WLOCKPCB, NULL);
if (inp != NULL && PRC_IS_REDIRECT(cmd)) {
/* signal EHOSTDOWN, as it flushes the cached route */
inp = (*notify)(inp, EHOSTDOWN);
- if (inp != NULL)
- INP_WUNLOCK(inp);
- } else if (inp != NULL) {
+ goto out;
+ }
+ off += sizeof(struct tcp_ports);
+ if (m->m_pkthdr.len < (int32_t) (off + sizeof(tcp_seq))) {
+ goto out;
+ }
+ m_copydata(m, off, sizeof(tcp_seq), (caddr_t)&icmp_tcp_seq);
+ if (inp != NULL) {
if (!(inp->inp_flags & INP_TIMEWAIT) &&
!(inp->inp_flags & INP_DROPPED) &&
!(inp->inp_socket == NULL)) {
- icmp_tcp_seq = ntohl(th->th_seq);
tp = intotcpcb(inp);
- if (SEQ_GEQ(icmp_tcp_seq, tp->snd_una) &&
- SEQ_LT(icmp_tcp_seq, tp->snd_max)) {
+ if (SEQ_GEQ(ntohl(icmp_tcp_seq), tp->snd_una) &&
+ SEQ_LT(ntohl(icmp_tcp_seq), tp->snd_max)) {
if (cmd == PRC_MSGSIZE) {
/*
* MTU discovery:
@@ -2136,22 +2230,20 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
*/
if (mtu < IPV6_MMTU)
mtu = IPV6_MMTU - 8;
-
-
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
inc.inc6_faddr = *dst;
if (in6_setscope(&inc.inc6_faddr,
m->m_pkthdr.rcvif, NULL))
- goto unlock_inp;
-
+ goto out;
/*
* Only process the offered MTU if it
* is smaller than the current one.
*/
if (mtu < tp->t_maxseg +
- (sizeof (*th) + sizeof (*ip6))) {
+ sizeof (struct tcphdr) +
+ sizeof (struct ip6_hdr)) {
tcp_hc_updatemtu(&inc, mtu);
tcp_mtudisc(inp, mtu);
ICMP6STAT_INC(icp6s_pmtuchg);
@@ -2161,19 +2253,19 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
inet6ctlerrmap[cmd]);
}
}
-unlock_inp:
- if (inp != NULL)
- INP_WUNLOCK(inp);
} else {
bzero(&inc, sizeof(inc));
inc.inc_fibnum = M_GETFIB(m);
inc.inc_flags |= INC_ISIPV6;
- inc.inc_fport = th->th_dport;
- inc.inc_lport = th->th_sport;
+ inc.inc_fport = t_ports.th_dport;
+ inc.inc_lport = t_ports.th_sport;
inc.inc6_faddr = *dst;
inc.inc6_laddr = ip6->ip6_src;
- syncache_unreach(&inc, th);
+ syncache_unreach(&inc, icmp_tcp_seq);
}
+out:
+ if (inp != NULL)
+ INP_WUNLOCK(inp);
INP_INFO_RUNLOCK(&V_tcbinfo);
}
#endif /* INET6 */
diff --git a/freebsd/sys/netinet/tcp_syncache.c b/freebsd/sys/netinet/tcp_syncache.c
index 13170ae9..cf1f0ad1 100644
--- a/freebsd/sys/netinet/tcp_syncache.c
+++ b/freebsd/sys/netinet/tcp_syncache.c
@@ -604,7 +604,7 @@ syncache_badack(struct in_conninfo *inc)
}
void
-syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
+syncache_unreach(struct in_conninfo *inc, tcp_seq th_seq)
{
struct syncache *sc;
struct syncache_head *sch;
@@ -615,7 +615,7 @@ syncache_unreach(struct in_conninfo *inc, struct tcphdr *th)
goto done;
/* If the sequence number != sc_iss, then it's a bogus ICMP msg */
- if (ntohl(th->th_seq) != sc->sc_iss)
+ if (ntohl(th_seq) != sc->sc_iss)
goto done;
/*
@@ -1274,6 +1274,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
* soon as possible.
*/
so = *lsop;
+ KASSERT(SOLISTENING(so), ("%s: %p not listening", __func__, so));
tp = sototcpcb(so);
cred = crhold(so->so_cred);
@@ -1284,7 +1285,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
#endif
ip_ttl = inp->inp_ip_ttl;
ip_tos = inp->inp_ip_tos;
- win = sbspace(&so->so_rcv);
+ win = so->sol_sbrcv_hiwat;
ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
#ifdef TCP_RFC7413
@@ -1297,7 +1298,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
* listen queue with bogus TFO connections.
*/
if (atomic_fetchadd_int(tp->t_tfo_pending, 1) <=
- (so->so_qlimit / 2)) {
+ (so->sol_qlimit / 2)) {
int result;
result = tcp_fastopen_check_cookie(inc,
@@ -2125,7 +2126,7 @@ syncookie_lookup(struct in_conninfo *inc, struct syncache_head *sch,
sc->sc_flags |= SCF_WINSCALE;
}
- wnd = sbspace(&lso->so_rcv);
+ wnd = lso->sol_sbrcv_hiwat;
wnd = imax(wnd, 0);
wnd = imin(wnd, TCP_MAXWIN);
sc->sc_wnd = wnd;
diff --git a/freebsd/sys/netinet/tcp_syncache.h b/freebsd/sys/netinet/tcp_syncache.h
index ebf9fb84..3932cab7 100644
--- a/freebsd/sys/netinet/tcp_syncache.h
+++ b/freebsd/sys/netinet/tcp_syncache.h
@@ -38,7 +38,7 @@ void syncache_init(void);
#ifdef VIMAGE
void syncache_destroy(void);
#endif
-void syncache_unreach(struct in_conninfo *, struct tcphdr *);
+void syncache_unreach(struct in_conninfo *, tcp_seq);
int syncache_expand(struct in_conninfo *, struct tcpopt *,
struct tcphdr *, struct socket **, struct mbuf *);
int syncache_add(struct in_conninfo *, struct tcpopt *,
diff --git a/freebsd/sys/netinet/tcp_timewait.c b/freebsd/sys/netinet/tcp_timewait.c
index de7d08da..13105339 100644
--- a/freebsd/sys/netinet/tcp_timewait.c
+++ b/freebsd/sys/netinet/tcp_timewait.c
@@ -354,7 +354,6 @@ tcp_twstart(struct tcpcb *tp)
("tcp_twstart: !SS_PROTOREF"));
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
sofree(so);
@@ -493,7 +492,6 @@ tcp_twclose(struct tcptw *tw, int reuse)
if (inp->inp_flags & INP_SOCKREF) {
inp->inp_flags &= ~INP_SOCKREF;
INP_WUNLOCK(inp);
- ACCEPT_LOCK();
SOCK_LOCK(so);
KASSERT(so->so_state & SS_PROTOREF,
("tcp_twclose: INP_SOCKREF && !SS_PROTOREF"));
diff --git a/freebsd/sys/netinet/tcp_var.h b/freebsd/sys/netinet/tcp_var.h
index d298c9dd..2e2f88ac 100644
--- a/freebsd/sys/netinet/tcp_var.h
+++ b/freebsd/sys/netinet/tcp_var.h
@@ -272,8 +272,9 @@ struct tcp_function_block {
};
struct tcp_function {
- TAILQ_ENTRY(tcp_function) tf_next;
- struct tcp_function_block *tf_fb;
+ TAILQ_ENTRY(tcp_function) tf_next;
+ char tf_name[TCP_FUNCTION_NAME_LEN_MAX];
+ struct tcp_function_block *tf_fb;
};
TAILQ_HEAD(tcp_funchead, tcp_function);
@@ -785,6 +786,10 @@ void tcp_do_segment(struct mbuf *, struct tcphdr *,
int);
int register_tcp_functions(struct tcp_function_block *blk, int wait);
+int register_tcp_functions_as_names(struct tcp_function_block *blk,
+ int wait, const char *names[], int *num_names);
+int register_tcp_functions_as_name(struct tcp_function_block *blk,
+ const char *name, int wait);
int deregister_tcp_functions(struct tcp_function_block *blk);
struct tcp_function_block *find_and_ref_tcp_functions(struct tcp_function_set *fs);
struct tcp_function_block *find_and_ref_tcp_fb(struct tcp_function_block *blk);
diff --git a/freebsd/sys/netinet6/ip6_output.c b/freebsd/sys/netinet6/ip6_output.c
index 48a8c454..d8ed24a9 100644
--- a/freebsd/sys/netinet6/ip6_output.c
+++ b/freebsd/sys/netinet6/ip6_output.c
@@ -119,10 +119,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
#include <netinet6/scope6_var.h>
-#ifdef FLOWTABLE
-#include <net/flowtable.h>
-#endif
-
extern int in6_mcast_loop;
struct ip6_exthdrs {
@@ -504,10 +500,6 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
if (opt && opt->ip6po_rthdr)
ro = &opt->ip6po_route;
dst = (struct sockaddr_in6 *)&ro->ro_dst;
-#ifdef FLOWTABLE
- if (ro->ro_rt == NULL)
- (void )flowtable_lookup(AF_INET6, m, (struct route *)ro);
-#endif
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m);
again:
/*
diff --git a/freebsd/sys/netinet6/sctp6_usrreq.c b/freebsd/sys/netinet6/sctp6_usrreq.c
index f94068f9..cca2ebcf 100644
--- a/freebsd/sys/netinet6/sctp6_usrreq.c
+++ b/freebsd/sys/netinet6/sctp6_usrreq.c
@@ -307,7 +307,7 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
return;
}
/* Copy out the port numbers and the verification tag. */
- bzero(&sh, sizeof(sh));
+ memset(&sh, 0, sizeof(sh));
m_copydata(ip6cp->ip6c_m,
ip6cp->ip6c_off,
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
diff --git a/freebsd/sys/netipsec/ipsec.h b/freebsd/sys/netipsec/ipsec.h
index 0522b7e7..a4c3f3d2 100644
--- a/freebsd/sys/netipsec/ipsec.h
+++ b/freebsd/sys/netipsec/ipsec.h
@@ -253,8 +253,9 @@ struct ipsecstat {
#include <sys/counter.h>
struct ipsec_ctx_data;
-#define IPSEC_INIT_CTX(_ctx, _mp, _sav, _af, _enc) do { \
+#define IPSEC_INIT_CTX(_ctx, _mp, _inp, _sav, _af, _enc) do { \
(_ctx)->mp = (_mp); \
+ (_ctx)->inp = (_inp); \
(_ctx)->sav = (_sav); \
(_ctx)->af = (_af); \
(_ctx)->enc = (_enc); \
diff --git a/freebsd/sys/netipsec/ipsec_input.c b/freebsd/sys/netipsec/ipsec_input.c
index d9dfd254..38341346 100644
--- a/freebsd/sys/netipsec/ipsec_input.c
+++ b/freebsd/sys/netipsec/ipsec_input.c
@@ -327,7 +327,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
(prot == IPPROTO_UDP || prot == IPPROTO_TCP))
udp_ipsec_adjust_cksum(m, sav, prot, skip);
- IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
+ IPSEC_INIT_CTX(&ctx, &m, NULL, sav, AF_INET, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
ip = mtod(m, struct ip *); /* update pointer */
@@ -418,7 +418,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
goto bad;
}
- IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_AFTER);
+ IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
@@ -524,7 +524,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
goto bad;
}
- IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_BEFORE);
+ IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
@@ -595,7 +595,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
else
#endif
af = AF_INET6;
- IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_AFTER);
+ IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
if (skip == 0) {
diff --git a/freebsd/sys/netipsec/ipsec_output.c b/freebsd/sys/netipsec/ipsec_output.c
index b7dd8f30..07e39a8a 100644
--- a/freebsd/sys/netipsec/ipsec_output.c
+++ b/freebsd/sys/netipsec/ipsec_output.c
@@ -183,7 +183,8 @@ next:
* IPsec output logic for IPv4.
*/
static int
-ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
+ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp,
+ struct inpcb *inp, u_int idx)
{
struct ipsec_ctx_data ctx;
union sockaddr_union *dst;
@@ -213,7 +214,7 @@ ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/*
* XXXAE: most likely ip_sum at this point is wrong.
*/
- IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
+ IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@@ -237,9 +238,10 @@ ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/* XXXAE: IPSEC_OSTAT_INC(tunnel); */
goto bad;
}
+ inp = NULL;
}
- IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
+ IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@@ -287,7 +289,7 @@ ipsec4_process_packet(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp)
{
- return (ipsec4_perform_request(m, sp, 0));
+ return (ipsec4_perform_request(m, sp, inp, 0));
}
static int
@@ -493,7 +495,8 @@ next:
* IPsec output logic for IPv6.
*/
static int
-ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
+ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp,
+ struct inpcb *inp, u_int idx)
{
struct ipsec_ctx_data ctx;
union sockaddr_union *dst;
@@ -516,7 +519,7 @@ ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
- IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET6, IPSEC_ENC_BEFORE);
+ IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET6, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@@ -542,9 +545,10 @@ ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/* XXXAE: IPSEC_OSTAT_INC(tunnel); */
goto bad;
}
+ inp = NULL;
}
- IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
+ IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@@ -587,7 +591,7 @@ ipsec6_process_packet(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp)
{
- return (ipsec6_perform_request(m, sp, 0));
+ return (ipsec6_perform_request(m, sp, inp, 0));
}
static int
@@ -752,14 +756,14 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
case AF_INET:
key_freesav(&sav);
IPSECSTAT_INC(ips_out_bundlesa);
- return (ipsec4_perform_request(m, sp, idx));
+ return (ipsec4_perform_request(m, sp, NULL, idx));
/* NOTREACHED */
#endif
#ifdef INET6
case AF_INET6:
key_freesav(&sav);
IPSEC6STAT_INC(ips_out_bundlesa);
- return (ipsec6_perform_request(m, sp, idx));
+ return (ipsec6_perform_request(m, sp, NULL, idx));
/* NOTREACHED */
#endif /* INET6 */
default:
diff --git a/freebsd/sys/netipsec/key_debug.c b/freebsd/sys/netipsec/key_debug.c
index 1911af01..f71212b7 100644
--- a/freebsd/sys/netipsec/key_debug.c
+++ b/freebsd/sys/netipsec/key_debug.c
@@ -79,10 +79,6 @@ static void kdebug_sadb_x_sa2(struct sadb_ext *);
static void kdebug_sadb_x_sa_replay(struct sadb_ext *);
static void kdebug_sadb_x_natt(struct sadb_ext *);
-#ifdef _KERNEL
-static void kdebug_secreplay(struct secreplay *);
-#endif
-
#ifndef _KERNEL
#define panic(fmt, ...) { printf(fmt, ## __VA_ARGS__); exit(-1); }
#endif
@@ -726,6 +722,7 @@ kdebug_secash(struct secashead *sah, const char *indent)
printf("}\n");
}
+#ifdef IPSEC_DEBUG
static void
kdebug_secreplay(struct secreplay *rpl)
{
@@ -747,6 +744,7 @@ kdebug_secreplay(struct secreplay *rpl)
}
printf(" }\n");
}
+#endif /* IPSEC_DEBUG */
static void
kdebug_secnatt(struct secnatt *natt)
diff --git a/freebsd/sys/netpfil/pf/pf.c b/freebsd/sys/netpfil/pf/pf.c
index 42f9132d..ca46d16e 100644
--- a/freebsd/sys/netpfil/pf/pf.c
+++ b/freebsd/sys/netpfil/pf/pf.c
@@ -134,6 +134,9 @@ VNET_DEFINE(int, pf_tcp_iss_off);
VNET_DECLARE(int, pf_vnet_active);
#define V_pf_vnet_active VNET(pf_vnet_active)
+static VNET_DEFINE(uint32_t, pf_purge_idx);
+#define V_pf_purge_idx VNET(pf_purge_idx)
+
/*
* Queue for pf_intr() sends.
*/
@@ -1429,7 +1432,6 @@ void
pf_purge_thread(void *unused __unused)
{
VNET_ITERATOR_DECL(vnet_iter);
- u_int idx = 0;
sx_xlock(&pf_end_lock);
while (pf_end_threads == 0) {
@@ -1450,14 +1452,15 @@ pf_purge_thread(void *unused __unused)
* Process 1/interval fraction of the state
* table every run.
*/
- idx = pf_purge_expired_states(idx, pf_hashmask /
+ V_pf_purge_idx =
+ pf_purge_expired_states(V_pf_purge_idx, pf_hashmask /
(V_pf_default_rule.timeout[PFTM_INTERVAL] * 10));
/*
* Purge other expired types every
* PFTM_INTERVAL seconds.
*/
- if (idx == 0) {
+ if (V_pf_purge_idx == 0) {
/*
* Order is important:
* - states and src nodes reference rules
diff --git a/freebsd/sys/sys/_pctrie.h b/freebsd/sys/sys/_pctrie.h
index 45f69b20..c6d13baa 100644
--- a/freebsd/sys/sys/_pctrie.h
+++ b/freebsd/sys/sys/_pctrie.h
@@ -38,14 +38,4 @@ struct pctrie {
uintptr_t pt_root;
};
-#ifdef _KERNEL
-
-static __inline boolean_t
-pctrie_is_empty(struct pctrie *ptree)
-{
-
- return (ptree->pt_root == 0);
-}
-
-#endif /* _KERNEL */
#endif /* !__SYS_PCTRIE_H_ */
diff --git a/freebsd/sys/sys/ata.h b/freebsd/sys/sys/ata.h
index 0ed78ec8..4d3b3e7f 100644
--- a/freebsd/sys/sys/ata.h
+++ b/freebsd/sys/sys/ata.h
@@ -68,8 +68,8 @@ struct ata_params {
/*049*/ u_int16_t capabilities1;
#define ATA_SUPPORT_DMA 0x0100
#define ATA_SUPPORT_LBA 0x0200
-#define ATA_SUPPORT_IORDY 0x0400
-#define ATA_SUPPORT_IORDYDIS 0x0800
+#define ATA_SUPPORT_IORDYDIS 0x0400
+#define ATA_SUPPORT_IORDY 0x0800
#define ATA_SUPPORT_OVERLAP 0x4000
/*050*/ u_int16_t capabilities2;
diff --git a/freebsd/sys/sys/blist.h b/freebsd/sys/sys/blist.h
index f2e81ec8..292f9b97 100644
--- a/freebsd/sys/sys/blist.h
+++ b/freebsd/sys/sys/blist.h
@@ -44,7 +44,7 @@
* ops.
*
* SWAPBLK_NONE is returned on failure. This module is typically
- * capable of managing up to (2^31) blocks per blist, though
+ * capable of managing up to (2^63) blocks per blist, though
* the memory utilization would be insane if you actually did
* that. Managing something like 512MB worth of 4K blocks
* eats around 32 KBytes of memory.
@@ -56,7 +56,7 @@
#ifndef _SYS_BLIST_H_
#define _SYS_BLIST_H_
-typedef u_int32_t u_daddr_t; /* unsigned disk address */
+typedef uint64_t u_daddr_t; /* unsigned disk address */
/*
* note: currently use SWAPBLK_NONE as an absolute value rather then
@@ -67,7 +67,7 @@ typedef u_int32_t u_daddr_t; /* unsigned disk address */
#define SWAPBLK_NONE ((daddr_t)((u_daddr_t)SWAPBLK_MASK + 1))/* flag */
/*
- * blmeta and bl_bitmap_t MUST be a power of 2 in size.
+ * Both blmeta and bmu_bitmap MUST be a power of 2 in size.
*/
typedef struct blmeta {
@@ -82,9 +82,8 @@ typedef struct blist {
daddr_t bl_blocks; /* area of coverage */
daddr_t bl_radix; /* coverage radix */
daddr_t bl_skip; /* starting skip */
- daddr_t bl_free; /* number of free blocks */
+ daddr_t bl_cursor; /* next-fit search starts at */
blmeta_t *bl_root; /* root of radix tree */
- daddr_t bl_rootblks; /* daddr_t blks allocated for tree */
} *blist_t;
#define BLIST_META_RADIX 16
@@ -92,13 +91,14 @@ typedef struct blist {
#define BLIST_MAX_ALLOC BLIST_BMAP_RADIX
-extern blist_t blist_create(daddr_t blocks, int flags);
-extern void blist_destroy(blist_t blist);
-extern daddr_t blist_alloc(blist_t blist, daddr_t count);
-extern void blist_free(blist_t blist, daddr_t blkno, daddr_t count);
-extern int blist_fill(blist_t bl, daddr_t blkno, daddr_t count);
-extern void blist_print(blist_t blist);
-extern void blist_resize(blist_t *pblist, daddr_t count, int freenew, int flags);
+daddr_t blist_alloc(blist_t blist, daddr_t count);
+daddr_t blist_avail(blist_t blist);
+blist_t blist_create(daddr_t blocks, int flags);
+void blist_destroy(blist_t blist);
+daddr_t blist_fill(blist_t bl, daddr_t blkno, daddr_t count);
+void blist_free(blist_t blist, daddr_t blkno, daddr_t count);
+void blist_print(blist_t blist);
+void blist_resize(blist_t *pblist, daddr_t count, int freenew, int flags);
#endif /* _SYS_BLIST_H_ */
diff --git a/freebsd/sys/sys/buf.h b/freebsd/sys/sys/buf.h
index 830fb054..58bd91e3 100644
--- a/freebsd/sys/sys/buf.h
+++ b/freebsd/sys/sys/buf.h
@@ -472,6 +472,7 @@ buf_track(struct buf *bp, const char *location)
extern int nbuf; /* The number of buffer headers */
extern long maxswzone; /* Max KVA for swap structures */
extern long maxbcache; /* Max KVA for buffer cache */
+extern int maxbcachebuf; /* Max buffer cache block size */
extern long runningbufspace;
extern long hibufspace;
extern int dirtybufthresh;
diff --git a/freebsd/sys/sys/bus_dma.h b/freebsd/sys/sys/bus_dma.h
index 1a2ecd6b..04dbe0cb 100644
--- a/freebsd/sys/sys/bus_dma.h
+++ b/freebsd/sys/sys/bus_dma.h
@@ -248,105 +248,49 @@ int bus_dmamap_load_ma_triv(bus_dma_tag_t dmat, bus_dmamap_t map,
struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
bus_dma_segment_t *segs, int *segp);
-/*
- * XXX sparc64 uses the same interface, but a much different implementation.
- * <machine/bus_dma.h> for the sparc64 arch contains the equivalent
- * declarations.
- */
-#if !defined(__sparc64__)
+#ifdef WANT_INLINE_DMAMAP
+#define BUS_DMAMAP_OP static inline
+#else
+#define BUS_DMAMAP_OP
+#endif
/*
* Allocate a handle for mapping from kva/uva/physical
* address space into bus device space.
*/
-int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp);
+BUS_DMAMAP_OP int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp);
/*
* Destroy a handle for mapping from kva/uva/physical
* address space into bus device space.
*/
-int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map);
+BUS_DMAMAP_OP int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map);
/*
* Allocate a piece of memory that can be efficiently mapped into
* bus device space based on the constraints listed in the dma tag.
* A dmamap to for use with dmamap_load is also allocated.
*/
-int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
+BUS_DMAMAP_OP int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
bus_dmamap_t *mapp);
/*
* Free a piece of memory and its allocated dmamap, that was allocated
* via bus_dmamem_alloc.
*/
-void bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);
+BUS_DMAMAP_OP void bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);
/*
* Perform a synchronization operation on the given map. If the map
- * is NULL we have a fully IO-coherent system. On every ARM architecture
- * there must be a memory barrier placed to ensure that all data
- * accesses are visible before going any further.
+ * is NULL we have a fully IO-coherent system.
*/
-void _bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t);
-#if defined(__arm__)
- #define __BUS_DMAMAP_SYNC_DEFAULT mb()
-#elif defined(__aarch64__)
- #define __BUS_DMAMAP_SYNC_DEFAULT dmb(sy)
-#else
- #define __BUS_DMAMAP_SYNC_DEFAULT do {} while (0)
-#endif
-#define bus_dmamap_sync(dmat, dmamap, op) \
- do { \
- if ((dmamap) != NULL) \
- _bus_dmamap_sync(dmat, dmamap, op); \
- else \
- __BUS_DMAMAP_SYNC_DEFAULT; \
- } while (0)
+BUS_DMAMAP_OP void bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t dmamap, bus_dmasync_op_t op);
/*
* Release the mapping held by map.
*/
-void _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map);
-#define bus_dmamap_unload(dmat, dmamap) \
- do { \
- if ((dmamap) != NULL) \
- _bus_dmamap_unload(dmat, dmamap); \
- } while (0)
-
-/*
- * The following functions define the interface between the MD and MI
- * busdma layers. These are not intended for consumption by driver
- * software.
- */
-void __bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct memdesc *mem,
- bus_dmamap_callback_t *callback,
- void *callback_arg);
-
-#define _bus_dmamap_waitok(dmat, map, mem, callback, callback_arg) \
- do { \
- if ((map) != NULL) \
- __bus_dmamap_waitok(dmat, map, mem, callback, \
- callback_arg); \
- } while (0);
-
-int _bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map,
- void *buf, bus_size_t buflen, struct pmap *pmap,
- int flags, bus_dma_segment_t *segs, int *segp);
-
-int _bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
- vm_paddr_t paddr, bus_size_t buflen,
- int flags, bus_dma_segment_t *segs, int *segp);
-
-int _bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
- bus_dma_segment_t *segs, int *segp);
-
-bus_dma_segment_t *_bus_dmamap_complete(bus_dma_tag_t dmat,
- bus_dmamap_t map,
- bus_dma_segment_t *segs,
- int nsegs, int error);
+BUS_DMAMAP_OP void bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t dmamap);
-#endif /* __sparc64__ */
+#undef BUS_DMAMAP_OP
#endif /* _BUS_DMA_H_ */
diff --git a/freebsd/sys/sys/jail.h b/freebsd/sys/sys/jail.h
index c67c8f55..bc9025cf 100644
--- a/freebsd/sys/sys/jail.h
+++ b/freebsd/sys/sys/jail.h
@@ -215,22 +215,24 @@ struct prison_racct {
/* by this jail or an ancestor */
/* Flags for pr_allow */
-#define PR_ALLOW_SET_HOSTNAME 0x0001
-#define PR_ALLOW_SYSVIPC 0x0002
-#define PR_ALLOW_RAW_SOCKETS 0x0004
-#define PR_ALLOW_CHFLAGS 0x0008
-#define PR_ALLOW_MOUNT 0x0010
-#define PR_ALLOW_QUOTAS 0x0020
-#define PR_ALLOW_SOCKET_AF 0x0040
-#define PR_ALLOW_MOUNT_DEVFS 0x0080
-#define PR_ALLOW_MOUNT_NULLFS 0x0100
-#define PR_ALLOW_MOUNT_ZFS 0x0200
-#define PR_ALLOW_MOUNT_PROCFS 0x0400
-#define PR_ALLOW_MOUNT_TMPFS 0x0800
-#define PR_ALLOW_MOUNT_FDESCFS 0x1000
-#define PR_ALLOW_MOUNT_LINPROCFS 0x2000
-#define PR_ALLOW_MOUNT_LINSYSFS 0x4000
-#define PR_ALLOW_ALL 0x7fff
+#define PR_ALLOW_SET_HOSTNAME 0x00000001
+#define PR_ALLOW_SYSVIPC 0x00000002
+#define PR_ALLOW_RAW_SOCKETS 0x00000004
+#define PR_ALLOW_CHFLAGS 0x00000008
+#define PR_ALLOW_MOUNT 0x00000010
+#define PR_ALLOW_QUOTAS 0x00000020
+#define PR_ALLOW_SOCKET_AF 0x00000040
+#define PR_ALLOW_MOUNT_DEVFS 0x00000080
+#define PR_ALLOW_MOUNT_NULLFS 0x00000100
+#define PR_ALLOW_MOUNT_ZFS 0x00000200
+#define PR_ALLOW_MOUNT_PROCFS 0x00000400
+#define PR_ALLOW_MOUNT_TMPFS 0x00000800
+#define PR_ALLOW_MOUNT_FDESCFS 0x00001000
+#define PR_ALLOW_MOUNT_LINPROCFS 0x00002000
+#define PR_ALLOW_MOUNT_LINSYSFS 0x00004000
+#define PR_ALLOW_RESERVED_PORTS 0x00008000
+#define PR_ALLOW_KMEM_ACCESS 0x00010000 /* reserved, not used yet */
+#define PR_ALLOW_ALL 0x0001ffff
/*
* OSD methods
diff --git a/freebsd/sys/sys/module.h b/freebsd/sys/sys/module.h
index 71aa9954..5a268fc1 100644
--- a/freebsd/sys/sys/module.h
+++ b/freebsd/sys/sys/module.h
@@ -106,14 +106,15 @@ struct mod_pnp_match_info
#include <sys/linker_set.h>
+#define MODULE_METADATA_CONCAT(uniquifier) _mod_metadata##uniquifier
#define MODULE_METADATA(uniquifier, type, data, cval) \
- static struct mod_metadata _mod_metadata##uniquifier = { \
+ static struct mod_metadata MODULE_METADATA_CONCAT(uniquifier) = { \
MDT_STRUCT_VERSION, \
type, \
data, \
cval \
}; \
- DATA_SET(modmetadata_set, _mod_metadata##uniquifier)
+ DATA_SET(modmetadata_set, MODULE_METADATA_CONCAT(uniquifier))
#define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) \
static struct mod_depend _##module##_depend_on_##mdepend \
@@ -139,7 +140,7 @@ struct mod_pnp_match_info
#define DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, maxver) \
MODULE_DEPEND(name, kernel, __FreeBSD_version, \
__FreeBSD_version, maxver); \
- MODULE_METADATA(_md_##name, MDT_MODULE, &data, #name); \
+ MODULE_METADATA(_md_##name, MDT_MODULE, &data, __XSTRING(name));\
SYSINIT(name##module, sub, order, module_register_init, &data); \
struct __hack
@@ -156,13 +157,14 @@ struct mod_pnp_match_info
#define DECLARE_MODULE_TIED(name, data, sub, order) \
DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, __FreeBSD_version)
+#define MODULE_VERSION_CONCAT(module, version) _##module##_version
#define MODULE_VERSION(module, version) \
- static struct mod_version _##module##_version \
+ static struct mod_version MODULE_VERSION_CONCAT(module, version)\
__section(".data") = { \
version \
}; \
- MODULE_METADATA(_##module##_version, MDT_VERSION, \
- &_##module##_version, #module)
+ MODULE_METADATA(MODULE_VERSION_CONCAT(module, version), MDT_VERSION,\
+ &MODULE_VERSION_CONCAT(module, version), __XSTRING(module))
/**
* Generic macros to create pnp info hints that modules may export
diff --git a/freebsd/sys/sys/proc.h b/freebsd/sys/sys/proc.h
index 0644d68b..b28c19e6 100644
--- a/freebsd/sys/sys/proc.h
+++ b/freebsd/sys/sys/proc.h
@@ -142,6 +142,7 @@ struct pargs {
* j - locked by proc slock
* k - only accessed by curthread
* k*- only accessed by curthread and from an interrupt
+ * kx- only accessed by curthread and by debugger
* l - the attaching proc or attaching proc parent
* m - Giant
* n - not locked, lazy
@@ -327,11 +328,11 @@ struct thread {
u_char td_pri_class; /* (t) Scheduling class. */
u_char td_user_pri; /* (t) User pri from estcpu and nice. */
u_char td_base_user_pri; /* (t) Base user pri */
- u_int td_dbg_sc_code; /* (c) Syscall code to debugger. */
- u_int td_dbg_sc_narg; /* (c) Syscall arg count to debugger.*/
uintptr_t td_rb_list; /* (k) Robust list head. */
uintptr_t td_rbp_list; /* (k) Robust priv list head. */
uintptr_t td_rb_inact; /* (k) Current in-action mutex loc. */
+ struct syscall_args td_sa; /* (kx) Syscall parameters. Copied on
+ fork for child tracing. */
#define td_endcopy td_pcb
/*
@@ -1119,7 +1120,7 @@ void userret(struct thread *, struct trapframe *);
void cpu_exit(struct thread *);
void exit1(struct thread *, int, int) __dead2;
void cpu_copy_thread(struct thread *td, struct thread *td0);
-int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
+int cpu_fetch_syscall_args(struct thread *td);
void cpu_fork(struct thread *, struct proc *, struct thread *, int);
void cpu_fork_kthread_handler(struct thread *, void (*)(void *), void *);
void cpu_set_syscall_retval(struct thread *, int);
diff --git a/freebsd/sys/sys/refcount.h b/freebsd/sys/sys/refcount.h
index 32f7f6e4..ea846f8c 100644
--- a/freebsd/sys/sys/refcount.h
+++ b/freebsd/sys/sys/refcount.h
@@ -50,7 +50,7 @@ refcount_acquire(volatile u_int *count)
{
KASSERT(*count < UINT_MAX, ("refcount %p overflowed", count));
- atomic_add_acq_int((volatile int *)count, 1);
+ atomic_add_int((volatile int *)count, 1);
}
static __inline int
@@ -58,10 +58,20 @@ refcount_release(volatile u_int *count)
{
u_int old;
- /* XXX: Should this have a rel membar? */
+ atomic_thread_fence_rel();
old = atomic_fetchadd_int((volatile int *)count, -1);
KASSERT(old > 0, ("negative refcount %p", count));
- return (old == 1);
+ if (old > 1)
+ return (0);
+
+ /*
+ * Last reference. Signal the user to call the destructor.
+ *
+ * Ensure that the destructor sees all updates. The fence_rel
+ * at the start of the function synchronized with this fence.
+ */
+ atomic_thread_fence_acq();
+ return (1);
}
#endif /* ! __SYS_REFCOUNT_H__ */
diff --git a/freebsd/sys/sys/sockbuf.h b/freebsd/sys/sys/sockbuf.h
index b1ebe62f..c9cb4dd7 100644
--- a/freebsd/sys/sys/sockbuf.h
+++ b/freebsd/sys/sys/sockbuf.h
@@ -32,7 +32,6 @@
*/
#ifndef _SYS_SOCKBUF_H_
#define _SYS_SOCKBUF_H_
-#include <sys/selinfo.h> /* for struct selinfo */
#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/_sx.h>
@@ -64,6 +63,7 @@ struct mbuf;
struct sockaddr;
struct socket;
struct thread;
+struct selinfo;
struct xsockbuf {
u_int sb_cc;
@@ -84,9 +84,9 @@ struct xsockbuf {
* (a) locked by SOCKBUF_LOCK().
*/
struct sockbuf {
- struct selinfo sb_sel; /* process selecting read/write */
- struct mtx sb_mtx; /* sockbuf lock */
- struct sx sb_sx; /* prevent I/O interlacing */
+ struct mtx sb_mtx; /* sockbuf lock */
+ struct sx sb_sx; /* prevent I/O interlacing */
+ struct selinfo *sb_sel; /* process selecting read/write */
short sb_state; /* (a) socket state on sockbuf */
#define sb_startzero sb_mb
struct mbuf *sb_mb; /* (a) the mbuf chain */
@@ -169,8 +169,7 @@ void sbflush_locked(struct sockbuf *sb);
void sbrelease(struct sockbuf *sb, struct socket *so);
void sbrelease_internal(struct sockbuf *sb, struct socket *so);
void sbrelease_locked(struct sockbuf *sb, struct socket *so);
-int sbreserve(struct sockbuf *sb, u_long cc, struct socket *so,
- struct thread *td);
+int sbsetopt(struct socket *so, int cmd, u_long cc);
int sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so,
struct thread *td);
struct mbuf *
diff --git a/freebsd/sys/sys/socketvar.h b/freebsd/sys/sys/socketvar.h
index 245a687b..0c5b95ec 100644
--- a/freebsd/sys/sys/socketvar.h
+++ b/freebsd/sys/sys/socketvar.h
@@ -55,7 +55,8 @@ struct vnet;
* handle on protocol and pointer to protocol
* private data and error information.
*/
-typedef u_quad_t so_gen_t;
+typedef uint64_t so_gen_t;
+typedef int so_upcall_t(struct socket *, void *, int);
struct socket;
@@ -63,60 +64,35 @@ struct socket;
* Locking key to struct socket:
* (a) constant after allocation, no locking required.
* (b) locked by SOCK_LOCK(so).
- * (c) locked by SOCKBUF_LOCK(&so->so_rcv).
- * (e) locked by ACCEPT_LOCK().
+ * (cr) locked by SOCKBUF_LOCK(&so->so_rcv).
+ * (cs) locked by SOCKBUF_LOCK(&so->so_rcv).
+ * (e) locked by SOLISTEN_LOCK() of corresponding listening socket.
* (f) not locked since integer reads/writes are atomic.
* (g) used only as a sleep/wakeup address, no value.
* (h) locked by global mutex so_global_mtx.
*/
+TAILQ_HEAD(accept_queue, socket);
struct socket {
- int so_count; /* (b) reference count */
+ struct mtx so_lock;
+ volatile u_int so_count; /* (b / refcount) */
+ struct selinfo so_rdsel; /* (b/cr) for so_rcv/so_comp */
+ struct selinfo so_wrsel; /* (b/cs) for so_snd */
short so_type; /* (a) generic type, see socket.h */
- short so_options; /* from socket call, see socket.h */
- short so_linger; /* time to linger while closing */
+ short so_options; /* (b) from socket call, see socket.h */
+ short so_linger; /* time to linger close(2) */
short so_state; /* (b) internal state flags SS_* */
- int so_qstate; /* (e) internal state flags SQ_* */
void *so_pcb; /* protocol control block */
struct vnet *so_vnet; /* (a) network stack instance */
struct protosw *so_proto; /* (a) protocol handle */
-/*
- * Variables for connection queuing.
- * Socket where accepts occur is so_head in all subsidiary sockets.
- * If so_head is 0, socket is not related to an accept.
- * For head socket so_incomp queues partially completed connections,
- * while so_comp is a queue of connections ready to be accepted.
- * If a connection is aborted and it has so_head set, then
- * it has to be pulled out of either so_incomp or so_comp.
- * We allow connections to queue up based on current queue lengths
- * and limit on number of queued connections for this socket.
- */
- struct socket *so_head; /* (e) back pointer to listen socket */
- TAILQ_HEAD(, socket) so_incomp; /* (e) queue of partial unaccepted connections */
- TAILQ_HEAD(, socket) so_comp; /* (e) queue of complete unaccepted connections */
- TAILQ_ENTRY(socket) so_list; /* (e) list of unaccepted connections */
- u_int so_qlen; /* (e) number of unaccepted connections */
- u_int so_incqlen; /* (e) number of unaccepted incomplete
- connections */
- u_int so_qlimit; /* (e) max number queued connections */
short so_timeo; /* (g) connection timeout */
u_short so_error; /* (f) error affecting connection */
struct sigio *so_sigio; /* [sg] information for async I/O or
out of band data (SIGURG) */
- u_long so_oobmark; /* (c) chars to oob mark */
-
- struct sockbuf so_rcv, so_snd;
-
struct ucred *so_cred; /* (a) user credentials */
struct label *so_label; /* (b) MAC label for socket */
- struct label *so_peerlabel; /* (b) cached MAC label for peer */
/* NB: generation count must not be first. */
so_gen_t so_gencnt; /* (h) generation count */
void *so_emuldata; /* (b) private data for emulators */
- struct so_accf {
- struct accept_filter *so_accept_filter;
- void *so_accept_filter_arg; /* saved filter args */
- char *so_accept_filter_str; /* saved user args */
- } *so_accf;
struct osd osd; /* Object Specific extensions */
/*
* so_fibnum, so_user_cookie and friends can be used to attach
@@ -129,39 +105,93 @@ struct socket {
int so_ts_clock; /* type of the clock used for timestamps */
uint32_t so_max_pacing_rate; /* (f) TX rate limit in bytes/s */
-
- void *so_pspare[2]; /* general use */
- int so_ispare[2]; /* general use */
+ union {
+ /* Regular (data flow) socket. */
+ struct {
+ /* (cr, cs) Receive and send buffers. */
+ struct sockbuf so_rcv, so_snd;
+
+ /* (e) Our place on accept queue. */
+ TAILQ_ENTRY(socket) so_list;
+ struct socket *so_listen; /* (b) */
+ enum {
+ SQ_NONE = 0,
+ SQ_INCOMP = 0x0800, /* on sol_incomp */
+ SQ_COMP = 0x1000, /* on sol_comp */
+ } so_qstate; /* (b) */
+
+ /* (b) cached MAC label for peer */
+ struct label *so_peerlabel;
+ u_long so_oobmark; /* chars to oob mark */
+ };
+ /*
+ * Listening socket, where accepts occur, is so_listen in all
+ * subsidiary sockets. If so_listen is NULL, socket is not
+ * related to an accept. For a listening socket itself
+ * sol_incomp queues partially completed connections, while
+ * sol_comp is a queue of connections ready to be accepted.
+ * If a connection is aborted and it has so_listen set, then
+ * it has to be pulled out of either sol_incomp or sol_comp.
+ * We allow connections to queue up based on current queue
+ * lengths and limit on number of queued connections for this
+ * socket.
+ */
+ struct {
+ /* (e) queue of partial unaccepted connections */
+ struct accept_queue sol_incomp;
+ /* (e) queue of complete unaccepted connections */
+ struct accept_queue sol_comp;
+ u_int sol_qlen; /* (e) sol_comp length */
+ u_int sol_incqlen; /* (e) sol_incomp length */
+ u_int sol_qlimit; /* (e) queue limit */
+
+ /* accept_filter(9) optional data */
+ struct accept_filter *sol_accept_filter;
+ void *sol_accept_filter_arg; /* saved filter args */
+ char *sol_accept_filter_str; /* saved user args */
+
+ /* Optional upcall, for kernel socket. */
+ so_upcall_t *sol_upcall; /* (e) */
+ void *sol_upcallarg; /* (e) */
+
+ /* Socket buffer parameters, to be copied to
+ * dataflow sockets, accepted from this one. */
+ int sol_sbrcv_lowat;
+ int sol_sbsnd_lowat;
+ u_int sol_sbrcv_hiwat;
+ u_int sol_sbsnd_hiwat;
+ short sol_sbrcv_flags;
+ short sol_sbsnd_flags;
+ sbintime_t sol_sbrcv_timeo;
+ sbintime_t sol_sbsnd_timeo;
+ };
+ };
};
-/*
- * Global accept mutex to serialize access to accept queues and
- * fields associated with multiple sockets. This allows us to
- * avoid defining a lock order between listen and accept sockets
- * until such time as it proves to be a good idea.
- */
-extern struct mtx accept_mtx;
-#define ACCEPT_LOCK_ASSERT() mtx_assert(&accept_mtx, MA_OWNED)
-#define ACCEPT_UNLOCK_ASSERT() mtx_assert(&accept_mtx, MA_NOTOWNED)
-#define ACCEPT_LOCK() mtx_lock(&accept_mtx)
-#define ACCEPT_UNLOCK() mtx_unlock(&accept_mtx)
-
-/*
- * Per-socket mutex: we reuse the receive socket buffer mutex for space
- * efficiency. This decision should probably be revisited as we optimize
- * locking for the socket code.
- */
-#define SOCK_MTX(_so) SOCKBUF_MTX(&(_so)->so_rcv)
-#define SOCK_LOCK(_so) SOCKBUF_LOCK(&(_so)->so_rcv)
-#define SOCK_OWNED(_so) SOCKBUF_OWNED(&(_so)->so_rcv)
-#define SOCK_UNLOCK(_so) SOCKBUF_UNLOCK(&(_so)->so_rcv)
-#define SOCK_LOCK_ASSERT(_so) SOCKBUF_LOCK_ASSERT(&(_so)->so_rcv)
-
-/*
- * Socket state bits stored in so_qstate.
- */
-#define SQ_INCOMP 0x0800 /* unaccepted, incomplete connection */
-#define SQ_COMP 0x1000 /* unaccepted, complete connection */
+#define SOCK_MTX(so) &(so)->so_lock
+#define SOCK_LOCK(so) mtx_lock(&(so)->so_lock)
+#define SOCK_OWNED(so) mtx_owned(&(so)->so_lock)
+#define SOCK_UNLOCK(so) mtx_unlock(&(so)->so_lock)
+#define SOCK_LOCK_ASSERT(so) mtx_assert(&(so)->so_lock, MA_OWNED)
+#define SOCK_UNLOCK_ASSERT(so) mtx_assert(&(so)->so_lock, MA_NOTOWNED)
+
+#define SOLISTENING(sol) (((sol)->so_options & SO_ACCEPTCONN) != 0)
+#define SOLISTEN_LOCK(sol) do { \
+ mtx_lock(&(sol)->so_lock); \
+ KASSERT(SOLISTENING(sol), \
+ ("%s: %p not listening", __func__, (sol))); \
+} while (0)
+#define SOLISTEN_TRYLOCK(sol) mtx_trylock(&(sol)->so_lock)
+#define SOLISTEN_UNLOCK(sol) do { \
+ KASSERT(SOLISTENING(sol), \
+ ("%s: %p not listening", __func__, (sol))); \
+ mtx_unlock(&(sol)->so_lock); \
+} while (0)
+#define SOLISTEN_LOCK_ASSERT(sol) do { \
+ mtx_assert(&(sol)->so_lock, MA_OWNED); \
+ KASSERT(SOLISTENING(sol), \
+ ("%s: %p not listening", __func__, (sol))); \
+} while (0)
/*
* Externalized form of struct socket used by the sysctl(3) interface.
@@ -212,8 +242,7 @@ struct xsocket {
/* can we read something from so? */
#define soreadabledata(so) \
- (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || \
- !TAILQ_EMPTY(&(so)->so_comp) || (so)->so_error)
+ (sbavail(&(so)->so_rcv) >= (so)->so_rcv.sb_lowat || (so)->so_error)
#define soreadable(so) \
(soreadabledata(so) || ((so)->so_rcv.sb_state & SBS_CANTRCVMORE))
@@ -226,26 +255,19 @@ struct xsocket {
(so)->so_error)
/*
- * soref()/sorele() ref-count the socket structure. Note that you must
- * still explicitly close the socket, but the last ref count will free
- * the structure.
+ * soref()/sorele() ref-count the socket structure.
+ * soref() may be called without owning socket lock, but in that case a
+ * caller must own something that holds socket, and so_count must be not 0.
+ * Note that you must still explicitly close the socket, but the last ref
+ * count will free the structure.
*/
-#define soref(so) do { \
- SOCK_LOCK_ASSERT(so); \
- ++(so)->so_count; \
-} while (0)
-
+#define soref(so) refcount_acquire(&(so)->so_count)
#define sorele(so) do { \
- ACCEPT_LOCK_ASSERT(); \
SOCK_LOCK_ASSERT(so); \
- if ((so)->so_count <= 0) \
- panic("sorele"); \
- if (--(so)->so_count == 0) \
+ if (refcount_release(&(so)->so_count)) \
sofree(so); \
- else { \
+ else \
SOCK_UNLOCK(so); \
- ACCEPT_UNLOCK(); \
- } \
} while (0)
/*
@@ -370,10 +392,11 @@ void sohasoutofband(struct socket *so);
int solisten(struct socket *so, int backlog, struct thread *td);
void solisten_proto(struct socket *so, int backlog);
int solisten_proto_check(struct socket *so);
+int solisten_dequeue(struct socket *, struct socket **, int);
struct socket *
sonewconn(struct socket *head, int connstatus);
-
-
+struct socket *
+ sopeeloff(struct socket *);
int sopoll(struct socket *so, int events, struct ucred *active_cred,
struct thread *td);
int sopoll_generic(struct socket *so, int events,
@@ -402,15 +425,16 @@ int sosend_generic(struct socket *so, struct sockaddr *addr,
int flags, struct thread *td);
int soshutdown(struct socket *so, int how);
void sotoxsocket(struct socket *so, struct xsocket *xso);
-void soupcall_clear(struct socket *so, int which);
-void soupcall_set(struct socket *so, int which,
- int (*func)(struct socket *, void *, int), void *arg);
+void soupcall_clear(struct socket *, int);
+void soupcall_set(struct socket *, int, so_upcall_t, void *);
+void solisten_upcall_set(struct socket *, so_upcall_t, void *);
void sowakeup(struct socket *so, struct sockbuf *sb);
#ifndef __rtems__
void sowakeup_aio(struct socket *so, struct sockbuf *sb);
#else /* __rtems__ */
#define sowakeup_aio(so, sb) (void)0
#endif /* __rtems__ */
+void solisten_wakeup(struct socket *);
int selsocket(struct socket *so, int events, struct timeval *tv,
struct thread *td);
diff --git a/freebsd/sys/sys/sockopt.h b/freebsd/sys/sys/sockopt.h
index 4131a5b7..029e5b4a 100644
--- a/freebsd/sys/sys/sockopt.h
+++ b/freebsd/sys/sys/sockopt.h
@@ -64,8 +64,8 @@ int sooptcopyout(struct sockopt *sopt, const void *buf, size_t len);
int soopt_getm(struct sockopt *sopt, struct mbuf **mp);
int soopt_mcopyin(struct sockopt *sopt, struct mbuf *m);
int soopt_mcopyout(struct sockopt *sopt, struct mbuf *m);
-int do_getopt_accept_filter(struct socket *so, struct sockopt *sopt);
-int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt);
+int accept_filt_getopt(struct socket *, struct sockopt *);
+int accept_filt_setopt(struct socket *, struct sockopt *);
int so_setsockopt(struct socket *so, int level, int optname,
void *optval, size_t optlen);
diff --git a/freebsd/sys/sys/sysproto.h b/freebsd/sys/sys/sysproto.h
index 151b380b..d5cda835 100644
--- a/freebsd/sys/sys/sysproto.h
+++ b/freebsd/sys/sys/sysproto.h
@@ -1002,18 +1002,6 @@ struct getresgid_args {
struct kqueue_args {
register_t dummy;
};
-struct kevent_args {
- char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
-#ifndef __rtems__
- char changelist_l_[PADL_(struct kevent *)]; struct kevent * changelist; char changelist_r_[PADR_(struct kevent *)];
-#else /* __rtems__ */
- char changelist_l_[PADL_(struct kevent *)]; const struct kevent * changelist; char changelist_r_[PADR_(struct kevent *)];
-#endif /* __rtems__ */
- char nchanges_l_[PADL_(int)]; int nchanges; char nchanges_r_[PADR_(int)];
- char eventlist_l_[PADL_(struct kevent *)]; struct kevent * eventlist; char eventlist_r_[PADR_(struct kevent *)];
- char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
- char timeout_l_[PADL_(const struct timespec *)]; const struct timespec * timeout; char timeout_r_[PADR_(const struct timespec *)];
-};
#ifndef __rtems__
struct extattr_set_fd_args {
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
@@ -1806,6 +1794,20 @@ struct mknodat_args {
char mode_l_[PADL_(mode_t)]; mode_t mode; char mode_r_[PADR_(mode_t)];
char dev_l_[PADL_(dev_t)]; dev_t dev; char dev_r_[PADR_(dev_t)];
};
+#endif /* __rtems__ */
+struct kevent_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+#ifndef __rtems__
+ char changelist_l_[PADL_(struct kevent *)]; struct kevent * changelist; char changelist_r_[PADR_(struct kevent *)];
+#else /* __rtems__ */
+ char changelist_l_[PADL_(struct kevent *)]; const struct kevent * changelist; char changelist_r_[PADR_(struct kevent *)];
+#endif /* __rtems__ */
+ char nchanges_l_[PADL_(int)]; int nchanges; char nchanges_r_[PADR_(int)];
+ char eventlist_l_[PADL_(struct kevent *)]; struct kevent * eventlist; char eventlist_r_[PADR_(struct kevent *)];
+ char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
+ char timeout_l_[PADL_(const struct timespec *)]; const struct timespec * timeout; char timeout_r_[PADR_(const struct timespec *)];
+};
+#ifndef __rtems__
int nosys(struct thread *, struct nosys_args *);
void sys_sys_exit(struct thread *, struct sys_exit_args *);
int sys_fork(struct thread *, struct fork_args *);
@@ -2021,7 +2023,6 @@ int sys_aio_waitcomplete(struct thread *, struct aio_waitcomplete_args *);
int sys_getresuid(struct thread *, struct getresuid_args *);
int sys_getresgid(struct thread *, struct getresgid_args *);
int sys_kqueue(struct thread *, struct kqueue_args *);
-int sys_kevent(struct thread *, struct kevent_args *);
int sys_extattr_set_fd(struct thread *, struct extattr_set_fd_args *);
int sys_extattr_get_fd(struct thread *, struct extattr_get_fd_args *);
int sys_extattr_delete_fd(struct thread *, struct extattr_delete_fd_args *);
@@ -2186,6 +2187,7 @@ int sys_fstatfs(struct thread *, struct fstatfs_args *);
int sys_getfsstat(struct thread *, struct getfsstat_args *);
int sys_fhstatfs(struct thread *, struct fhstatfs_args *);
int sys_mknodat(struct thread *, struct mknodat_args *);
+int sys_kevent(struct thread *, struct kevent_args *);
#ifdef COMPAT_43
@@ -2564,6 +2566,14 @@ struct freebsd11_fhstat_args {
char u_fhp_l_[PADL_(const struct fhandle *)]; const struct fhandle * u_fhp; char u_fhp_r_[PADR_(const struct fhandle *)];
char sb_l_[PADL_(struct freebsd11_stat *)]; struct freebsd11_stat * sb; char sb_r_[PADR_(struct freebsd11_stat *)];
};
+struct freebsd11_kevent_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char changelist_l_[PADL_(struct kevent_freebsd11 *)]; struct kevent_freebsd11 * changelist; char changelist_r_[PADR_(struct kevent_freebsd11 *)];
+ char nchanges_l_[PADL_(int)]; int nchanges; char nchanges_r_[PADR_(int)];
+ char eventlist_l_[PADL_(struct kevent_freebsd11 *)]; struct kevent_freebsd11 * eventlist; char eventlist_r_[PADR_(struct kevent_freebsd11 *)];
+ char nevents_l_[PADL_(int)]; int nevents; char nevents_r_[PADR_(int)];
+ char timeout_l_[PADL_(const struct timespec *)]; const struct timespec * timeout; char timeout_r_[PADR_(const struct timespec *)];
+};
struct freebsd11_getfsstat_args {
char buf_l_[PADL_(struct freebsd11_statfs *)]; struct freebsd11_statfs * buf; char buf_r_[PADR_(struct freebsd11_statfs *)];
char bufsize_l_[PADL_(long)]; long bufsize; char bufsize_r_[PADR_(long)];
@@ -2603,6 +2613,7 @@ int freebsd11_nstat(struct thread *, struct freebsd11_nstat_args *);
int freebsd11_nfstat(struct thread *, struct freebsd11_nfstat_args *);
int freebsd11_nlstat(struct thread *, struct freebsd11_nlstat_args *);
int freebsd11_fhstat(struct thread *, struct freebsd11_fhstat_args *);
+int freebsd11_kevent(struct thread *, struct freebsd11_kevent_args *);
int freebsd11_getfsstat(struct thread *, struct freebsd11_getfsstat_args *);
int freebsd11_statfs(struct thread *, struct freebsd11_statfs_args *);
int freebsd11_fstatfs(struct thread *, struct freebsd11_fstatfs_args *);
@@ -2897,7 +2908,7 @@ int freebsd11_mknodat(struct thread *, struct freebsd11_mknodat_args *);
#define SYS_AUE_getresuid AUE_GETRESUID
#define SYS_AUE_getresgid AUE_GETRESGID
#define SYS_AUE_kqueue AUE_KQUEUE
-#define SYS_AUE_kevent AUE_KEVENT
+#define SYS_AUE_freebsd11_kevent AUE_KEVENT
#define SYS_AUE_extattr_set_fd AUE_EXTATTR_SET_FD
#define SYS_AUE_extattr_get_fd AUE_EXTATTR_GET_FD
#define SYS_AUE_extattr_delete_fd AUE_EXTATTR_DELETE_FD
@@ -3068,6 +3079,7 @@ int freebsd11_mknodat(struct thread *, struct freebsd11_mknodat_args *);
#define SYS_AUE_getfsstat AUE_GETFSSTAT
#define SYS_AUE_fhstatfs AUE_FHSTATFS
#define SYS_AUE_mknodat AUE_MKNODAT
+#define SYS_AUE_kevent AUE_KEVENT
#endif /* __rtems__ */
#undef PAD_
diff --git a/freebsd/sys/sys/systm.h b/freebsd/sys/sys/systm.h
index 6b557c56..4488c7cd 100644
--- a/freebsd/sys/sys/systm.h
+++ b/freebsd/sys/sys/systm.h
@@ -102,7 +102,7 @@ extern int vm_guest; /* Running as virtual machine guest? */
* Keep in sync with vm_guest_sysctl_names[].
*/
enum VM_GUEST { VM_GUEST_NO = 0, VM_GUEST_VM, VM_GUEST_XEN, VM_GUEST_HV,
- VM_GUEST_VMWARE, VM_GUEST_KVM, VM_LAST };
+ VM_GUEST_VMWARE, VM_GUEST_KVM, VM_GUEST_BHYVE, VM_LAST };
#if defined(WITNESS) || defined(INVARIANT_SUPPORT)
#ifndef __rtems__
diff --git a/freebsd/sys/sys/taskqueue.h b/freebsd/sys/sys/taskqueue.h
index 583f796e..7db75c6d 100644
--- a/freebsd/sys/sys/taskqueue.h
+++ b/freebsd/sys/sys/taskqueue.h
@@ -79,6 +79,9 @@ int taskqueue_start_threads_cpuset(struct taskqueue **tqp, int count,
int taskqueue_enqueue(struct taskqueue *queue, struct task *task);
int taskqueue_enqueue_timeout(struct taskqueue *queue,
struct timeout_task *timeout_task, int ticks);
+int taskqueue_enqueue_timeout_sbt(struct taskqueue *queue,
+ struct timeout_task *timeout_task, sbintime_t sbt, sbintime_t pr,
+ int flags);
int taskqueue_poll_is_busy(struct taskqueue *queue, struct task *task);
int taskqueue_cancel(struct taskqueue *queue, struct task *task,
u_int *pendp);
diff --git a/freebsd/sys/sys/unpcb.h b/freebsd/sys/sys/unpcb.h
index 619b68dd..76bc63a9 100644
--- a/freebsd/sys/sys/unpcb.h
+++ b/freebsd/sys/sys/unpcb.h
@@ -96,14 +96,8 @@ struct unpcb {
* and is really the credentials of the connected peer. This is used
* to determine whether the contents should be sent to the user or
* not.
- *
- * UNP_HAVEPCCACHED - indicates that the unp_peercred member is filled
- * in, but does *not* contain the credentials of the connected peer
- * (there may not even be a peer). This is set in unp_listen() when
- * it fills in unp_peercred for later consumption by unp_connect().
*/
#define UNP_HAVEPC 0x001
-#define UNP_HAVEPCCACHED 0x002
#define UNP_WANTCRED 0x004 /* credentials wanted */
#define UNP_CONNWAIT 0x008 /* connect blocks until accepted */
diff --git a/freebsd/sys/sys/uuid.h b/freebsd/sys/sys/uuid.h
index 0748f611..97971fd7 100644
--- a/freebsd/sys/sys/uuid.h
+++ b/freebsd/sys/sys/uuid.h
@@ -65,6 +65,7 @@ int snprintf_uuid(char *, size_t, struct uuid *);
int printf_uuid(struct uuid *);
int sbuf_printf_uuid(struct sbuf *, struct uuid *);
int parse_uuid(const char *, struct uuid *);
+int uuidcmp(const struct uuid *, const struct uuid *);
void be_uuid_dec(void const *buf, struct uuid *uuid);
void be_uuid_enc(void *buf, struct uuid const *uuid);
diff --git a/freebsd/sys/sys/vnode.h b/freebsd/sys/sys/vnode.h
index 8f123d5e..61cbf000 100644
--- a/freebsd/sys/sys/vnode.h
+++ b/freebsd/sys/sys/vnode.h
@@ -113,14 +113,13 @@ struct vnode {
/*
* Type specific fields, only one applies to any given vnode.
- * See #defines below for renaming to v_* namespace.
*/
union {
- struct mount *vu_mount; /* v ptr to mountpoint (VDIR) */
- struct socket *vu_socket; /* v unix domain net (VSOCK) */
- struct cdev *vu_cdev; /* v device (VCHR, VBLK) */
- struct fifoinfo *vu_fifoinfo; /* v fifo (VFIFO) */
- } v_un;
+ struct mount *v_mountedhere; /* v ptr to mountpoint (VDIR) */
+ struct unpcb *v_unpcb; /* v unix domain net (VSOCK) */
+ struct cdev *v_rdev; /* v device (VCHR, VBLK) */
+ struct fifoinfo *v_fifoinfo; /* v fifo (VFIFO) */
+ };
/*
* vfs_hash: (mount + inode) -> vnode hash. The hash value
@@ -176,11 +175,6 @@ struct vnode {
#endif /* defined(_KERNEL) || defined(_KVM_VNODE) */
-#define v_mountedhere v_un.vu_mount
-#define v_socket v_un.vu_socket
-#define v_rdev v_un.vu_cdev
-#define v_fifoinfo v_un.vu_fifoinfo
-
#define bo2vnode(bo) __containerof((bo), struct vnode, v_bufobj)
/* XXX: These are temporary to avoid a source sweep at this time */
@@ -201,7 +195,7 @@ struct xvnode {
long xv_numoutput; /* num of writes in progress */
enum vtype xv_type; /* vnode type */
union {
- void *xvu_socket; /* socket, if VSOCK */
+ void *xvu_socket; /* unpcb, if VSOCK */
void *xvu_fifo; /* fifo, if VFIFO */
dev_t xvu_rdev; /* maj/min, if VBLK/VCHR */
struct {
@@ -617,7 +611,7 @@ void cache_purgevfs(struct mount *mp, bool force);
int change_dir(struct vnode *vp, struct thread *td);
void cvtstat(struct stat *st, struct ostat *ost);
void freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb);
-void freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost);
+int freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost);
int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
struct vnode **vpp);
void getnewvnode_reserve(u_int count);
diff --git a/freebsd/sys/vm/uma_core.c b/freebsd/sys/vm/uma_core.c
index c69faea9..011f6494 100644
--- a/freebsd/sys/vm/uma_core.c
+++ b/freebsd/sys/vm/uma_core.c
@@ -52,13 +52,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-/* I should really use ktr.. */
-/*
-#define UMA_DEBUG 1
-#define UMA_DEBUG_ALLOC 1
-#define UMA_DEBUG_ALLOC_1 1
-*/
-
#include <rtems/bsd/local/opt_ddb.h>
#include <rtems/bsd/local/opt_param.h>
#include <rtems/bsd/local/opt_vm.h>
@@ -162,12 +155,15 @@ static LIST_HEAD(,uma_zone) uma_cachezones =
static struct rwlock_padalign uma_rwlock;
#ifndef __rtems__
-/* Linked list of boot time pages */
-static LIST_HEAD(,uma_slab) uma_boot_pages =
- LIST_HEAD_INITIALIZER(uma_boot_pages);
-
-/* This mutex protects the boot time pages list */
-static struct mtx_padalign uma_boot_pages_mtx;
+/*
+ * Pointer and counter to pool of pages, that is preallocated at
+ * startup to bootstrap UMA. Early zones continue to use the pool
+ * until it is depleted, so allocations may happen after boot, thus
+ * we need a mutex to protect it.
+ */
+static char *bootmem;
+static int boot_pages;
+static struct mtx uma_boot_pages_mtx;
#endif /* __rtems__ */
static struct sx uma_drain_lock;
@@ -862,6 +858,9 @@ keg_free_slab(uma_keg_t keg, uma_slab_t slab, int start)
int i;
uint8_t flags;
+ CTR4(KTR_UMA, "keg_free_slab keg %s(%p) slab %p, returning %d bytes",
+ keg->uk_name, keg, slab, PAGE_SIZE * keg->uk_ppera);
+
mem = slab->us_data;
flags = slab->us_flags;
i = start;
@@ -872,10 +871,6 @@ keg_free_slab(uma_keg_t keg, uma_slab_t slab, int start)
}
if (keg->uk_flags & UMA_ZONE_OFFPAGE)
zone_free_item(keg->uk_slabzone, slab, NULL, SKIP_NONE);
-#ifdef UMA_DEBUG
- printf("%s: Returning %d bytes.\n", keg->uk_name,
- PAGE_SIZE * keg->uk_ppera);
-#endif
keg->uk_freef(mem, PAGE_SIZE * keg->uk_ppera, flags);
}
@@ -898,9 +893,8 @@ keg_drain(uma_keg_t keg)
if (keg->uk_flags & UMA_ZONE_NOFREE || keg->uk_freef == NULL)
return;
-#ifdef UMA_DEBUG
- printf("%s free items: %u\n", keg->uk_name, keg->uk_free);
-#endif
+ CTR3(KTR_UMA, "keg_drain %s(%p) free items: %u",
+ keg->uk_name, keg, keg->uk_free);
KEG_LOCK(keg);
if (keg->uk_free == 0)
goto finished;
@@ -992,9 +986,6 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int wait)
slab = NULL;
mem = NULL;
-#ifdef UMA_DEBUG
- printf("alloc_slab: Allocating a new slab for %s\n", keg->uk_name);
-#endif
allocf = keg->uk_allocf;
KEG_UNLOCK(keg);
@@ -1059,6 +1050,9 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int wait)
out:
KEG_LOCK(keg);
+ CTR3(KTR_UMA, "keg_alloc_slab: allocated slab %p for %s(%p)",
+ slab, keg->uk_name, keg);
+
if (slab != NULL) {
if (keg->uk_flags & UMA_ZONE_HASH)
UMA_HASH_INSERT(&keg->uk_hash, slab, mem);
@@ -1080,36 +1074,24 @@ static void *
startup_alloc(uma_zone_t zone, vm_size_t bytes, uint8_t *pflag, int wait)
{
uma_keg_t keg;
- uma_slab_t tmps;
- int pages, check_pages;
+ void *mem;
+ int pages;
keg = zone_first_keg(zone);
pages = howmany(bytes, PAGE_SIZE);
- check_pages = pages - 1;
KASSERT(pages > 0, ("startup_alloc can't reserve 0 pages\n"));
/*
* Check our small startup cache to see if it has pages remaining.
*/
mtx_lock(&uma_boot_pages_mtx);
-
- /* First check if we have enough room. */
- tmps = LIST_FIRST(&uma_boot_pages);
- while (tmps != NULL && check_pages-- > 0)
- tmps = LIST_NEXT(tmps, us_link);
- if (tmps != NULL) {
- /*
- * It's ok to lose tmps references. The last one will
- * have tmps->us_data pointing to the start address of
- * "pages" contiguous pages of memory.
- */
- while (pages-- > 0) {
- tmps = LIST_FIRST(&uma_boot_pages);
- LIST_REMOVE(tmps, us_link);
- }
+ if (pages <= boot_pages) {
+ mem = bootmem;
+ boot_pages -= pages;
+ bootmem += pages * PAGE_SIZE;
mtx_unlock(&uma_boot_pages_mtx);
- *pflag = tmps->us_flags;
- return (tmps->us_data);
+ *pflag = UMA_SLAB_BOOT;
+ return (mem);
}
mtx_unlock(&uma_boot_pages_mtx);
if (booted < UMA_STARTUP2)
@@ -1344,15 +1326,13 @@ keg_small_init(uma_keg_t keg)
keg->uk_ipers = slabsize / keg->uk_rsize;
KASSERT(keg->uk_ipers > 0 && keg->uk_ipers <= SLAB_SETSIZE,
("%s: keg->uk_ipers %u", __func__, keg->uk_ipers));
-#ifdef UMA_DEBUG
- printf("UMA decided we need offpage slab headers for "
- "keg: %s, calculated wastedspace = %d, "
+ CTR6(KTR_UMA, "UMA decided we need offpage slab headers for "
+ "keg: %s(%p), calculated wastedspace = %d, "
"maximum wasted space allowed = %d, "
"calculated ipers = %d, "
- "new wasted space = %d\n", keg->uk_name, wastedspace,
+ "new wasted space = %d\n", keg->uk_name, keg, wastedspace,
slabsize / UMA_MAX_WASTE, keg->uk_ipers,
slabsize - keg->uk_ipers * keg->uk_rsize);
-#endif
keg->uk_flags |= UMA_ZONE_OFFPAGE;
}
@@ -1465,8 +1445,6 @@ keg_ctor(void *mem, int size, void *udata, int flags)
keg->uk_reserve = 0;
keg->uk_pages = 0;
keg->uk_flags = arg->flags;
- keg->uk_allocf = page_alloc;
- keg->uk_freef = page_free;
keg->uk_slabzone = NULL;
/*
@@ -1503,32 +1481,28 @@ keg_ctor(void *mem, int size, void *udata, int flags)
if (keg->uk_flags & UMA_ZONE_OFFPAGE)
keg->uk_slabzone = slabzone;
+#ifndef __rtems__
/*
* If we haven't booted yet we need allocations to go through the
* startup cache until the vm is ready.
*/
- if (keg->uk_ppera == 1) {
+ if (booted < UMA_STARTUP2)
+ keg->uk_allocf = startup_alloc;
#ifdef UMA_MD_SMALL_ALLOC
+ else if (keg->uk_ppera == 1)
keg->uk_allocf = uma_small_alloc;
- keg->uk_freef = uma_small_free;
-
-#ifndef __rtems__
- if (booted < UMA_STARTUP)
- keg->uk_allocf = startup_alloc;
+#endif
+ else
#endif /* __rtems__ */
-#else
+ keg->uk_allocf = page_alloc;
#ifndef __rtems__
- if (booted < UMA_STARTUP2)
- keg->uk_allocf = startup_alloc;
-#endif /* __rtems__ */
+#ifdef UMA_MD_SMALL_ALLOC
+ if (keg->uk_ppera == 1)
+ keg->uk_freef = uma_small_free;
+ else
#endif
-#ifndef __rtems__
- } else if (booted < UMA_STARTUP2 &&
- (keg->uk_flags & UMA_ZFLAG_INTERNAL))
- keg->uk_allocf = startup_alloc;
-#else /* __rtems__ */
- }
#endif /* __rtems__ */
+ keg->uk_freef = page_free;
/*
* Initialize keg's lock
@@ -1570,13 +1544,10 @@ keg_ctor(void *mem, int size, void *udata, int flags)
if (keg->uk_flags & UMA_ZONE_HASH)
hash_alloc(&keg->uk_hash);
-#ifdef UMA_DEBUG
- printf("UMA: %s(%p) size %d(%d) flags %#x ipers %d ppera %d out %d free %d\n",
- zone->uz_name, zone, keg->uk_size, keg->uk_rsize, keg->uk_flags,
- keg->uk_ipers, keg->uk_ppera,
+ CTR5(KTR_UMA, "keg_ctor %p zone %s(%p) out %d free %d\n",
+ keg, zone->uz_name, zone,
(keg->uk_pages / keg->uk_ppera) * keg->uk_ipers - keg->uk_free,
keg->uk_free);
-#endif
LIST_INSERT_HEAD(&keg->uk_zones, zone, uz_link);
@@ -1817,17 +1788,10 @@ zone_foreach(void (*zfunc)(uma_zone_t))
/* Public functions */
/* See uma.h */
void
-uma_startup(void *bootmem, int boot_pages)
+uma_startup(void *mem, int npages)
{
struct uma_zctor_args args;
-#ifndef __rtems__
- uma_slab_t slab;
- int i;
-#endif /* __rtems__ */
-#ifdef UMA_DEBUG
- printf("Creating uma keg headers zone and keg.\n");
-#endif
rw_init(&uma_rwlock, "UMA lock");
/* "manually" create the initial zone */
@@ -1845,21 +1809,11 @@ uma_startup(void *bootmem, int boot_pages)
zone_ctor(kegs, sizeof(struct uma_zone), &args, M_WAITOK);
#ifndef __rtems__
-#ifdef UMA_DEBUG
- printf("Filling boot free list.\n");
-#endif
- for (i = 0; i < boot_pages; i++) {
- slab = (uma_slab_t)((uint8_t *)bootmem + (i * UMA_SLAB_SIZE));
- slab->us_data = (uint8_t *)slab;
- slab->us_flags = UMA_SLAB_BOOT;
- LIST_INSERT_HEAD(&uma_boot_pages, slab, us_link);
- }
mtx_init(&uma_boot_pages_mtx, "UMA boot pages", NULL, MTX_DEF);
+ bootmem = mem;
+ boot_pages = npages;
#endif /* __rtems__ */
-#ifdef UMA_DEBUG
- printf("Creating uma zone headers zone and keg.\n");
-#endif
args.name = "UMA Zones";
args.size = sizeof(struct uma_zone) +
(sizeof(struct uma_cache) * (mp_maxid + 1));
@@ -1873,10 +1827,6 @@ uma_startup(void *bootmem, int boot_pages)
/* The initial zone has no Per cpu queues so it's smaller */
zone_ctor(zones, sizeof(struct uma_zone), &args, M_WAITOK);
-#ifdef UMA_DEBUG
- printf("Creating slab and hash zones.\n");
-#endif
-
/* Now make a zone for slab headers */
slabzone = uma_zcreate("UMA Slabs",
sizeof(struct uma_slab),
@@ -1893,10 +1843,6 @@ uma_startup(void *bootmem, int boot_pages)
#ifndef __rtems__
booted = UMA_STARTUP;
#endif /* __rtems__ */
-
-#ifdef UMA_DEBUG
- printf("UMA startup complete.\n");
-#endif
}
#ifdef __rtems__
static void
@@ -1920,9 +1866,6 @@ uma_startup2(void)
booted = UMA_STARTUP2;
bucket_enable();
sx_init(&uma_drain_lock, "umadrain");
-#ifdef UMA_DEBUG
- printf("UMA startup2 complete.\n");
-#endif
}
#endif /* __rtems__ */
@@ -1934,14 +1877,9 @@ uma_startup2(void)
static void
uma_startup3(void)
{
-#ifdef UMA_DEBUG
- printf("Starting callout.\n");
-#endif
+
callout_init(&uma_callout, 1);
callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL);
-#ifdef UMA_DEBUG
- printf("UMA startup3 complete.\n");
-#endif
}
static uma_keg_t
@@ -2199,11 +2137,8 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
random_harvest_fast_uma(&zone, sizeof(zone), 1, RANDOM_UMA);
/* This is the fast path allocation */
-#ifdef UMA_DEBUG_ALLOC_1
- printf("Allocating one item from %s(%p)\n", zone->uz_name, zone);
-#endif
- CTR3(KTR_UMA, "uma_zalloc_arg thread %x zone %s flags %d", curthread,
- zone->uz_name, flags);
+ CTR4(KTR_UMA, "uma_zalloc_arg thread %x zone %s(%p) flags %d",
+ curthread, zone->uz_name, zone, flags);
if (flags & M_WAITOK) {
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
@@ -2278,9 +2213,9 @@ zalloc_start:
*/
bucket = cache->uc_freebucket;
if (bucket != NULL && bucket->ub_cnt > 0) {
-#ifdef UMA_DEBUG_ALLOC
- printf("uma_zalloc: Swapping empty with alloc.\n");
-#endif
+ CTR2(KTR_UMA,
+ "uma_zalloc: zone %s(%p) swapping empty with alloc",
+ zone->uz_name, zone);
cache->uc_freebucket = cache->uc_allocbucket;
cache->uc_allocbucket = bucket;
goto zalloc_start;
@@ -2361,6 +2296,8 @@ zalloc_start:
* will use the just filled bucket.
*/
bucket = zone_alloc_bucket(zone, udata, flags);
+ CTR3(KTR_UMA, "uma_zalloc: zone %s(%p) bucket zone returned %p",
+ zone->uz_name, zone, bucket);
if (bucket != NULL) {
ZONE_LOCK(zone);
critical_enter();
@@ -2382,10 +2319,6 @@ zalloc_start:
/*
* We may not be able to get a bucket so return an actual item.
*/
-#ifdef UMA_DEBUG
- printf("uma_zalloc_arg: Bucketzone returned NULL\n");
-#endif
-
zalloc_item:
item = zone_alloc_item(zone, udata, flags);
@@ -2693,9 +2626,6 @@ zone_alloc_item(uma_zone_t zone, void *udata, int flags)
item = NULL;
-#ifdef UMA_DEBUG_ALLOC
- printf("INTERNAL: Allocating one item from %s(%p)\n", zone->uz_name, zone);
-#endif
if (zone->uz_import(zone->uz_arg, &item, 1, flags) != 1)
goto fail;
atomic_add_long(&zone->uz_allocs, 1);
@@ -2724,9 +2654,14 @@ zone_alloc_item(uma_zone_t zone, void *udata, int flags)
if (flags & M_ZERO)
uma_zero_item(item, zone);
+ CTR3(KTR_UMA, "zone_alloc_item item %p from %s(%p)", item,
+ zone->uz_name, zone);
+
return (item);
fail:
+ CTR2(KTR_UMA, "zone_alloc_item failed from %s(%p)",
+ zone->uz_name, zone);
atomic_add_long(&zone->uz_fails, 1);
return (NULL);
}
@@ -2743,9 +2678,6 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata)
/* Enable entropy collection for RANDOM_ENABLE_UMA kernel option */
random_harvest_fast_uma(&zone, sizeof(zone), 1, RANDOM_UMA);
-#ifdef UMA_DEBUG_ALLOC_1
- printf("Freeing item %p to %s(%p)\n", item, zone->uz_name, zone);
-#endif
CTR2(KTR_UMA, "uma_zfree_arg thread %x zone %s", curthread,
zone->uz_name);
@@ -2859,9 +2791,9 @@ zfree_start:
/* Can we throw this on the zone full list? */
if (bucket != NULL) {
-#ifdef UMA_DEBUG_ALLOC
- printf("uma_zfree: Putting old bucket on the free list.\n");
-#endif
+ CTR3(KTR_UMA,
+ "uma_zfree: zone %s(%p) putting bucket %p on free list",
+ zone->uz_name, zone, bucket);
/* ub_cnt is pointing to the last free item */
KASSERT(bucket->ub_cnt != 0,
("uma_zfree: Attempting to insert an empty bucket onto the full list.\n"));
@@ -2876,10 +2808,9 @@ zfree_start:
zone->uz_count++;
ZONE_UNLOCK(zone);
-#ifdef UMA_DEBUG_ALLOC
- printf("uma_zfree: Allocating new free bucket.\n");
-#endif
bucket = bucket_alloc(zone, udata, M_NOWAIT);
+ CTR3(KTR_UMA, "uma_zfree: zone %s(%p) allocated bucket %p",
+ zone->uz_name, zone, bucket);
if (bucket) {
critical_enter();
cpu = curcpu;
@@ -3281,9 +3212,7 @@ static void
uma_reclaim_locked(bool kmem_danger)
{
-#ifdef UMA_DEBUG
- printf("UMA: vm asked us to release pages!\n");
-#endif
+ CTR0(KTR_UMA, "UMA: vm asked us to release pages!");
sx_assert(&uma_drain_lock, SA_XLOCKED);
bucket_enable();
zone_foreach(zone_drain);
diff --git a/freebsd/sys/vm/vm.h b/freebsd/sys/vm/vm.h
index a41bc0b1..d0945a3d 100644
--- a/freebsd/sys/vm/vm.h
+++ b/freebsd/sys/vm/vm.h
@@ -78,6 +78,7 @@ typedef u_char vm_prot_t; /* protection codes */
#define VM_PROT_WRITE ((vm_prot_t) 0x02)
#define VM_PROT_EXECUTE ((vm_prot_t) 0x04)
#define VM_PROT_COPY ((vm_prot_t) 0x08) /* copy-on-read */
+#define VM_PROT_FAULT_LOOKUP ((vm_prot_t) 0x010)
#define VM_PROT_ALL (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)
#define VM_PROT_RW (VM_PROT_READ|VM_PROT_WRITE)
diff --git a/freebsd/usr.bin/netstat/flowtable.c b/freebsd/usr.bin/netstat/flowtable.c
deleted file mode 100644
index 2b1f2975..00000000
--- a/freebsd/usr.bin/netstat/flowtable.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <machine/rtems-bsd-user-space.h>
-
-#ifdef __rtems__
-#include "rtems-bsd-netstat-namespace.h"
-#endif /* __rtems__ */
-
-/*-
- * Copyright (c) 2014 Gleb Smirnoff <glebius@FreeBSD.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 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.
- */
-
-#ifdef __rtems__
-#include <machine/rtems-bsd-program.h>
-#endif /* __rtems__ */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-
-#include <net/flowtable.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdbool.h>
-
-#include "netstat.h"
-#ifdef __rtems__
-#include "rtems-bsd-netstat-flowtable-data.h"
-#endif /* __rtems__ */
-
-/*
- * Print flowtable statistics.
- */
-
-static void
-print_stats(struct flowtable_stat *stat)
-{
-
-#define p(f, m) if (stat->f || sflag <= 1) \
- printf(m, (uintmax_t)stat->f, plural(stat->f))
-#define p2(f, m) if (stat->f || sflag <= 1) \
- printf(m, (uintmax_t)stat->f, plurales(stat->f))
-
- p(ft_lookups, "\t%ju lookup%s\n");
- p(ft_hits, "\t%ju hit%s\n");
- p2(ft_misses, "\t%ju miss%s\n");
- p(ft_inserts, "\t%ju insert%s\n");
- p(ft_collisions, "\t%ju collision%s\n");
- p(ft_free_checks, "\t%ju free check%s\n");
- p(ft_frees, "\t%ju free%s\n");
- p(ft_fail_lle_invalid,
- "\t%ju lookup%s with not resolved Layer 2 address\n");
-
-#undef p2
-#undef p
-}
-
-void
-flowtable_stats(void)
-{
- struct flowtable_stat stat;
-
- if (!live)
- return;
-
- if (fetch_stats("net.flowtable.ip4.stat", 0, &stat,
- sizeof(stat), NULL) == 0) {
- printf("flowtable for IPv4:\n");
- print_stats(&stat);
- }
-
- if (fetch_stats("net.flowtable.ip6.stat", 0, &stat,
- sizeof(stat), NULL) == 0) {
- printf("flowtable for IPv6:\n");
- print_stats(&stat);
- }
-}
diff --git a/freebsd/usr.bin/netstat/inet.c b/freebsd/usr.bin/netstat/inet.c
index 299eee3d..05d5f2c3 100644
--- a/freebsd/usr.bin/netstat/inet.c
+++ b/freebsd/usr.bin/netstat/inet.c
@@ -182,14 +182,17 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
if (kread((uintptr_t)proto.pr_domain, &domain, sizeof(domain)) != 0)
return (-1);
xso->xso_family = domain.dom_family;
- xso->so_qlen = so->so_qlen;
- xso->so_incqlen = so->so_incqlen;
- xso->so_qlimit = so->so_qlimit;
xso->so_timeo = so->so_timeo;
xso->so_error = so->so_error;
- xso->so_oobmark = so->so_oobmark;
- sbtoxsockbuf(&so->so_snd, &xso->so_snd);
- sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
+ if (SOLISTENING(so)) {
+ xso->so_qlen = so->sol_qlen;
+ xso->so_incqlen = so->sol_incqlen;
+ xso->so_qlimit = so->sol_qlimit;
+ } else {
+ sbtoxsockbuf(&so->so_snd, &xso->so_snd);
+ sbtoxsockbuf(&so->so_rcv, &xso->so_rcv);
+ xso->so_oobmark = so->so_oobmark;
+ }
return (0);
}
diff --git a/freebsd/usr.bin/netstat/main.c b/freebsd/usr.bin/netstat/main.c
index 24fc3442..3cf39d1c 100644
--- a/freebsd/usr.bin/netstat/main.c
+++ b/freebsd/usr.bin/netstat/main.c
@@ -575,7 +575,6 @@ main(int argc, char *argv[])
xo_open_container("statistics");
if (sflag) {
rt_stats();
- flowtable_stats();
} else
routepr(fib, af);
xo_close_container("statistics");
diff --git a/freebsd/usr.bin/netstat/netstat.h b/freebsd/usr.bin/netstat/netstat.h
index 776c09e7..d6402987 100644
--- a/freebsd/usr.bin/netstat/netstat.h
+++ b/freebsd/usr.bin/netstat/netstat.h
@@ -140,7 +140,6 @@ void intpr(void (*)(char *), int);
void pr_family(int);
void rt_stats(void);
-void flowtable_stats(void);
char *routename(struct sockaddr *, int);
const char *netname(struct sockaddr *, struct sockaddr *);
diff --git a/freebsd/usr.bin/netstat/rtems-bsd-netstat-data.h b/freebsd/usr.bin/netstat/rtems-bsd-netstat-data.h
index 675a2c71..f1a44d99 100644
--- a/freebsd/usr.bin/netstat/rtems-bsd-netstat-data.h
+++ b/freebsd/usr.bin/netstat/rtems-bsd-netstat-data.h
@@ -1,7 +1,6 @@
/* generated by userspace-header-gen.py */
#include <rtems/linkersets.h>
/* bpf.c */
-/* flowtable.c */
/* if.c */
/* inet6.c */
/* inet.c */
diff --git a/freebsd/usr.bin/netstat/rtems-bsd-netstat-namespace.h b/freebsd/usr.bin/netstat/rtems-bsd-netstat-namespace.h
index 64c3c52a..7a938bc0 100644
--- a/freebsd/usr.bin/netstat/rtems-bsd-netstat-namespace.h
+++ b/freebsd/usr.bin/netstat/rtems-bsd-netstat-namespace.h
@@ -1,8 +1,6 @@
/* generated by userspace-header-gen.py */
/* bpf.c */
#define bpf_stats _bsd_netstat_bpf_stats
-/* flowtable.c */
-#define flowtable_stats _bsd_netstat_flowtable_stats
/* if.c */
#define intpr _bsd_netstat_intpr
/* inet6.c */
diff --git a/libbsd.py b/libbsd.py
index 6f413855..ad97f48b 100644
--- a/libbsd.py
+++ b/libbsd.py
@@ -549,6 +549,7 @@ class fdt(builder.Module):
'sys/sys/slicer.h',
'sys/dev/fdt/fdt_common.h',
'sys/dev/fdt/simplebus.h',
+ 'sys/dev/mii/mii_fdt.h',
'sys/dev/ofw/ofw_bus.h',
'sys/dev/ofw/ofw_bus_subr.h',
'sys/dev/ofw/ofw_subr.h',
@@ -561,6 +562,7 @@ class fdt(builder.Module):
[
'sys/dev/fdt/simplebus.c',
'sys/dev/fdt/fdt_common.c',
+ 'sys/dev/mii/mii_fdt.c',
'sys/dev/ofw/ofwbus.c',
'sys/dev/ofw/openfirm.c',
'sys/dev/ofw/ofw_fdt.c',
@@ -1304,19 +1306,23 @@ class cam(builder.Module):
mm = self.manager
self.addKernelSpaceHeaderFiles(
[
- 'sys/dev/nvme/nvme.h',
- 'sys/sys/ata.h',
- 'sys/cam/cam.h',
+ 'sys/cam/ata/ata_all.h',
'sys/cam/cam_ccb.h',
+ 'sys/cam/cam_debug.h',
+ 'sys/cam/cam.h',
+ 'sys/cam/cam_periph.h',
'sys/cam/cam_sim.h',
+ 'sys/cam/cam_xpt.h',
'sys/cam/cam_xpt_sim.h',
+ 'sys/cam/mmc/mmc_all.h',
+ 'sys/cam/mmc/mmc_bus.h',
+ 'sys/cam/mmc/mmc.h',
+ 'sys/cam/mmc/mmc_sdio.h',
'sys/cam/nvme/nvme_all.h',
'sys/cam/scsi/scsi_all.h',
'sys/cam/scsi/scsi_da.h',
- 'sys/cam/ata/ata_all.h',
- 'sys/cam/cam_periph.h',
- 'sys/cam/cam_debug.h',
- 'sys/cam/cam_xpt.h',
+ 'sys/dev/nvme/nvme.h',
+ 'sys/sys/ata.h',
]
)
self.addKernelSpaceSourceFiles(
@@ -1339,15 +1345,26 @@ class dev_net(builder.Module):
mm = self.manager
self.addKernelSpaceHeaderFiles(
[
+ 'sys/arm/lpc/if_lpereg.h',
+ 'sys/arm/lpc/lpcreg.h',
+ 'sys/arm/lpc/lpcvar.h',
+ 'sys/arm/xilinx/zy7_slcr.h',
+ 'sys/dev/cadence/if_cgem_hw.h',
+ 'sys/dev/dwc/if_dwc.h',
+ 'sys/dev/dwc/if_dwcvar.h',
'sys/dev/ffec/if_ffecreg.h',
- 'sys/dev/mii/mii.h',
- 'sys/dev/mii/mii_bitbang.h',
- 'sys/dev/mii/miivar.h',
+ 'sys/dev/led/led.h',
'sys/dev/mii/brgphyreg.h',
'sys/dev/mii/e1000phyreg.h',
'sys/dev/mii/icsphyreg.h',
+ 'sys/dev/mii/mii_bitbang.h',
+ 'sys/dev/mii/mii_fdt.h',
+ 'sys/dev/mii/mii.h',
+ 'sys/dev/mii/miivar.h',
'sys/dev/mii/rgephyreg.h',
- 'sys/dev/led/led.h',
+ 'sys/dev/ofw/openfirm.h',
+ 'sys/dev/tsec/if_tsec.h',
+ 'sys/dev/tsec/if_tsecreg.h',
'sys/net/bpf.h',
'sys/net/dlt.h',
'sys/net/ethernet.h',
@@ -1359,16 +1376,6 @@ class dev_net(builder.Module):
'sys/net/if_types.h',
'sys/net/if_var.h',
'sys/net/vnet.h',
- 'sys/dev/ofw/openfirm.h',
- 'sys/dev/tsec/if_tsec.h',
- 'sys/dev/tsec/if_tsecreg.h',
- 'sys/dev/cadence/if_cgem_hw.h',
- 'sys/dev/dwc/if_dwc.h',
- 'sys/dev/dwc/if_dwcvar.h',
- 'sys/arm/xilinx/zy7_slcr.h',
- 'sys/arm/lpc/if_lpereg.h',
- 'sys/arm/lpc/lpcreg.h',
- 'sys/arm/lpc/lpcvar.h',
]
)
self.addKernelSpaceSourceFiles(
@@ -1643,7 +1650,6 @@ class net(builder.Module):
'sys/net/ethernet.h',
'sys/net/fddi.h',
'sys/net/firewire.h',
- 'sys/net/flowtable.h',
'sys/net/ieee8023ad_lacp.h',
'sys/net/if_arc.h',
'sys/net/if_arp.h',
@@ -2877,7 +2883,6 @@ class user_space(builder.Module):
'sbin/route/route.c',
'sbin/sysctl/sysctl.c',
'usr.bin/netstat/bpf.c',
- 'usr.bin/netstat/flowtable.c',
'usr.bin/netstat/if.c',
'usr.bin/netstat/inet6.c',
'usr.bin/netstat/inet.c',
diff --git a/rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h b/rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h
index 028d3742..9eaed1f1 100644
--- a/rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h
+++ b/rtemsbsd/include/machine/rtems-bsd-kernel-namespace.h
@@ -6,6 +6,8 @@
#define accept_filt_del _bsd_accept_filt_del
#define accept_filt_generic_mod_event _bsd_accept_filt_generic_mod_event
#define accept_filt_get _bsd_accept_filt_get
+#define accept_filt_getopt _bsd_accept_filt_getopt
+#define accept_filt_setopt _bsd_accept_filt_setopt
#define accept_mtx _bsd_accept_mtx
#define AddFragmentPtrLink _bsd_AddFragmentPtrLink
#define AddLink _bsd_AddLink
@@ -308,6 +310,7 @@
#define BF_set_key _bsd_BF_set_key
#define bin2bcd_data _bsd_bin2bcd_data
#define blist_alloc _bsd_blist_alloc
+#define blist_avail _bsd_blist_avail
#define blist_create _bsd_blist_create
#define blist_destroy _bsd_blist_destroy
#define blist_fill _bsd_blist_fill
@@ -387,8 +390,8 @@
#define bus_dmamap_load_buffer _bsd_bus_dmamap_load_buffer
#define bus_dmamap_load_mbuf _bsd_bus_dmamap_load_mbuf
#define bus_dmamap_load_mbuf_sg _bsd_bus_dmamap_load_mbuf_sg
-#define _bus_dmamap_sync _bsd__bus_dmamap_sync
-#define _bus_dmamap_unload _bsd__bus_dmamap_unload
+#define bus_dmamap_sync _bsd_bus_dmamap_sync
+#define bus_dmamap_unload _bsd_bus_dmamap_unload
#define bus_dmamem_alloc _bsd_bus_dmamem_alloc
#define bus_dmamem_free _bsd_bus_dmamem_free
#define bus_dma_tag_create _bsd_bus_dma_tag_create
@@ -703,12 +706,10 @@
#define DifferentialChecksum _bsd_DifferentialChecksum
#define div_protosw _bsd_div_protosw
#define div_usrreqs _bsd_div_usrreqs
-#define do_getopt_accept_filter _bsd_do_getopt_accept_filter
#define domain_add _bsd_domain_add
#define domain_init _bsd_domain_init
#define domain_init_status _bsd_domain_init_status
#define domains _bsd_domains
-#define do_setopt_accept_filter _bsd_do_setopt_accept_filter
#define drbr_dequeue_drv _bsd_drbr_dequeue_drv
#define drbr_enqueue_drv _bsd_drbr_enqueue_drv
#define drbr_inuse_drv _bsd_drbr_inuse_drv
@@ -2639,6 +2640,11 @@
#define miibus_driver _bsd_miibus_driver
#define mii_dev_mac_match _bsd_mii_dev_mac_match
#define mii_dev_mac_softc _bsd_mii_dev_mac_softc
+#define mii_fdt_contype_from_name _bsd_mii_fdt_contype_from_name
+#define mii_fdt_contype_to_name _bsd_mii_fdt_contype_to_name
+#define mii_fdt_free_config _bsd_mii_fdt_free_config
+#define mii_fdt_get_config _bsd_mii_fdt_get_config
+#define mii_fdt_get_contype _bsd_mii_fdt_get_contype
#define mii_mediachg _bsd_mii_mediachg
#define mii_oui _bsd_mii_oui
#define mii_phy_add_media _bsd_mii_phy_add_media
@@ -3565,6 +3571,8 @@
#define read_machclk _bsd_read_machclk
#define registered_toedevs _bsd_registered_toedevs
#define register_tcp_functions _bsd_register_tcp_functions
+#define register_tcp_functions_as_name _bsd_register_tcp_functions_as_name
+#define register_tcp_functions_as_names _bsd_register_tcp_functions_as_names
#define resource_disabled _bsd_resource_disabled
#define resource_find_match _bsd_resource_find_match
#define resource_int_value _bsd_resource_int_value
@@ -3839,8 +3847,8 @@
#define sbrelease _bsd_sbrelease
#define sbrelease_internal _bsd_sbrelease_internal
#define sbrelease_locked _bsd_sbrelease_locked
-#define sbreserve _bsd_sbreserve
#define sbreserve_locked _bsd_sbreserve_locked
+#define sbsetopt _bsd_sbsetopt
#define sbsndmbuf _bsd_sbsndmbuf
#define sbsndptr _bsd_sbsndptr
#define sbtoxsockbuf _bsd_sbtoxsockbuf
@@ -4279,9 +4287,11 @@
#define sdhci_generic_release_host _bsd_sdhci_generic_release_host
#define sdhci_generic_request _bsd_sdhci_generic_request
#define sdhci_generic_resume _bsd_sdhci_generic_resume
+#define sdhci_generic_retune _bsd_sdhci_generic_retune
#define sdhci_generic_set_uhs_timing _bsd_sdhci_generic_set_uhs_timing
#define sdhci_generic_suspend _bsd_sdhci_generic_suspend
#define sdhci_generic_switch_vccq _bsd_sdhci_generic_switch_vccq
+#define sdhci_generic_tune _bsd_sdhci_generic_tune
#define sdhci_generic_update_ios _bsd_sdhci_generic_update_ios
#define sdhci_generic_write_ivar _bsd_sdhci_generic_write_ivar
#define sdhci_handle_card_present _bsd_sdhci_handle_card_present
@@ -4425,9 +4435,11 @@
#define so_linger_get _bsd_so_linger_get
#define so_linger_set _bsd_so_linger_set
#define solisten _bsd_solisten
-#define so_listeners_apply_all _bsd_so_listeners_apply_all
+#define solisten_dequeue _bsd_solisten_dequeue
#define solisten_proto _bsd_solisten_proto
#define solisten_proto_check _bsd_solisten_proto_check
+#define solisten_upcall_set _bsd_solisten_upcall_set
+#define solisten_wakeup _bsd_solisten_wakeup
#define so_lock _bsd_so_lock
#define sonewconn _bsd_sonewconn
#define soo_close _bsd_soo_close
@@ -4745,6 +4757,7 @@
#define tcp_sack_output _bsd_tcp_sack_output
#define tcp_sack_partialack _bsd_tcp_sack_partialack
#define tcp_sc_rst_sock_fail _bsd_tcp_sc_rst_sock_fail
+#define tcp_sendbuf_auto_lowat _bsd_tcp_sendbuf_auto_lowat
#define tcp_sendspace _bsd_tcp_sendspace
#define tcp_setpersist _bsd_tcp_setpersist
#define tcp_slowtimo _bsd_tcp_slowtimo
@@ -5244,6 +5257,7 @@
#define usb_test_quirk_p _bsd_usb_test_quirk_p
#define usb_trim_spaces _bsd_usb_trim_spaces
#define usb_ugen_methods _bsd_usb_ugen_methods
+#define uuidcmp _bsd_uuidcmp
#define uuid_ether_add _bsd_uuid_ether_add
#define uuid_ether_del _bsd_uuid_ether_del
#define vht80_chan_ranges _bsd_vht80_chan_ranges
diff --git a/rtemsbsd/include/rtems/bsd/local/miidevs.h b/rtemsbsd/include/rtems/bsd/local/miidevs.h
index 4c6f542d..4ef09049 100644
--- a/rtemsbsd/include/rtems/bsd/local/miidevs.h
+++ b/rtemsbsd/include/rtems/bsd/local/miidevs.h
@@ -512,7 +512,9 @@
#define MII_MODEL_xxTSC_78Q2121 0x0015
#define MII_STR_xxTSC_78Q2121 "78Q2121 100BASE-TX media interface"
-/* Vitesse Semiconductor */
+/* Vitesse Semiconductor (now Microsemi) */
+#define MII_MODEL_xxVITESSE_VSC8501 0x0013
+#define MII_STR_xxVITESSE_VSC8501 "Vitesse VSC8501 10/100/1000TX PHY"
#define MII_MODEL_xxVITESSE_VSC8641 0x0003
#define MII_STR_xxVITESSE_VSC8641 "Vitesse VSC8641 10/100/1000TX PHY"
diff --git a/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h b/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h
index 33cb98e6..2fc1656c 100644
--- a/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h
+++ b/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h
@@ -38,6 +38,30 @@ static __inline int MMCBR_SWITCH_VCCQ(device_t brdev, device_t reqdev)
return ((mmcbr_switch_vccq_t *) _m)(brdev, reqdev);
}
+/** @brief Unique descriptor for the MMCBR_TUNE() method */
+extern struct kobjop_desc mmcbr_tune_desc;
+/** @brief A function implementing the MMCBR_TUNE() method */
+typedef int mmcbr_tune_t(device_t brdev, device_t reqdev, bool hs400);
+
+static __inline int MMCBR_TUNE(device_t brdev, device_t reqdev, bool hs400)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_tune);
+ return ((mmcbr_tune_t *) _m)(brdev, reqdev, hs400);
+}
+
+/** @brief Unique descriptor for the MMCBR_RETUNE() method */
+extern struct kobjop_desc mmcbr_retune_desc;
+/** @brief A function implementing the MMCBR_RETUNE() method */
+typedef int mmcbr_retune_t(device_t brdev, device_t reqdev, bool reset);
+
+static __inline int MMCBR_RETUNE(device_t brdev, device_t reqdev, bool reset)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_retune);
+ return ((mmcbr_retune_t *) _m)(brdev, reqdev, reset);
+}
+
/** @brief Unique descriptor for the MMCBR_REQUEST() method */
extern struct kobjop_desc mmcbr_request_desc;
/** @brief A function implementing the MMCBR_REQUEST() method */
diff --git a/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h b/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h
index 35fc1a0f..7910f1f3 100644
--- a/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h
+++ b/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h
@@ -14,6 +14,32 @@
#ifndef _mmcbus_if_h_
#define _mmcbus_if_h_
+/** @brief Unique descriptor for the MMCBUS_RETUNE_PAUSE() method */
+extern struct kobjop_desc mmcbus_retune_pause_desc;
+/** @brief A function implementing the MMCBUS_RETUNE_PAUSE() method */
+typedef void mmcbus_retune_pause_t(device_t brdev, device_t reqdev,
+ bool retune);
+
+static __inline void MMCBUS_RETUNE_PAUSE(device_t brdev, device_t reqdev,
+ bool retune)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbus_retune_pause);
+ ((mmcbus_retune_pause_t *) _m)(brdev, reqdev, retune);
+}
+
+/** @brief Unique descriptor for the MMCBUS_RETUNE_UNPAUSE() method */
+extern struct kobjop_desc mmcbus_retune_unpause_desc;
+/** @brief A function implementing the MMCBUS_RETUNE_UNPAUSE() method */
+typedef void mmcbus_retune_unpause_t(device_t brdev, device_t reqdev);
+
+static __inline void MMCBUS_RETUNE_UNPAUSE(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbus_retune_unpause);
+ ((mmcbus_retune_unpause_t *) _m)(brdev, reqdev);
+}
+
/** @brief Unique descriptor for the MMCBUS_WAIT_FOR_REQUEST() method */
extern struct kobjop_desc mmcbus_wait_for_request_desc;
/** @brief A function implementing the MMCBUS_WAIT_FOR_REQUEST() method */
diff --git a/rtemsbsd/include/rtems/bsd/local/opt_mmccam.h b/rtemsbsd/include/rtems/bsd/local/opt_mmccam.h
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/rtemsbsd/include/rtems/bsd/local/opt_mmccam.h
diff --git a/rtemsbsd/local/mmcbr_if.c b/rtemsbsd/local/mmcbr_if.c
index 6a338f87..2c8a72ba 100644
--- a/rtemsbsd/local/mmcbr_if.c
+++ b/rtemsbsd/local/mmcbr_if.c
@@ -29,6 +29,22 @@ null_switch_vccq(device_t brdev __unused, device_t reqdev __unused)
return (0);
}
+static int
+null_retune(device_t brdev __unused, device_t reqdev __unused,
+ bool reset __unused)
+{
+
+ return (0);
+}
+
+static int
+null_tune(device_t brdev __unused, device_t reqdev __unused,
+ bool hs400 __unused)
+{
+
+ return (0);
+}
+
struct kobjop_desc mmcbr_update_ios_desc = {
0, { &mmcbr_update_ios_desc, (kobjop_t)kobj_error_method }
};
@@ -37,6 +53,14 @@ struct kobjop_desc mmcbr_switch_vccq_desc = {
0, { &mmcbr_switch_vccq_desc, (kobjop_t)null_switch_vccq }
};
+struct kobjop_desc mmcbr_tune_desc = {
+ 0, { &mmcbr_tune_desc, (kobjop_t)null_tune }
+};
+
+struct kobjop_desc mmcbr_retune_desc = {
+ 0, { &mmcbr_retune_desc, (kobjop_t)null_retune }
+};
+
struct kobjop_desc mmcbr_request_desc = {
0, { &mmcbr_request_desc, (kobjop_t)kobj_error_method }
};
diff --git a/rtemsbsd/local/mmcbus_if.c b/rtemsbsd/local/mmcbus_if.c
index 7a9ba510..30061335 100644
--- a/rtemsbsd/local/mmcbus_if.c
+++ b/rtemsbsd/local/mmcbus_if.c
@@ -21,6 +21,14 @@
#include <dev/mmc/bridge.h>
#include <rtems/bsd/local/mmcbus_if.h>
+struct kobjop_desc mmcbus_retune_pause_desc = {
+ 0, { &mmcbus_retune_pause_desc, (kobjop_t)kobj_error_method }
+};
+
+struct kobjop_desc mmcbus_retune_unpause_desc = {
+ 0, { &mmcbus_retune_unpause_desc, (kobjop_t)kobj_error_method }
+};
+
struct kobjop_desc mmcbus_wait_for_request_desc = {
0, { &mmcbus_wait_for_request_desc, (kobjop_t)kobj_error_method }
};
diff --git a/rtemsbsd/rtems/rtems-kernel-bus-dma.c b/rtemsbsd/rtems/rtems-kernel-bus-dma.c
index c7cc8724..8c15e92b 100644
--- a/rtemsbsd/rtems/rtems-kernel-bus-dma.c
+++ b/rtemsbsd/rtems/rtems-kernel-bus-dma.c
@@ -383,14 +383,14 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
* Release the mapping held by map. A no-op on PowerPC.
*/
void
-_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
+bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
{
return;
}
void
-_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
+bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
{
#ifdef CPU_DATA_CACHE_ALIGNMENT
uintptr_t size = map->buffer_size;