From d883da7ba4eb9b148404a424cba419d0b2289d47 Mon Sep 17 00:00:00 2001 From: attilio Date: Thu, 21 Feb 2013 21:59:35 +0000 Subject: MFC --- contrib/binutils/opcodes/i386-opc.h | 9 +- sbin/devd/devd.conf.5 | 9 +- share/man/man4/carp.4 | 4 +- sys/conf/files | 1 - sys/dev/ath/if_ath.c | 2 + sys/dev/ath/if_ath_tx.c | 2 + sys/dev/cxgbe/common/t4_hw.h | 1 + sys/dev/cxgbe/t4_main.c | 229 +++++++++++++++++++++++ sys/dev/firewire/sbp.c | 4 +- sys/dev/mxge/if_mxge.c | 289 +++++++++++++++-------------- sys/dev/mxge/if_mxge_var.h | 32 +--- sys/dev/mxge/mxge_lro.c | 357 ------------------------------------ sys/fs/nfs/nfs_commonkrpc.c | 2 - sys/fs/nfsclient/nfs_clvfsops.c | 2 +- sys/kern/kern_sig.c | 22 ++- sys/kern/subr_trap.c | 2 + sys/kern/vfs_export.c | 1 + sys/kern/vfs_lookup.c | 2 +- sys/modules/mxge/mxge/Makefile | 2 +- sys/netinet/tcp_lro.c | 2 +- sys/nfsclient/nfs_krpc.c | 2 - sys/nfsclient/nfs_vfsops.c | 2 +- sys/sys/mount.h | 140 +++++++++++--- sys/sys/signalvar.h | 4 +- sys/sys/systm.h | 2 - sys/tools/vnode_if.awk | 3 + sys/x86/isa/atrtc.c | 16 +- 27 files changed, 551 insertions(+), 592 deletions(-) delete mode 100644 sys/dev/mxge/mxge_lro.c diff --git a/contrib/binutils/opcodes/i386-opc.h b/contrib/binutils/opcodes/i386-opc.h index 45589d8..27c1dab 100644 --- a/contrib/binutils/opcodes/i386-opc.h +++ b/contrib/binutils/opcodes/i386-opc.h @@ -73,15 +73,16 @@ typedef struct template #define CpuSSE4_2 0x800000 /* SSE4.2 Instructions required */ #define CpuXSAVE 0x1000000 /* XSAVE Instructions required */ #define CpuAES 0x2000000 /* AES Instructions required */ -#define CpuPCLMUL 0x4000000 /* Carry-less Multiplication extensions */ - -/* SSE4.1/4.2 Instructions required */ -#define CpuSSE4 (CpuSSE4_1|CpuSSE4_2) /* These flags are set by gas depending on the flag_code. */ #define Cpu64 0x4000000 /* 64bit support required */ #define CpuNo64 0x8000000 /* Not supported in the 64bit mode */ +#define CpuPCLMUL 0x10000000 /* Carry-less Multiplication extensions */ + +/* SSE4.1/4.2 Instructions required */ +#define CpuSSE4 (CpuSSE4_1|CpuSSE4_2) + /* The default value for unknown CPUs - enable all features to avoid problems. */ #define CpuUnknownFlags (Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 \ |CpuP4|CpuSledgehammer|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuVMX \ diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5 index 4c1893d..311228e 100644 --- a/sbin/devd/devd.conf.5 +++ b/sbin/devd/devd.conf.5 @@ -41,7 +41,7 @@ .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS .\" SOFTWARE. .\" -.Dd December 16, 2011 +.Dd February 22, 2013 .Dt DEVD.CONF 5 .Os .Sh NAME @@ -181,9 +181,8 @@ Valid media types are: .Dq Li Tokenring , .Dq Li FDDI , .Dq Li 802.11 , -.Dq Li ATM , and -.Dq Li CARP . +.Dq Li ATM . .It Ic subdevice Qq Ar string ; This is shorthand for .Dq Ic match Qo Li subdevice Qc Qq Ar string . @@ -350,6 +349,7 @@ The network interface is attached to the system. The network interface is detached from the system. .El .El +.Pp .It Li DEVFS Events related to the .Xr devfs 5 @@ -369,6 +369,7 @@ The node is destroyed. .El .El +.Pp .It Li USB Events related to the USB subsystem. .Bl -tag -width ".Sy Subsystem" -compact @@ -390,6 +391,7 @@ USB interface is attached to a device. USB interface is detached from a device. .El .El +.Pp .It Li coretemp Events related to the .Xr coretemp 4 @@ -404,6 +406,7 @@ Notification that the CPU core has reached critical temperature. String containing the temperature of the core that has become too hot. .El .El +.Pp .It Li kern Events related to the kernel. .Bl -tag -width ".Sy Subsystem" -compact diff --git a/share/man/man4/carp.4 b/share/man/man4/carp.4 index d051377..84e87d6 100644 --- a/share/man/man4/carp.4 +++ b/share/man/man4/carp.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 25, 2012 +.Dd February 21, 2013 .Dt CARP 4 .Os .Sh NAME @@ -281,7 +281,7 @@ status change events can be set up by using the following devd.conf rule: .Bd -literal -offset indent notify 0 { match "system" "CARP"; - match "subsystem" "[0-9]+@"; + match "subsystem" "[0-9]+@[0-9a-z]+"; match "type" "(MASTER|BACKUP)"; action "/root/carpcontrol.sh $subsystem $type"; }; diff --git a/sys/conf/files b/sys/conf/files index 2c9d93c..322f9c4 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1743,7 +1743,6 @@ mwlboot.fw optional mwlfw \ no-obj no-implicit-rule \ clean "mwlboot.fw" dev/mxge/if_mxge.c optional mxge pci -dev/mxge/mxge_lro.c optional mxge pci dev/mxge/mxge_eth_z8e.c optional mxge pci dev/mxge/mxge_ethp_z8e.c optional mxge pci dev/mxge/mxge_rss_eth_z8e.c optional mxge pci diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 98c219bb..2ea3909 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -3631,12 +3631,14 @@ ath_tx_default_comp(struct ath_softc *sc, struct ath_buf *bf, int fail) st = ((bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0) ? ts->ts_status : HAL_TXERR_XRETRY; +#if 0 if (bf->bf_state.bfs_dobaw) device_printf(sc->sc_dev, "%s: bf %p: seqno %d: dobaw should've been cleared!\n", __func__, bf, SEQNO(bf->bf_state.bfs_seqno)); +#endif if (bf->bf_next != NULL) device_printf(sc->sc_dev, "%s: bf %p: seqno %d: bf_next not NULL!\n", diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c index f3ce0e7..92b28c6 100644 --- a/sys/dev/ath/if_ath_tx.c +++ b/sys/dev/ath/if_ath_tx.c @@ -3373,6 +3373,7 @@ ath_tx_tid_drain_pkt(struct ath_softc *sc, struct ath_node *an, ath_tx_update_baw(sc, an, tid, bf); bf->bf_state.bfs_dobaw = 0; } +#if 0 /* * This has become a non-fatal error now */ @@ -3380,6 +3381,7 @@ ath_tx_tid_drain_pkt(struct ath_softc *sc, struct ath_node *an, device_printf(sc->sc_dev, "%s: wasn't added: seqno %d\n", __func__, SEQNO(bf->bf_state.bfs_seqno)); +#endif } TAILQ_INSERT_TAIL(bf_cq, bf, bf_list); } diff --git a/sys/dev/cxgbe/common/t4_hw.h b/sys/dev/cxgbe/common/t4_hw.h index 256a7d5..acc383a 100644 --- a/sys/dev/cxgbe/common/t4_hw.h +++ b/sys/dev/cxgbe/common/t4_hw.h @@ -58,6 +58,7 @@ enum { CIM_PIFLA_SIZE = 64, /* # of 192-bit words in CIM PIF LA */ CIM_MALA_SIZE = 64, /* # of 160-bit words in CIM MA LA */ CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */ + CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */ TPLA_SIZE = 128, /* # of 64-bit words in TP LA */ ULPRX_LA_SIZE = 512, /* # of 256-bit words in ULP_RX LA */ }; diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 96246a6..0e24c7c 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -317,6 +317,9 @@ static int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); static int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); #ifdef SBUF_DRAIN static int sysctl_cctrl(SYSCTL_HANDLER_ARGS); +static int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); +static int sysctl_cim_la(SYSCTL_HANDLER_ARGS); +static int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); static int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); static int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); static int sysctl_devlog(SYSCTL_HANDLER_ARGS); @@ -3171,6 +3174,62 @@ t4_sysctls(struct adapter *sc) CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_cctrl, "A", "congestion control"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", + CTLTYPE_STRING | CTLFLAG_RD, sc, 0, + sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", + CTLTYPE_STRING | CTLFLAG_RD, sc, 1, + sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", + CTLTYPE_STRING | CTLFLAG_RD, sc, 2, + sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", + CTLTYPE_STRING | CTLFLAG_RD, sc, 3, + sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", + CTLTYPE_STRING | CTLFLAG_RD, sc, 4, + sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", + CTLTYPE_STRING | CTLFLAG_RD, sc, 5, + sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", + CTLTYPE_STRING | CTLFLAG_RD, sc, 0, + sysctl_cim_la, "A", "CIM logic analyzer"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", + CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", + CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", + CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", + CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", + CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", + CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, + sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", + CTLTYPE_STRING | CTLFLAG_RD, sc, 0, + sysctl_cim_qcfg, "A", "CIM queue configuration"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_cpl_stats, "A", "CPL statistics"); @@ -3694,6 +3753,176 @@ sysctl_cctrl(SYSCTL_HANDLER_ARGS) return (rc); } +static const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ] = { + "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ + "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI" /* obq's */ +}; + +static int +sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) +{ + struct adapter *sc = arg1; + struct sbuf *sb; + int rc, i, n, qid = arg2; + uint32_t *buf, *p; + char *qtype; + + KASSERT(qid >= 0 && qid < nitems(qname), + ("%s: bad qid %d\n", __func__, qid)); + + if (qid < CIM_NUM_IBQ) { + /* inbound queue */ + qtype = "IBQ"; + n = 4 * CIM_IBQ_SIZE; + buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); + rc = t4_read_cim_ibq(sc, qid, buf, n); + } else { + /* outbound queue */ + qtype = "OBQ"; + qid -= CIM_NUM_IBQ; + n = 4 * 6 * CIM_OBQ_SIZE; + buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); + rc = t4_read_cim_obq(sc, qid, buf, n); + } + + if (rc < 0) { + rc = -rc; + goto done; + } + n = rc * sizeof(uint32_t); /* rc has # of words actually read */ + + rc = sysctl_wire_old_buffer(req, 0); + if (rc != 0) + goto done; + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) { + rc = ENOMEM; + goto done; + } + + sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); + for (i = 0, p = buf; i < n; i += 16, p += 4) + sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], + p[2], p[3]); + + rc = sbuf_finish(sb); + sbuf_delete(sb); +done: + free(buf, M_CXGBE); + return (rc); +} + +static int +sysctl_cim_la(SYSCTL_HANDLER_ARGS) +{ + struct adapter *sc = arg1; + u_int cfg; + struct sbuf *sb; + uint32_t *buf, *p; + int rc; + + rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); + if (rc != 0) + return (rc); + + rc = sysctl_wire_old_buffer(req, 0); + if (rc != 0) + return (rc); + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) + return (ENOMEM); + + buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, + M_ZERO | M_WAITOK); + + rc = -t4_cim_read_la(sc, buf, NULL); + if (rc != 0) + goto done; + + sbuf_printf(sb, "Status Data PC%s", + cfg & F_UPDBGLACAPTPCONLY ? "" : + " LS0Stat LS0Addr LS0Data"); + + KASSERT((sc->params.cim_la_size & 7) == 0, + ("%s: p will walk off the end of buf", __func__)); + + for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { + if (cfg & F_UPDBGLACAPTPCONLY) { + sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, + p[6], p[7]); + sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", + (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, + p[4] & 0xff, p[5] >> 8); + sbuf_printf(sb, "\n %02x %x%07x %x%07x", + (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, + p[1] & 0xf, p[2] >> 4); + } else { + sbuf_printf(sb, + "\n %02x %x%07x %x%07x %08x %08x " + "%08x%08x%08x%08x", + (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, + p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], + p[6], p[7]); + } + } + + rc = sbuf_finish(sb); + sbuf_delete(sb); +done: + free(buf, M_CXGBE); + return (rc); +} + +static int +sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) +{ + struct adapter *sc = arg1; + struct sbuf *sb; + int rc, i; + uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ]; + uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ]; + uint16_t thres[CIM_NUM_IBQ]; + uint32_t obq_wr[2 * CIM_NUM_OBQ], *wr = obq_wr; + uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ)], *p = stat; + + rc = -t4_cim_read(sc, A_UP_IBQ_0_RDADDR, nitems(stat), stat); + if (rc == 0) + rc = -t4_cim_read(sc, A_UP_OBQ_0_REALADDR, nitems(obq_wr), + obq_wr); + if (rc != 0) + return (rc); + + t4_read_cimq_cfg(sc, base, size, thres); + + rc = sysctl_wire_old_buffer(req, 0); + if (rc != 0) + return (rc); + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) + return (ENOMEM); + + sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); + + for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) + sbuf_printf(sb, "\n%5s %5x %5u %4u %6x %4x %4u %4u %5u", + qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), + G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), + G_QUEREMFLITS(p[2]) * 16); + for ( ; i < CIM_NUM_IBQ + CIM_NUM_OBQ; i++, p += 4, wr += 2) + sbuf_printf(sb, "\n%5s %5x %5u %11x %4x %4u %4u %5u", qname[i], + base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, + wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), + G_QUEREMFLITS(p[2]) * 16); + + rc = sbuf_finish(sb); + sbuf_delete(sb); + + return (rc); +} + static int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS) { diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c index 8089d99..5efc5eb 100644 --- a/sys/dev/firewire/sbp.c +++ b/sys/dev/firewire/sbp.c @@ -2488,16 +2488,14 @@ printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[0]), ntohl(ocb->orb[1]), ntoh printf("ORB %08x %08x %08x %08x\n", ntohl(ocb->orb[4]), ntohl(ocb->orb[5]), ntohl(ocb->orb[6]), ntohl(ocb->orb[7])); */ if (ccb->csio.dxfer_len > 0) { - int s, error; + int error; - s = splsoftvm(); error = bus_dmamap_load_ccb(/*dma tag*/sbp->dmat, /*dma map*/ocb->dmamap, ccb, sbp_execute_ocb, ocb, /*flags*/0); - splx(s); if (error) printf("sbp: bus_dmamap_load error %d\n", error); } else diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c index 68afbf9..fcc0825 100644 --- a/sys/dev/mxge/if_mxge.c +++ b/sys/dev/mxge/if_mxge.c @@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -102,7 +103,6 @@ static int mxge_intr_coal_delay = 30; static int mxge_deassert_wait = 1; static int mxge_flow_control = 1; static int mxge_verbose = 0; -static int mxge_lro_cnt = 8; static int mxge_ticks; static int mxge_max_slices = 1; static int mxge_rss_hash_type = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT; @@ -1311,9 +1311,9 @@ mxge_reset(mxge_softc_t *sc, int interrupts_setup) ss->tx.stall = 0; ss->rx_big.cnt = 0; ss->rx_small.cnt = 0; - ss->lro_bad_csum = 0; - ss->lro_queued = 0; - ss->lro_flushed = 0; + ss->lc.lro_bad_csum = 0; + ss->lc.lro_queued = 0; + ss->lc.lro_flushed = 0; if (ss->fw_stats != NULL) { bzero(ss->fw_stats, sizeof *ss->fw_stats); } @@ -1414,50 +1414,6 @@ mxge_change_flow_control(SYSCTL_HANDLER_ARGS) } static int -mxge_change_lro_locked(mxge_softc_t *sc, int lro_cnt) -{ - struct ifnet *ifp; - int err = 0; - - ifp = sc->ifp; - if (lro_cnt == 0) - ifp->if_capenable &= ~IFCAP_LRO; - else - ifp->if_capenable |= IFCAP_LRO; - sc->lro_cnt = lro_cnt; - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - mxge_close(sc, 0); - err = mxge_open(sc); - } - return err; -} - -static int -mxge_change_lro(SYSCTL_HANDLER_ARGS) -{ - mxge_softc_t *sc; - unsigned int lro_cnt; - int err; - - sc = arg1; - lro_cnt = sc->lro_cnt; - err = sysctl_handle_int(oidp, &lro_cnt, arg2, req); - if (err != 0) - return err; - - if (lro_cnt == sc->lro_cnt) - return 0; - - if (lro_cnt > 128) - return EINVAL; - - mtx_lock(&sc->driver_mtx); - err = mxge_change_lro_locked(sc, lro_cnt); - mtx_unlock(&sc->driver_mtx); - return err; -} - -static int mxge_handle_be32(SYSCTL_HANDLER_ARGS) { int err; @@ -1653,14 +1609,6 @@ mxge_add_sysctls(mxge_softc_t *sc) CTLFLAG_RW, &mxge_verbose, 0, "verbose printing"); - /* lro */ - SYSCTL_ADD_PROC(ctx, children, OID_AUTO, - "lro_cnt", - CTLTYPE_INT|CTLFLAG_RW, sc, - 0, mxge_change_lro, - "I", "number of lro merge queues"); - - /* add counters exported for debugging from all slices */ sysctl_ctx_init(&sc->slice_sysctl_ctx); sc->slice_sysctl_tree = @@ -1686,11 +1634,15 @@ mxge_add_sysctls(mxge_softc_t *sc) CTLFLAG_RD, &ss->rx_big.cnt, 0, "rx_small_cnt"); SYSCTL_ADD_INT(ctx, children, OID_AUTO, - "lro_flushed", CTLFLAG_RD, &ss->lro_flushed, + "lro_flushed", CTLFLAG_RD, &ss->lc.lro_flushed, 0, "number of lro merge queues flushed"); SYSCTL_ADD_INT(ctx, children, OID_AUTO, - "lro_queued", CTLFLAG_RD, &ss->lro_queued, + "lro_bad_csum", CTLFLAG_RD, &ss->lc.lro_bad_csum, + 0, "number of bad csums preventing LRO"); + + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "lro_queued", CTLFLAG_RD, &ss->lc.lro_queued, 0, "number of frames appended to lro merge" "queues"); @@ -2534,6 +2486,64 @@ done: return err; } +#ifdef INET6 + +static uint16_t +mxge_csum_generic(uint16_t *raw, int len) +{ + uint32_t csum; + + + csum = 0; + while (len > 0) { + csum += *raw; + raw++; + len -= 2; + } + csum = (csum >> 16) + (csum & 0xffff); + csum = (csum >> 16) + (csum & 0xffff); + return (uint16_t)csum; +} + +static inline uint16_t +mxge_rx_csum6(void *p, struct mbuf *m, uint32_t csum) +{ + uint32_t partial; + int nxt, cksum_offset; + struct ip6_hdr *ip6 = p; + uint16_t c; + + nxt = ip6->ip6_nxt; + cksum_offset = sizeof (*ip6) + ETHER_HDR_LEN; + if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP) { + cksum_offset = ip6_lasthdr(m, ETHER_HDR_LEN, + IPPROTO_IPV6, &nxt); + if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP) + return (1); + } + + /* + * IPv6 headers do not contain a checksum, and hence + * do not checksum to zero, so they don't "fall out" + * of the partial checksum calculation like IPv4 + * headers do. We need to fix the partial checksum by + * subtracting the checksum of the IPv6 header. + */ + + partial = mxge_csum_generic((uint16_t *)ip6, cksum_offset - + ETHER_HDR_LEN); + csum += ~partial; + csum += (csum < ~partial); + csum = (csum >> 16) + (csum & 0xFFFF); + csum = (csum >> 16) + (csum & 0xFFFF); + c = in6_cksum_pseudo(ip6, m->m_pkthdr.len - cksum_offset, nxt, + csum); + +// printf("%d %d %x %x %x %x %x\n", m->m_pkthdr.len, cksum_offset, c, csum, ocsum, partial, d); + c ^= 0xffff; + return (c); +} +#endif /* INET6 */ /* * Myri10GE hardware checksums are not valid if the sender * padded the frame with non-zero padding. This is because @@ -2547,26 +2557,39 @@ static inline uint16_t mxge_rx_csum(struct mbuf *m, int csum) { struct ether_header *eh; +#ifdef INET struct ip *ip; - uint16_t c; +#endif + int cap = m->m_pkthdr.rcvif->if_capenable; + uint16_t c, etype; - eh = mtod(m, struct ether_header *); - /* only deal with IPv4 TCP & UDP for now */ - if (__predict_false(eh->ether_type != htons(ETHERTYPE_IP))) - return 1; - ip = (struct ip *)(eh + 1); - if (__predict_false(ip->ip_p != IPPROTO_TCP && - ip->ip_p != IPPROTO_UDP)) - return 1; + eh = mtod(m, struct ether_header *); + etype = ntohs(eh->ether_type); + switch (etype) { #ifdef INET - c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htonl(ntohs(csum) + ntohs(ip->ip_len) + - - (ip->ip_hl << 2) + ip->ip_p)); -#else - c = 1; + case ETHERTYPE_IP: + if ((cap & IFCAP_RXCSUM) == 0) + return (1); + ip = (struct ip *)(eh + 1); + if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP) + return (1); + c = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htonl(ntohs(csum) + ntohs(ip->ip_len) - + (ip->ip_hl << 2) + ip->ip_p)); + c ^= 0xffff; + break; #endif - c ^= 0xffff; +#ifdef INET6 + case ETHERTYPE_IPV6: + if ((cap & IFCAP_RXCSUM_IPV6) == 0) + return (1); + c = mxge_rx_csum6((eh + 1), m, csum); + break; +#endif + default: + c = 1; + } return (c); } @@ -2628,7 +2651,8 @@ mxge_vlan_tag_remove(struct mbuf *m, uint32_t *csum) static inline void -mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) +mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, + uint32_t csum, int lro) { mxge_softc_t *sc; struct ifnet *ifp; @@ -2637,7 +2661,6 @@ mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) mxge_rx_ring_t *rx; bus_dmamap_t old_map; int idx; - uint16_t tcpudp_csum; sc = ss->sc; ifp = sc->ifp; @@ -2674,14 +2697,18 @@ mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) mxge_vlan_tag_remove(m, &csum); } /* if the checksum is valid, mark it in the mbuf header */ - if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { - if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) - return; - /* otherwise, it was a UDP frame, or a TCP frame which - we could not do LRO on. Tell the stack that the - checksum is good */ + + if ((ifp->if_capenable & (IFCAP_RXCSUM_IPV6 | IFCAP_RXCSUM)) && + (0 == mxge_rx_csum(m, csum))) { + /* Tell the stack that the checksum is good */ m->m_pkthdr.csum_data = 0xffff; - m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; + m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | + CSUM_DATA_VALID; + +#if defined(INET) || defined (INET6) + if (lro && (0 == tcp_lro_rx(&ss->lc, m, 0))) + return; +#endif } /* flowid only valid if RSS hashing is enabled */ if (sc->num_slices > 1) { @@ -2693,7 +2720,8 @@ mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) } static inline void -mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) +mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, + uint32_t csum, int lro) { mxge_softc_t *sc; struct ifnet *ifp; @@ -2702,7 +2730,6 @@ mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) mxge_rx_ring_t *rx; bus_dmamap_t old_map; int idx; - uint16_t tcpudp_csum; sc = ss->sc; ifp = sc->ifp; @@ -2739,14 +2766,17 @@ mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len, uint32_t csum) mxge_vlan_tag_remove(m, &csum); } /* if the checksum is valid, mark it in the mbuf header */ - if (sc->csum_flag && (0 == (tcpudp_csum = mxge_rx_csum(m, csum)))) { - if (sc->lro_cnt && (0 == mxge_lro_rx(ss, m, csum))) - return; - /* otherwise, it was a UDP frame, or a TCP frame which - we could not do LRO on. Tell the stack that the - checksum is good */ + if ((ifp->if_capenable & (IFCAP_RXCSUM_IPV6 | IFCAP_RXCSUM)) && + (0 == mxge_rx_csum(m, csum))) { + /* Tell the stack that the checksum is good */ m->m_pkthdr.csum_data = 0xffff; - m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | CSUM_DATA_VALID; + m->m_pkthdr.csum_flags = CSUM_PSEUDO_HDR | + CSUM_DATA_VALID; + +#if defined(INET) || defined (INET6) + if (lro && (0 == tcp_lro_rx(&ss->lc, m, csum))) + return; +#endif } /* flowid only valid if RSS hashing is enabled */ if (sc->num_slices > 1) { @@ -2764,16 +2794,17 @@ mxge_clean_rx_done(struct mxge_slice_state *ss) int limit = 0; uint16_t length; uint16_t checksum; + int lro; - + lro = ss->sc->ifp->if_capenable & IFCAP_LRO; while (rx_done->entry[rx_done->idx].length != 0) { length = ntohs(rx_done->entry[rx_done->idx].length); rx_done->entry[rx_done->idx].length = 0; checksum = rx_done->entry[rx_done->idx].checksum; if (length <= (MHLEN - MXGEFW_PAD)) - mxge_rx_done_small(ss, length, checksum); + mxge_rx_done_small(ss, length, checksum, lro); else - mxge_rx_done_big(ss, length, checksum); + mxge_rx_done_big(ss, length, checksum, lro); rx_done->cnt++; rx_done->idx = rx_done->cnt & rx_done->mask; @@ -2781,11 +2812,11 @@ mxge_clean_rx_done(struct mxge_slice_state *ss) if (__predict_false(++limit > rx_done->mask / 2)) break; } -#ifdef INET - while (!SLIST_EMPTY(&ss->lro_active)) { - struct lro_entry *lro = SLIST_FIRST(&ss->lro_active); - SLIST_REMOVE_HEAD(&ss->lro_active, next); - mxge_lro_flush(ss, lro); +#if defined(INET) || defined (INET6) + while (!SLIST_EMPTY(&ss->lc.lro_active)) { + struct lro_entry *lro = SLIST_FIRST(&ss->lc.lro_active); + SLIST_REMOVE_HEAD(&ss->lc.lro_active, next); + tcp_lro_flush(&ss->lc, lro); } #endif } @@ -3153,15 +3184,11 @@ mxge_init(void *arg) static void mxge_free_slice_mbufs(struct mxge_slice_state *ss) { - struct lro_entry *lro_entry; int i; - while (!SLIST_EMPTY(&ss->lro_free)) { - lro_entry = SLIST_FIRST(&ss->lro_free); - SLIST_REMOVE_HEAD(&ss->lro_free, next); - free(lro_entry, M_DEVBUF); - } - +#if defined(INET) || defined(INET6) + tcp_lro_free(&ss->lc); +#endif for (i = 0; i <= ss->rx_big.mask; i++) { if (ss->rx_big.info[i].m == NULL) continue; @@ -3545,26 +3572,17 @@ mxge_slice_open(struct mxge_slice_state *ss, int nbufs, int cl_size) mxge_softc_t *sc; mxge_cmd_t cmd; bus_dmamap_t map; - struct lro_entry *lro_entry; int err, i, slice; sc = ss->sc; slice = ss - sc->ss; - SLIST_INIT(&ss->lro_free); - SLIST_INIT(&ss->lro_active); - - for (i = 0; i < sc->lro_cnt; i++) { - lro_entry = (struct lro_entry *) - malloc(sizeof (*lro_entry), M_DEVBUF, - M_NOWAIT | M_ZERO); - if (lro_entry == NULL) { - sc->lro_cnt = i; - break; - } - SLIST_INSERT_HEAD(&ss->lro_free, lro_entry, next); - } +#if defined(INET) || defined(INET6) + (void)tcp_lro_init(&ss->lc); +#endif + ss->lc.ifp = sc->ifp; + /* get the lanai pointers to the send and receive rings */ err = 0; @@ -4219,10 +4237,8 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } else if (mask & IFCAP_RXCSUM) { if (IFCAP_RXCSUM & ifp->if_capenable) { ifp->if_capenable &= ~IFCAP_RXCSUM; - sc->csum_flag = 0; } else { ifp->if_capenable |= IFCAP_RXCSUM; - sc->csum_flag = 1; } } if (mask & IFCAP_TSO4) { @@ -4249,16 +4265,12 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); } -#ifdef NOTYET - } else if (mask & IFCAP_RXCSUM6) { - if (IFCAP_RXCSUM6 & ifp->if_capenable) { - ifp->if_capenable &= ~IFCAP_RXCSUM6; - sc->csum_flag = 0; + } else if (mask & IFCAP_RXCSUM_IPV6) { + if (IFCAP_RXCSUM_IPV6 & ifp->if_capenable) { + ifp->if_capenable &= ~IFCAP_RXCSUM_IPV6; } else { - ifp->if_capenable |= IFCAP_RXCSUM6; - sc->csum_flag = 1; + ifp->if_capenable |= IFCAP_RXCSUM_IPV6; } -#endif } if (mask & IFCAP_TSO6) { if (IFCAP_TSO6 & ifp->if_capenable) { @@ -4274,12 +4286,8 @@ mxge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } #endif /*IFCAP_TSO6 */ - if (mask & IFCAP_LRO) { - if (IFCAP_LRO & ifp->if_capenable) - err = mxge_change_lro_locked(sc, 0); - else - err = mxge_change_lro_locked(sc, mxge_lro_cnt); - } + if (mask & IFCAP_LRO) + ifp->if_capenable ^= IFCAP_LRO; if (mask & IFCAP_VLAN_HWTAGGING) ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; if (mask & IFCAP_VLAN_HWTSO) @@ -4326,14 +4334,11 @@ mxge_fetch_tunables(mxge_softc_t *sc) TUNABLE_INT_FETCH("hw.mxge.verbose", &mxge_verbose); TUNABLE_INT_FETCH("hw.mxge.ticks", &mxge_ticks); - TUNABLE_INT_FETCH("hw.mxge.lro_cnt", &sc->lro_cnt); TUNABLE_INT_FETCH("hw.mxge.always_promisc", &mxge_always_promisc); TUNABLE_INT_FETCH("hw.mxge.rss_hash_type", &mxge_rss_hash_type); TUNABLE_INT_FETCH("hw.mxge.rss_hashtype", &mxge_rss_hash_type); TUNABLE_INT_FETCH("hw.mxge.initial_mtu", &mxge_initial_mtu); TUNABLE_INT_FETCH("hw.mxge.throttle", &mxge_throttle); - if (sc->lro_cnt != 0) - mxge_lro_cnt = sc->lro_cnt; if (bootverbose) mxge_verbose = 1; @@ -4897,8 +4902,9 @@ mxge_attach(device_t dev) if_initbaudrate(ifp, IF_Gbps(10)); ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO4 | - IFCAP_VLAN_MTU | IFCAP_LINKSTATE | IFCAP_TXCSUM_IPV6; -#ifdef INET + IFCAP_VLAN_MTU | IFCAP_LINKSTATE | IFCAP_TXCSUM_IPV6 | + IFCAP_RXCSUM_IPV6; +#if defined(INET) || defined(INET6) ifp->if_capabilities |= IFCAP_LRO; #endif @@ -4929,7 +4935,6 @@ mxge_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; if (sc->lro_cnt == 0) ifp->if_capenable &= ~IFCAP_LRO; - sc->csum_flag = 1; ifp->if_init = mxge_init; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; diff --git a/sys/dev/mxge/if_mxge_var.h b/sys/dev/mxge/if_mxge_var.h index 9393577..7ca1f39 100644 --- a/sys/dev/mxge/if_mxge_var.h +++ b/sys/dev/mxge/if_mxge_var.h @@ -194,31 +194,6 @@ typedef struct char mtx_name[16]; } mxge_tx_ring_t; -struct lro_entry; -struct lro_entry -{ - SLIST_ENTRY(lro_entry) next; - struct mbuf *m_head; - struct mbuf *m_tail; - int timestamp; - struct ip *ip; - uint32_t tsval; - uint32_t tsecr; - uint32_t source_ip; - uint32_t dest_ip; - uint32_t next_seq; - uint32_t ack_seq; - uint32_t len; - uint32_t data_csum; - uint16_t window; - uint16_t source_port; - uint16_t dest_port; - uint16_t append_cnt; - uint16_t mss; - -}; -SLIST_HEAD(lro_head, lro_entry); - struct mxge_softc; typedef struct mxge_softc mxge_softc_t; @@ -236,11 +211,7 @@ struct mxge_slice_state { u_long omcasts; u_long oerrors; int if_drv_flags; - struct lro_head lro_active; - struct lro_head lro_free; - int lro_queued; - int lro_flushed; - int lro_bad_csum; + struct lro_ctrl lc; mxge_dma_t fw_stats_dma; struct sysctl_oid *sysctl_tree; struct sysctl_ctx_list sysctl_ctx; @@ -250,7 +221,6 @@ struct mxge_slice_state { struct mxge_softc { struct ifnet* ifp; struct mxge_slice_state *ss; - int csum_flag; /* rx_csums? */ int tx_boundary; /* boundary transmits cannot cross*/ int lro_cnt; bus_dma_tag_t parent_dmat; diff --git a/sys/dev/mxge/mxge_lro.c b/sys/dev/mxge/mxge_lro.c deleted file mode 100644 index b313059..0000000 --- a/sys/dev/mxge/mxge_lro.c +++ /dev/null @@ -1,357 +0,0 @@ -/****************************************************************************** - -Copyright (c) 2007-2008, Myricom Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Neither the name of the Myricom Inc, nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************/ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "opt_inet.h" - -#ifdef INET - -/* Assume len is a multiple of 4 */ -static uint16_t -mxge_csum_generic(uint16_t *raw, int len) -{ - uint32_t csum; - csum = 0; - while (len > 0) { - csum += *raw; - raw++; - csum += *raw; - raw++; - len -= 4; - } - csum = (csum >> 16) + (csum & 0xffff); - csum = (csum >> 16) + (csum & 0xffff); - return (uint16_t)csum; -} - - -void -mxge_lro_flush(struct mxge_slice_state *ss, struct lro_entry *lro) -{ - mxge_softc_t *mgp = ss->sc; - struct ifnet *ifp; - struct ip *ip; - struct tcphdr *tcp; - uint32_t *ts_ptr; - uint32_t tcplen, tcp_csum; - - if (lro->append_cnt) { - /* incorporate the new len into the ip header and - * re-calculate the checksum */ - ip = lro->ip; - ip->ip_len = htons(lro->len - ETHER_HDR_LEN); - ip->ip_sum = 0; - ip->ip_sum = 0xffff ^ - mxge_csum_generic((uint16_t*)ip, - sizeof (*ip)); - - lro->m_head->m_pkthdr.csum_flags = CSUM_IP_CHECKED | - CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - lro->m_head->m_pkthdr.csum_data = 0xffff; - lro->m_head->m_pkthdr.len = lro->len; - - /* incorporate the latest ack into the tcp header */ - tcp = (struct tcphdr *) (ip + 1); - tcp->th_ack = lro->ack_seq; - tcp->th_win = lro->window; - /* incorporate latest timestamp into the tcp header */ - if (lro->timestamp) { - ts_ptr = (uint32_t *)(tcp + 1); - ts_ptr[1] = htonl(lro->tsval); - ts_ptr[2] = lro->tsecr; - } - /* - * update checksum in tcp header by re-calculating the - * tcp pseudoheader checksum, and adding it to the checksum - * of the tcp payload data - */ - tcp->th_sum = 0; - tcplen = lro->len - sizeof(*ip) - ETHER_HDR_LEN; - tcp_csum = lro->data_csum; - tcp_csum += in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(tcplen + IPPROTO_TCP)); - tcp_csum += mxge_csum_generic((uint16_t*)tcp, - tcp->th_off << 2); - tcp_csum = (tcp_csum & 0xffff) + (tcp_csum >> 16); - tcp_csum = (tcp_csum & 0xffff) + (tcp_csum >> 16); -#if 0 - IOLog("pseudo = 0x%x, generic = 0x%x, sum = %x\n", - in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(tcplen + IPPROTO_TCP)), - mxge_csum_generic((uint16_t*)tcp, - tcp->th_off << 2), - htons(0xffff ^ tcp_csum)); -#endif - tcp->th_sum = 0xffff ^ tcp_csum; - } - ifp = mgp->ifp; - (*ifp->if_input)(mgp->ifp, lro->m_head); - ss->lro_queued += lro->append_cnt + 1; - ss->lro_flushed++; - lro->m_head = NULL; - lro->timestamp = 0; - lro->append_cnt = 0; - SLIST_INSERT_HEAD(&ss->lro_free, lro, next); -} - -int -mxge_lro_rx(struct mxge_slice_state *ss, struct mbuf *m_head, uint32_t csum) -{ - struct ether_header *eh; - struct ip *ip; - struct tcphdr *tcp; - uint32_t *ts_ptr; - struct mbuf *m_nxt, *m_tail; - struct lro_entry *lro; - int hlen, ip_len, tcp_hdr_len, tcp_data_len, tot_len; - int opt_bytes, trim; - uint32_t seq, tmp_csum, device_mtu; - - eh = mtod(m_head, struct ether_header *); - if (eh->ether_type != htons(ETHERTYPE_IP)) - return 1; - ip = (struct ip *) (eh + 1); - if (ip->ip_p != IPPROTO_TCP) - return 1; - - /* ensure there are no options */ - if ((ip->ip_hl << 2) != sizeof (*ip)) - return -1; - - /* .. and the packet is not fragmented */ - if (ip->ip_off & htons(IP_MF|IP_OFFMASK)) - return -1; - - /* verify that the IP header checksum is correct */ - tmp_csum = mxge_csum_generic((uint16_t *)ip, sizeof (*ip)); - if (__predict_false((tmp_csum ^ 0xffff) != 0)) { - ss->lro_bad_csum++; - return -1; - } - - /* find the TCP header */ - tcp = (struct tcphdr *) (ip + 1); - - /* ensure no bits set besides ack or psh */ - if ((tcp->th_flags & ~(TH_ACK | TH_PUSH)) != 0) - return -1; - - /* check for timestamps. Since the only option we handle are - timestamps, we only have to handle the simple case of - aligned timestamps */ - - opt_bytes = (tcp->th_off << 2) - sizeof (*tcp); - tcp_hdr_len = sizeof (*tcp) + opt_bytes; - ts_ptr = (uint32_t *)(tcp + 1); - if (opt_bytes != 0) { - if (__predict_false(opt_bytes != TCPOLEN_TSTAMP_APPA) || - (*ts_ptr != ntohl(TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP))) - return -1; - } - - ip_len = ntohs(ip->ip_len); - tcp_data_len = ip_len - (tcp->th_off << 2) - sizeof (*ip); - - - /* - * If frame is padded beyond the end of the IP packet, - * then we must trim the extra bytes off the end. - */ - tot_len = m_head->m_pkthdr.len; - trim = tot_len - (ip_len + ETHER_HDR_LEN); - if (trim != 0) { - if (trim < 0) { - /* truncated packet */ - return -1; - } - m_adj(m_head, -trim); - tot_len = m_head->m_pkthdr.len; - } - - m_nxt = m_head; - m_tail = NULL; /* -Wuninitialized */ - while (m_nxt != NULL) { - m_tail = m_nxt; - m_nxt = m_tail->m_next; - } - - hlen = ip_len + ETHER_HDR_LEN - tcp_data_len; - seq = ntohl(tcp->th_seq); - - SLIST_FOREACH(lro, &ss->lro_active, next) { - if (lro->source_port == tcp->th_sport && - lro->dest_port == tcp->th_dport && - lro->source_ip == ip->ip_src.s_addr && - lro->dest_ip == ip->ip_dst.s_addr) { - /* Try to append it */ - - if (__predict_false(seq != lro->next_seq || - (tcp_data_len == 0 && - lro->ack_seq == tcp->th_ack))) { - /* out of order packet or dup ack */ - SLIST_REMOVE(&ss->lro_active, lro, - lro_entry, next); - mxge_lro_flush(ss, lro); - return -1; - } - - if (opt_bytes) { - uint32_t tsval = ntohl(*(ts_ptr + 1)); - /* make sure timestamp values are increasing */ - if (__predict_false(lro->tsval > tsval || - *(ts_ptr + 2) == 0)) { - return -1; - } - lro->tsval = tsval; - lro->tsecr = *(ts_ptr + 2); - } - - lro->next_seq += tcp_data_len; - lro->ack_seq = tcp->th_ack; - lro->window = tcp->th_win; - lro->append_cnt++; - if (tcp_data_len == 0) { - m_freem(m_head); - return 0; - } - /* subtract off the checksum of the tcp header - * from the hardware checksum, and add it to the - * stored tcp data checksum. Byteswap the checksum - * if the total length so far is odd - */ - tmp_csum = mxge_csum_generic((uint16_t*)tcp, - tcp_hdr_len); - csum = csum + (tmp_csum ^ 0xffff); - csum = (csum & 0xffff) + (csum >> 16); - csum = (csum & 0xffff) + (csum >> 16); - if (lro->len & 0x1) { - /* Odd number of bytes so far, flip bytes */ - csum = ((csum << 8) | (csum >> 8)) & 0xffff; - } - csum = csum + lro->data_csum; - csum = (csum & 0xffff) + (csum >> 16); - csum = (csum & 0xffff) + (csum >> 16); - lro->data_csum = csum; - - lro->len += tcp_data_len; - - /* adjust mbuf so that m->m_data points to - the first byte of the payload */ - m_adj(m_head, hlen); - /* append mbuf chain */ - lro->m_tail->m_next = m_head; - /* advance the last pointer */ - lro->m_tail = m_tail; - /* flush packet if required */ - device_mtu = ss->sc->ifp->if_mtu; - if (lro->len > (65535 - device_mtu)) { - SLIST_REMOVE(&ss->lro_active, lro, - lro_entry, next); - mxge_lro_flush(ss, lro); - } - return 0; - } - } - - if (SLIST_EMPTY(&ss->lro_free)) - return -1; - - /* start a new chain */ - lro = SLIST_FIRST(&ss->lro_free); - SLIST_REMOVE_HEAD(&ss->lro_free, next); - SLIST_INSERT_HEAD(&ss->lro_active, lro, next); - lro->source_port = tcp->th_sport; - lro->dest_port = tcp->th_dport; - lro->source_ip = ip->ip_src.s_addr; - lro->dest_ip = ip->ip_dst.s_addr; - lro->next_seq = seq + tcp_data_len; - lro->mss = tcp_data_len; - lro->ack_seq = tcp->th_ack; - lro->window = tcp->th_win; - - /* save the checksum of just the TCP payload by - * subtracting off the checksum of the TCP header from - * the entire hardware checksum - * Since IP header checksum is correct, checksum over - * the IP header is -0. Substracting -0 is unnecessary. - */ - tmp_csum = mxge_csum_generic((uint16_t*)tcp, tcp_hdr_len); - csum = csum + (tmp_csum ^ 0xffff); - csum = (csum & 0xffff) + (csum >> 16); - csum = (csum & 0xffff) + (csum >> 16); - lro->data_csum = csum; - - lro->ip = ip; - /* record timestamp if it is present */ - if (opt_bytes) { - lro->timestamp = 1; - lro->tsval = ntohl(*(ts_ptr + 1)); - lro->tsecr = *(ts_ptr + 2); - } - lro->len = tot_len; - lro->m_head = m_head; - lro->m_tail = m_tail; - return 0; -} - -#endif /* INET */ -/* - This file uses Myri10GE driver indentation. - - Local Variables: - c-file-style:"linux" - tab-width:8 - End: -*/ diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c index f08ba85..86b6987 100644 --- a/sys/fs/nfs/nfs_commonkrpc.c +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -1080,7 +1080,6 @@ newnfs_set_sigmask(struct thread *td, sigset_t *oldset) SIGDELSET(newset, newnfs_sig_set[i]); } mtx_unlock(&p->p_sigacts->ps_mtx); - sigdeferstop(td); kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, SIGPROCMASK_PROC_LOCKED); PROC_UNLOCK(p); @@ -1092,7 +1091,6 @@ newnfs_restore_sigmask(struct thread *td, sigset_t *set) if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); - sigallowstop(td); } /* diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index 83ce3cb..281ce44 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -132,7 +132,7 @@ static struct vfsops nfs_vfsops = { .vfs_unmount = nfs_unmount, .vfs_sysctl = nfs_sysctl, }; -VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); +VFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(nfs, 1); diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 7d3634d..e1dbedc 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2537,16 +2537,22 @@ tdsigcleanup(struct thread *td) } -/* Defer the delivery of SIGSTOP for the current thread. */ -void -sigdeferstop(struct thread *td) +/* + * Defer the delivery of SIGSTOP for the current thread. Returns true + * if stops were deferred and false if they were already deferred. + */ +int +sigdeferstop(void) { + struct thread *td; - KASSERT(!(td->td_flags & TDF_SBDRY), - ("attempt to set TDF_SBDRY recursively")); + td = curthread; + if (td->td_flags & TDF_SBDRY) + return (0); thread_lock(td); td->td_flags |= TDF_SBDRY; thread_unlock(td); + return (1); } /* @@ -2555,11 +2561,11 @@ sigdeferstop(struct thread *td) * will suspend either via ast() or a subsequent interruptible sleep. */ void -sigallowstop(struct thread *td) +sigallowstop() { + struct thread *td; - KASSERT(td->td_flags & TDF_SBDRY, - ("attempt to clear already-cleared TDF_SBDRY")); + td = curthread; thread_lock(td); td->td_flags &= ~TDF_SBDRY; thread_unlock(td); diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 22cabcb..bd06f20 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -164,6 +164,8 @@ userret(struct thread *td, struct trapframe *frame) ("userret: Returning with with pinned thread")); KASSERT(td->td_vp_reserv == 0, ("userret: Returning while holding vnode reservation")); + KASSERT((td->td_flags & TDF_SBDRY) == 0, + ("userret: Returning with stop signals deferred")); #ifdef VIMAGE /* Unfortunately td_vnet_lpush needs VNET_DEBUG. */ VNET_ASSERT(curvnet == NULL, diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 114c23e..6a3f291 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index e5ee4f6..fbde152 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -339,7 +339,7 @@ namei(struct nameidata *ndp) auio.uio_offset = 0; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; - auio.uio_td = (struct thread *)0; + auio.uio_td = td; auio.uio_resid = MAXPATHLEN; error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); if (error) { diff --git a/sys/modules/mxge/mxge/Makefile b/sys/modules/mxge/mxge/Makefile index 90c30eb..3f1f80f 100644 --- a/sys/modules/mxge/mxge/Makefile +++ b/sys/modules/mxge/mxge/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../../dev/mxge KMOD= if_mxge -SRCS= if_mxge.c mxge_lro.c device_if.h bus_if.h pci_if.h opt_inet.h opt_inet6.h +SRCS= if_mxge.c device_if.h bus_if.h pci_if.h opt_inet.h opt_inet6.h .include diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c index 3718e4d..032d47c 100644 --- a/sys/netinet/tcp_lro.c +++ b/sys/netinet/tcp_lro.c @@ -333,7 +333,7 @@ tcp_lro_rx_ipv4(struct lro_ctrl *lc, struct mbuf *m, struct ip *ip4, } } else { csum = in_cksum_hdr(ip4); - if (__predict_false((csum ^ 0xffff) != 0)) { + if (__predict_false((csum) != 0)) { lc->lro_bad_csum++; return (TCP_LRO_CANNOT); } diff --git a/sys/nfsclient/nfs_krpc.c b/sys/nfsclient/nfs_krpc.c index 851b0b6..d3082d8 100644 --- a/sys/nfsclient/nfs_krpc.c +++ b/sys/nfsclient/nfs_krpc.c @@ -748,7 +748,6 @@ nfs_set_sigmask(struct thread *td, sigset_t *oldset) SIGDELSET(newset, nfs_sig_set[i]); } mtx_unlock(&p->p_sigacts->ps_mtx); - sigdeferstop(td); kern_sigprocmask(td, SIG_SETMASK, &newset, oldset, SIGPROCMASK_PROC_LOCKED); PROC_UNLOCK(p); @@ -760,7 +759,6 @@ nfs_restore_sigmask(struct thread *td, sigset_t *set) if (td == NULL) td = curthread; /* XXX */ kern_sigprocmask(td, SIG_SETMASK, set, NULL, 0); - sigallowstop(td); } /* diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index 63b5772..9cec307 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -146,7 +146,7 @@ static struct vfsops nfs_vfsops = { .vfs_unmount = nfs_unmount, .vfs_sysctl = nfs_sysctl, }; -VFS_SET(nfs_vfsops, oldnfs, VFCF_NETWORK); +VFS_SET(nfs_vfsops, oldnfs, VFCF_NETWORK | VFCF_SBDRY); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_VERSION(oldnfs, 1); diff --git a/sys/sys/mount.h b/sys/sys/mount.h index bbbc569..f73d5d7 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -493,6 +493,7 @@ struct ovfsconf { #define VFCF_UNICODE 0x00200000 /* stores file names as Unicode */ #define VFCF_JAIL 0x00400000 /* can be mounted from within a jail */ #define VFCF_DELEGADMIN 0x00800000 /* supports delegated administration */ +#define VFCF_SBDRY 0x01000000 /* defer stop requests */ typedef uint32_t fsctlop_t; @@ -629,30 +630,121 @@ struct vfsops { vfs_statfs_t __vfs_statfs; -#define VFS_MOUNT(MP) (*(MP)->mnt_op->vfs_mount)(MP) -#define VFS_UNMOUNT(MP, FORCE) (*(MP)->mnt_op->vfs_unmount)(MP, FORCE) -#define VFS_ROOT(MP, FLAGS, VPP) \ - (*(MP)->mnt_op->vfs_root)(MP, FLAGS, VPP) -#define VFS_QUOTACTL(MP, C, U, A) \ - (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A) -#define VFS_STATFS(MP, SBP) __vfs_statfs((MP), (SBP)) -#define VFS_SYNC(MP, WAIT) (*(MP)->mnt_op->vfs_sync)(MP, WAIT) -#define VFS_VGET(MP, INO, FLAGS, VPP) \ - (*(MP)->mnt_op->vfs_vget)(MP, INO, FLAGS, VPP) -#define VFS_FHTOVP(MP, FIDP, FLAGS, VPP) \ - (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, FLAGS, VPP) -#define VFS_CHECKEXP(MP, NAM, EXFLG, CRED, NUMSEC, SEC) \ - (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED, NUMSEC, SEC) -#define VFS_EXTATTRCTL(MP, C, FN, NS, N) \ - (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N) -#define VFS_SYSCTL(MP, OP, REQ) \ - (*(MP)->mnt_op->vfs_sysctl)(MP, OP, REQ) -#define VFS_SUSP_CLEAN(MP) \ - ({if (*(MP)->mnt_op->vfs_susp_clean != NULL) \ - (*(MP)->mnt_op->vfs_susp_clean)(MP); }) -#define VFS_RECLAIM_LOWERVP(MP, VP) \ - ({if (*(MP)->mnt_op->vfs_reclaim_lowervp != NULL) \ - (*(MP)->mnt_op->vfs_reclaim_lowervp)((MP), (VP)); }) +#define VFS_PROLOGUE(MP) do { \ + int _enable_stops; \ + \ + _enable_stops = ((MP) != NULL && \ + ((MP)->mnt_vfc->vfc_flags & VFCF_SBDRY) && sigdeferstop()) + +#define VFS_EPILOGUE(MP) \ + if (_enable_stops) \ + sigallowstop(); \ +} while (0) + +#define VFS_MOUNT(MP) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_mount)(MP); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_UNMOUNT(MP, FORCE) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_unmount)(MP, FORCE); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_ROOT(MP, FLAGS, VPP) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_root)(MP, FLAGS, VPP); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_QUOTACTL(MP, C, U, A) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_quotactl)(MP, C, U, A); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_STATFS(MP, SBP) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = __vfs_statfs((MP), (SBP)); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_SYNC(MP, WAIT) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_sync)(MP, WAIT); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_VGET(MP, INO, FLAGS, VPP) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_vget)(MP, INO, FLAGS, VPP); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_FHTOVP(MP, FIDP, FLAGS, VPP) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_fhtovp)(MP, FIDP, FLAGS, VPP); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_CHECKEXP(MP, NAM, EXFLG, CRED, NUMSEC, SEC) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_checkexp)(MP, NAM, EXFLG, CRED, NUMSEC,\ + SEC); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_EXTATTRCTL(MP, C, FN, NS, N) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_SYSCTL(MP, OP, REQ) ({ \ + int _rc; \ + \ + VFS_PROLOGUE(MP); \ + _rc = (*(MP)->mnt_op->vfs_sysctl)(MP, OP, REQ); \ + VFS_EPILOGUE(MP); \ + _rc; }) + +#define VFS_SUSP_CLEAN(MP) do { \ + if (*(MP)->mnt_op->vfs_susp_clean != NULL) { \ + VFS_PROLOGUE(MP); \ + (*(MP)->mnt_op->vfs_susp_clean)(MP); \ + VFS_EPILOGUE(MP); \ + } \ +} while (0) + +#define VFS_RECLAIM_LOWERVP(MP, VP) do { \ + if (*(MP)->mnt_op->vfs_reclaim_lowervp != NULL) { \ + VFS_PROLOGUE(MP); \ + (*(MP)->mnt_op->vfs_reclaim_lowervp)((MP), (VP)); \ + VFS_EPILOGUE(MP); \ + } \ +} while (0) #define VFS_KNOTE_LOCKED(vp, hint) do \ { \ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 91655b2..fcf25ad 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -328,8 +328,8 @@ extern struct mtx sigio_lock; #define SIGPROCMASK_PS_LOCKED 0x0004 int cursig(struct thread *td, int stop_allowed); -void sigdeferstop(struct thread *td); -void sigallowstop(struct thread *td); +int sigdeferstop(void); +void sigallowstop(void); void execsigs(struct proc *p); void gsignal(int pgid, int sig, ksiginfo_t *ksi); void killproc(struct proc *p, char *why); diff --git a/sys/sys/systm.h b/sys/sys/systm.h index d9fdef0..611d014 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -330,8 +330,6 @@ static __inline intrmask_t splclock(void) { return 0; } static __inline intrmask_t splhigh(void) { return 0; } static __inline intrmask_t splimp(void) { return 0; } static __inline intrmask_t splnet(void) { return 0; } -static __inline intrmask_t splsoftclock(void) { return 0; } -static __inline intrmask_t splsoftvm(void) { return 0; } static __inline intrmask_t spltty(void) { return 0; } static __inline intrmask_t splvm(void) { return 0; } static __inline void splx(intrmask_t ipl __unused) { return; } diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk index c991458..2347004 100644 --- a/sys/tools/vnode_if.awk +++ b/sys/tools/vnode_if.awk @@ -172,6 +172,7 @@ if (cfile) { "#include \n" \ "#include \n" \ "#include \n" \ + "#include \n" \ "#include \n" \ "#include \n" \ "\n" \ @@ -365,10 +366,12 @@ while ((getline < srcfile) > 0) { add_debug_code(name, args[i], "Entry", "\t"); printc("\tKTR_START" ctrstr); add_pre(name); + printc("\tVFS_PROLOGUE(a->a_" args[0]"->v_mount);") printc("\tif (vop->"name" != NULL)") printc("\t\trc = vop->"name"(a);") printc("\telse") printc("\t\trc = vop->vop_bypass(&a->a_gen);") + printc("\tVFS_EPILOGUE(a->a_" args[0]"->v_mount);") printc("\tSDT_PROBE(vfs, vop, " name ", return, a->a_" args[0] ", a, rc, 0, 0);\n"); printc("\tif (rc == 0) {"); for (i = 0; i < numargs; ++i) diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c index b42beac..c6a6f8c 100644 --- a/sys/x86/isa/atrtc.c +++ b/sys/x86/isa/atrtc.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -52,8 +53,8 @@ __FBSDID("$FreeBSD$"); #include #include "clock_if.h" -#define RTC_LOCK mtx_lock_spin(&clock_lock) -#define RTC_UNLOCK mtx_unlock_spin(&clock_lock) +#define RTC_LOCK do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0) +#define RTC_UNLOCK do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0) int atrtcclock_disable = 0; @@ -335,10 +336,16 @@ atrtc_gettime(device_t dev, struct timespec *ts) return (EINVAL); } - /* wait for time update to complete */ - /* If RTCSA_TUP is zero, we have at least 244us before next update */ + /* + * wait for time update to complete + * If RTCSA_TUP is zero, we have at least 244us before next update. + * This is fast enough on most hardware, but a refinement would be + * to make sure that no more than 240us pass after we start reading, + * and try again if so. + */ while (rtcin(RTC_STATUSA) & RTCSA_TUP) continue; + critical_enter(); ct.nsec = 0; ct.sec = readrtc(RTC_SEC); ct.min = readrtc(RTC_MIN); @@ -352,6 +359,7 @@ atrtc_gettime(device_t dev, struct timespec *ts) #else ct.year += 2000; #endif + critical_exit(); /* Set dow = -1 because some clocks don't set it correctly. */ ct.dow = -1; return (clock_ct_to_ts(&ct, ts)); -- cgit v1.1