diff options
Diffstat (limited to 'sys/dev')
62 files changed, 1453 insertions, 469 deletions
diff --git a/sys/dev/ahci/ahci_pci.c b/sys/dev/ahci/ahci_pci.c index f29d803e99a8..82f56fc0d19e 100644 --- a/sys/dev/ahci/ahci_pci.c +++ b/sys/dev/ahci/ahci_pci.c @@ -195,6 +195,7 @@ static const struct { {0x1f3f8086, 0x00, "Intel Avoton (RAID)", 0}, {0x23a38086, 0x00, "Intel Coleto Creek", 0}, {0x31e38086, 0x00, "Intel Gemini Lake", 0}, + {0x4b638086, 0x00, "Intel Elkhart Lake", 0}, {0x5ae38086, 0x00, "Intel Apollo Lake", 0}, {0x7ae28086, 0x00, "Intel Alder Lake", 0}, {0x8c028086, 0x00, "Intel Lynx Point", 0}, diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c index 291d1ec64ed7..79bf08678249 100644 --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -179,7 +179,7 @@ ath_rate_sample_find_min_pktlength(struct ath_softc *sc, const struct txschedule *sched = &sn->sched[rix0]; int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE // Note: this may not be true in all cases; need to check? - int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40); + int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40); // Note: not great, but good enough.. int idx = is_ht40 ? MCS_HT40 : MCS_HT20; @@ -979,7 +979,7 @@ update_stats(struct ath_softc *sc, struct ath_node *an, const int size_bin = size_to_bin(frame_size); const int size = bin_to_size(size_bin); int tt; - int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40); + int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40); int pct; if (!IS_RATE_DEFINED(sn, rix0)) @@ -1365,7 +1365,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) continue; printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), calc_usecs_unicast_packet(sc, 1600, rix, 0,0, - (ni->ni_chw == IEEE80211_STA_RX_BW_40))); + (ni->ni_chw == NET80211_STA_RX_BW_40))); } printf("\n"); } @@ -1396,7 +1396,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) sn->stats[y][rix].perfect_tx_time = calc_usecs_unicast_packet(sc, size, rix, 0, 0, - (ni->ni_chw == IEEE80211_STA_RX_BW_40)); + (ni->ni_chw == NET80211_STA_RX_BW_40)); sn->stats[y][rix].average_tx_time = sn->stats[y][rix].perfect_tx_time; } diff --git a/sys/dev/ath/if_ath_tx_ht.c b/sys/dev/ath/if_ath_tx_ht.c index e7ee029fecf0..f42058bacb0d 100644 --- a/sys/dev/ath/if_ath_tx_ht.c +++ b/sys/dev/ath/if_ath_tx_ht.c @@ -283,7 +283,7 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) if (IS_HT_RATE(rate)) { rc[i].flags |= ATH_RC_HT_FLAG; - if (ni->ni_chw == IEEE80211_STA_RX_BW_40) + if (ni->ni_chw == NET80211_STA_RX_BW_40) rc[i].flags |= ATH_RC_CW40_FLAG; /* @@ -295,13 +295,13 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf) * and doesn't return the fractional part, so * we are always "out" by some amount. */ - if (ni->ni_chw == IEEE80211_STA_RX_BW_40 && + if (ni->ni_chw == NET80211_STA_RX_BW_40 && ieee80211_ht_check_tx_shortgi_40(ni) && (bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) { rc[i].flags |= ATH_RC_SGI_FLAG; } - if (ni->ni_chw == IEEE80211_STA_RX_BW_20 && + if (ni->ni_chw == NET80211_STA_RX_BW_20 && ieee80211_ht_check_tx_shortgi_20(ni) && (bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) { rc[i].flags |= ATH_RC_SGI_FLAG; diff --git a/sys/dev/axgbe/if_axgbe_pci.c b/sys/dev/axgbe/if_axgbe_pci.c index 290156ff11ca..6bc4bd33e162 100644 --- a/sys/dev/axgbe/if_axgbe_pci.c +++ b/sys/dev/axgbe/if_axgbe_pci.c @@ -2415,7 +2415,8 @@ axgbe_if_get_counter(if_ctx_t ctx, ift_counter cnt) case IFCOUNTER_OPACKETS: return (pstats->txframecount_gb); case IFCOUNTER_OERRORS: - return (pstats->txframecount_gb - pstats->txframecount_g); + return (if_get_counter_default(ifp, cnt) + + pstats->txframecount_gb - pstats->txframecount_g); case IFCOUNTER_IBYTES: return (pstats->rxoctetcount_gb); case IFCOUNTER_OBYTES: diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index 9e91250cb61c..9756a6945384 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -9016,7 +9016,7 @@ sysctl_loadavg(SYSCTL_HANDLER_ARGS) rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4lavg"); if (rc) return (rc); - if (hw_all_ok(sc)) + if (!hw_all_ok(sc)) rc = ENXIO; else { param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | diff --git a/sys/dev/cyapa/cyapa.c b/sys/dev/cyapa/cyapa.c index 50fa4faa560a..ed755f992949 100644 --- a/sys/dev/cyapa/cyapa.c +++ b/sys/dev/cyapa/cyapa.c @@ -761,42 +761,60 @@ again: /* * Generate report */ - c0 = 0; - if (delta_x < 0) - c0 |= 0x10; - if (delta_y < 0) - c0 |= 0x20; - c0 |= 0x08; - if (but & CYAPA_FNGR_LEFT) - c0 |= 0x01; - if (but & CYAPA_FNGR_MIDDLE) - c0 |= 0x04; - if (but & CYAPA_FNGR_RIGHT) - c0 |= 0x02; - - fifo_write_char(sc, &sc->rfifo, c0); - fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x); - fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y); - switch(sc->zenabled) { - case 1: - /* Z axis all 8 bits */ - fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z); - break; - case 2: - /* - * Z axis low 4 bits + 4th button and 5th button - * (high 2 bits must be left 0). Auto-scale - * delta_z to fit to avoid a wrong-direction - * overflow (don't try to retain the remainder). - */ - while (delta_z > 7 || delta_z < -8) - delta_z >>= 1; - c0 = (uint8_t)delta_z & 0x0F; + if (sc->mode.level == 1) { + c0 = MOUSE_SYS_SYNC; + if (but & CYAPA_FNGR_LEFT) + c0 |= MOUSE_SYS_BUTTON1UP; + if (but & CYAPA_FNGR_MIDDLE) + c0 |= MOUSE_SYS_BUTTON2UP; + if (but & CYAPA_FNGR_RIGHT) + c0 |= MOUSE_SYS_BUTTON3UP; fifo_write_char(sc, &sc->rfifo, c0); - break; - default: - /* basic PS/2 */ - break; + fifo_write_char(sc, &sc->rfifo, delta_x >> 1); + fifo_write_char(sc, &sc->rfifo, delta_y >> 1); + fifo_write_char(sc, &sc->rfifo, delta_x - (delta_x >> 1)); + fifo_write_char(sc, &sc->rfifo, delta_y - (delta_y >> 1)); + fifo_write_char(sc, &sc->rfifo, delta_z >> 1); + fifo_write_char(sc, &sc->rfifo, delta_z - (delta_z >> 1)); + fifo_write_char(sc, &sc->rfifo, MOUSE_SYS_EXTBUTTONS); + } else { + c0 = 0; + if (delta_x < 0) + c0 |= 0x10; + if (delta_y < 0) + c0 |= 0x20; + c0 |= 0x08; + if (but & CYAPA_FNGR_LEFT) + c0 |= 0x01; + if (but & CYAPA_FNGR_MIDDLE) + c0 |= 0x04; + if (but & CYAPA_FNGR_RIGHT) + c0 |= 0x02; + + fifo_write_char(sc, &sc->rfifo, c0); + fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x); + fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y); + switch(sc->zenabled) { + case 1: + /* Z axis all 8 bits */ + fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z); + break; + case 2: + /* + * Z axis low 4 bits + 4th button and 5th button + * (high 2 bits must be left 0). Auto-scale + * delta_z to fit to avoid a wrong-direction + * overflow (don't try to retain the remainder). + */ + while (delta_z > 7 || delta_z < -8) + delta_z >>= 1; + c0 = (uint8_t)delta_z & 0x0F; + fifo_write_char(sc, &sc->rfifo, c0); + break; + default: + /* basic PS/2 */ + break; + } } cyapa_notify(sc); } @@ -1205,6 +1223,11 @@ cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread ((mousemode_t *)data)->packetsize = MOUSE_PS2_PACKETSIZE; break; + case 1: + ((mousemode_t *)data)->protocol = MOUSE_PROTO_SYSMOUSE; + ((mousemode_t *)data)->packetsize = + MOUSE_SYS_PACKETSIZE; + break; case 2: ((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2; ((mousemode_t *)data)->packetsize = @@ -1223,7 +1246,7 @@ cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread error = EINVAL; break; } - sc->mode.level = *(int *)data ? 2 : 0; + sc->mode.level = *(int *)data; sc->zenabled = sc->mode.level ? 1 : 0; break; diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 9c5ae2806f75..60959fe679b8 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -4782,8 +4782,8 @@ em_if_get_counter(if_ctx_t ctx, ift_counter cnt) sc->stats.ruc + sc->stats.roc + sc->stats.mpc + sc->stats.cexterr); case IFCOUNTER_OERRORS: - return (sc->stats.ecol + sc->stats.latecol + - sc->watchdog_events); + return (if_get_counter_default(ifp, cnt) + + sc->stats.ecol + sc->stats.latecol + sc->watchdog_events); default: return (if_get_counter_default(ifp, cnt)); } diff --git a/sys/dev/enetc/if_enetc.c b/sys/dev/enetc/if_enetc.c index 3a5d6ec23282..808397b229a7 100644 --- a/sys/dev/enetc/if_enetc.c +++ b/sys/dev/enetc/if_enetc.c @@ -1343,7 +1343,8 @@ enetc_get_counter(if_ctx_t ctx, ift_counter cnt) case IFCOUNTER_IERRORS: return (ENETC_PORT_RD8(sc, ENETC_PM0_RERR)); case IFCOUNTER_OERRORS: - return (ENETC_PORT_RD8(sc, ENETC_PM0_TERR)); + return (if_get_counter_default(ifp, cnt) + + ENETC_PORT_RD8(sc, ENETC_PM0_TERR)); default: return (if_get_counter_default(ifp, cnt)); } diff --git a/sys/dev/gpio/gpioled.c b/sys/dev/gpio/gpioled.c index ba53cb733971..71af5741b2fe 100644 --- a/sys/dev/gpio/gpioled.c +++ b/sys/dev/gpio/gpioled.c @@ -55,13 +55,13 @@ device_get_nameunit((_sc)->sc_dev), "gpioled", MTX_DEF) #define GPIOLED_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) -struct gpioled_softc +struct gpioled_softc { device_t sc_dev; device_t sc_busdev; struct mtx sc_mtx; struct cdev *sc_leddev; - int sc_invert; + int sc_softinvert; }; static void gpioled_control(void *, int); @@ -69,20 +69,19 @@ static int gpioled_probe(device_t); static int gpioled_attach(device_t); static int gpioled_detach(device_t); -static void +static void gpioled_control(void *priv, int onoff) { struct gpioled_softc *sc; sc = (struct gpioled_softc *)priv; + if (onoff == -1) /* Keep the current state. */ + return; + if (sc->sc_softinvert) + onoff = !onoff; GPIOLED_LOCK(sc); - if (GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, - GPIO_PIN_OUTPUT) == 0) { - if (sc->sc_invert) - onoff = !onoff; - GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, - onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW); - } + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, + onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW); GPIOLED_UNLOCK(sc); } @@ -95,26 +94,101 @@ gpioled_probe(device_t dev) } static int +gpioled_inv(device_t dev, uint32_t *pin_flags) +{ + struct gpioled_softc *sc; + int invert; + uint32_t pin_caps; + + sc = device_get_softc(dev); + + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "invert", &invert)) + invert = 0; + + if (GPIOBUS_PIN_GETCAPS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, + &pin_caps) != 0) { + if (bootverbose) + device_printf(sc->sc_dev, "unable to get pin caps\n"); + return (-1); + } + if (pin_caps & GPIO_PIN_INVOUT) + *pin_flags &= ~GPIO_PIN_INVOUT; + sc->sc_softinvert = 0; + if (invert) { + const char *invmode; + + if (resource_string_value(device_get_name(dev), + device_get_unit(dev), "invmode", &invmode)) + invmode = NULL; + + if (invmode) { + if (!strcmp(invmode, "sw")) + sc->sc_softinvert = 1; + else if (!strcmp(invmode, "hw")) { + if (pin_caps & GPIO_PIN_INVOUT) + *pin_flags |= GPIO_PIN_INVOUT; + else { + device_printf(sc->sc_dev, "hardware pin inversion not supported\n"); + return (-1); + } + } else { + if (strcmp(invmode, "auto") != 0) + device_printf(sc->sc_dev, "invalid pin inversion mode\n"); + invmode = NULL; + } + } + /* + * auto inversion mode: use hardware support if available, else fallback to + * software emulation. + */ + if (invmode == NULL) { + if (pin_caps & GPIO_PIN_INVOUT) + *pin_flags |= GPIO_PIN_INVOUT; + else + sc->sc_softinvert = 1; + } + } + MPASS(!invert || + (((*pin_flags & GPIO_PIN_INVOUT) != 0) && !sc->sc_softinvert) || + (((*pin_flags & GPIO_PIN_INVOUT) == 0) && sc->sc_softinvert)); + return (invert); +} + +static int gpioled_attach(device_t dev) { struct gpioled_softc *sc; int state; const char *name; + uint32_t pin_flags; + int invert; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busdev = device_get_parent(dev); GPIOLED_LOCK_INIT(sc); - state = 0; - - if (resource_string_value(device_get_name(dev), + if (resource_string_value(device_get_name(dev), device_get_unit(dev), "name", &name)) name = NULL; - resource_int_value(device_get_name(dev), - device_get_unit(dev), "invert", &sc->sc_invert); - resource_int_value(device_get_name(dev), - device_get_unit(dev), "state", &state); + + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "state", &state)) + state = 0; + + pin_flags = GPIO_PIN_OUTPUT; + invert = gpioled_inv(dev, &pin_flags); + if (invert < 0) + return (ENXIO); + device_printf(sc->sc_dev, "state %d invert %s\n", + state, (invert ? (sc->sc_softinvert ? "sw" : "hw") : "no")); + if (GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, + pin_flags) != 0) { + if (bootverbose) + device_printf(sc->sc_dev, "unable to set pin flags, %#x\n", pin_flags); + return (ENXIO); + } sc->sc_leddev = led_create_state(gpioled_control, sc, name ? name : device_get_nameunit(dev), state); diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c index 9b85c989dc96..a6a6ae68996c 100644 --- a/sys/dev/hwpmc/hwpmc_mod.c +++ b/sys/dev/hwpmc/hwpmc_mod.c @@ -210,7 +210,7 @@ static int pmc_attach_one_process(struct proc *p, struct pmc *pm); static bool pmc_can_allocate_row(int ri, enum pmc_mode mode); static bool pmc_can_allocate_rowindex(struct proc *p, unsigned int ri, int cpu); -static int pmc_can_attach(struct pmc *pm, struct proc *p); +static bool pmc_can_attach(struct pmc *pm, struct proc *p); static void pmc_capture_user_callchain(int cpu, int soft, struct trapframe *tf); static void pmc_cleanup(void); @@ -1029,19 +1029,19 @@ pmc_unlink_target_process(struct pmc *pm, struct pmc_process *pp) * Check if PMC 'pm' may be attached to target process 't'. */ -static int +static bool pmc_can_attach(struct pmc *pm, struct proc *t) { struct proc *o; /* pmc owner */ struct ucred *oc, *tc; /* owner, target credentials */ - int decline_attach, i; + bool decline_attach; /* * A PMC's owner can always attach that PMC to itself. */ if ((o = pm->pm_owner->po_owner) == t) - return 0; + return (true); PROC_LOCK(o); oc = o->p_ucred; @@ -1066,18 +1066,17 @@ pmc_can_attach(struct pmc *pm, struct proc *t) * Every one of the target's group ids, must be in the owner's * group list. */ - for (i = 0; !decline_attach && i < tc->cr_ngroups; i++) + for (int i = 0; !decline_attach && i < tc->cr_ngroups; i++) decline_attach = !groupmember(tc->cr_groups[i], oc); - - /* check the read and saved gids too */ - if (decline_attach == 0) - decline_attach = !groupmember(tc->cr_rgid, oc) || + if (!decline_attach) + decline_attach = !groupmember(tc->cr_gid, oc) || + !groupmember(tc->cr_rgid, oc) || !groupmember(tc->cr_svgid, oc); crfree(tc); crfree(oc); - return !decline_attach; + return (!decline_attach); } /* @@ -1412,7 +1411,7 @@ pmc_process_exec(struct thread *td, struct pmckern_procexec *pk) */ for (ri = 0; ri < md->pmd_npmc; ri++) { if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL) { - if (pmc_can_attach(pm, td->td_proc) != 0) { + if (pmc_can_attach(pm, td->td_proc)) { pmc_detach_one_process(td->td_proc, pm, PMC_FLAG_NONE); } diff --git a/sys/dev/hwt/hwt_ioctl.c b/sys/dev/hwt/hwt_ioctl.c index 592db4931bb4..184c7e72f986 100644 --- a/sys/dev/hwt/hwt_ioctl.c +++ b/sys/dev/hwt/hwt_ioctl.c @@ -112,12 +112,11 @@ hwt_priv_check(struct proc *o, struct proc *t) error = EPERM; goto done; } - - /* Check the read and saved GIDs too. */ - if (!groupmember(tc->cr_rgid, oc) || + if (!groupmember(tc->cr_gid, oc) || + !groupmember(tc->cr_rgid, oc) || !groupmember(tc->cr_svgid, oc)) { - error = EPERM; - goto done; + error = EPERM; + goto done; } done: diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c index 442111e5ffaf..8b6349f686eb 100644 --- a/sys/dev/ice/ice_lib.c +++ b/sys/dev/ice/ice_lib.c @@ -7818,7 +7818,8 @@ ice_get_ifnet_counter(struct ice_vsi *vsi, ift_counter counter) case IFCOUNTER_OPACKETS: return (es->tx_unicast + es->tx_multicast + es->tx_broadcast); case IFCOUNTER_OERRORS: - return (es->tx_errors); + return (if_get_counter_default(vsi->sc->ifp, counter) + + es->tx_errors); case IFCOUNTER_COLLISIONS: return (0); case IFCOUNTER_IBYTES: @@ -7832,7 +7833,8 @@ ice_get_ifnet_counter(struct ice_vsi *vsi, ift_counter counter) case IFCOUNTER_IQDROPS: return (es->rx_discards); case IFCOUNTER_OQDROPS: - return (hs->tx_dropped_link_down); + return (if_get_counter_default(vsi->sc->ifp, counter) + + hs->tx_dropped_link_down); case IFCOUNTER_NOPROTO: return (es->rx_unknown_protocol); default: diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c index 728bb942d503..e4d87fe1fed2 100644 --- a/sys/dev/ichsmb/ichsmb_pci.c +++ b/sys/dev/ichsmb/ichsmb_pci.c @@ -107,6 +107,7 @@ #define ID_COMETLAKE2 0x06a3 #define ID_TIGERLAKE 0xa0a3 #define ID_TIGERLAKE2 0x43a3 +#define ID_ELKHARTLAKE 0x4b23 #define ID_GEMINILAKE 0x31d4 #define ID_CEDARFORK 0x18df #define ID_ICELAKE 0x34a3 @@ -206,6 +207,8 @@ static const struct pci_device_table ichsmb_devices[] = { PCI_DESCR("Intel Tiger Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_TIGERLAKE2), PCI_DESCR("Intel Tiger Lake SMBus controller") }, + { PCI_DEV(PCI_VENDOR_INTEL, ID_ELKHARTLAKE), + PCI_DESCR("Intel Elkhart Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_GEMINILAKE), PCI_DESCR("Intel Gemini Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_CEDARFORK), diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c index a1ae35c7aa43..f199a128c783 100644 --- a/sys/dev/igc/if_igc.c +++ b/sys/dev/igc/if_igc.c @@ -2599,8 +2599,8 @@ igc_if_get_counter(if_ctx_t ctx, ift_counter cnt) sc->stats.ruc + sc->stats.roc + sc->stats.mpc + sc->stats.htdpmc); case IFCOUNTER_OERRORS: - return (sc->stats.ecol + sc->stats.latecol + - sc->watchdog_events); + return (if_get_counter_default(ifp, cnt) + + sc->stats.ecol + sc->stats.latecol + sc->watchdog_events); default: return (if_get_counter_default(ifp, cnt)); } diff --git a/sys/dev/iommu/busdma_iommu.c b/sys/dev/iommu/busdma_iommu.c index 6856b0551dde..668ccf056463 100644 --- a/sys/dev/iommu/busdma_iommu.c +++ b/sys/dev/iommu/busdma_iommu.c @@ -114,8 +114,8 @@ iommu_bus_dma_is_dev_disabled(int domain, int bus, int slot, int func) * domain, and must collectively be assigned to use either IOMMU or * bounce mapping. */ -device_t -iommu_get_requester(device_t dev, uint16_t *rid) +int +iommu_get_requester(device_t dev, device_t *requesterp, uint16_t *rid) { devclass_t pci_class; device_t l, pci, pcib, pcip, pcibp, requester; @@ -129,7 +129,8 @@ iommu_get_requester(device_t dev, uint16_t *rid) pci = device_get_parent(dev); if (pci == NULL || device_get_devclass(pci) != pci_class) { *rid = 0; /* XXXKIB: Could be ACPI HID */ - return (requester); + *requesterp = NULL; + return (ENOTTY); } *rid = pci_get_rid(dev); @@ -141,16 +142,39 @@ iommu_get_requester(device_t dev, uint16_t *rid) */ for (;;) { pci = device_get_parent(l); - KASSERT(pci != NULL, ("iommu_get_requester(%s): NULL parent " - "for %s", device_get_name(dev), device_get_name(l))); - KASSERT(device_get_devclass(pci) == pci_class, - ("iommu_get_requester(%s): non-pci parent %s for %s", - device_get_name(dev), device_get_name(pci), - device_get_name(l))); + if (pci == NULL) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): NULL parent for %s\n", + device_get_name(dev), device_get_name(l)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } + if (device_get_devclass(pci) != pci_class) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): non-pci parent %s for %s\n", + device_get_name(dev), device_get_name(pci), + device_get_name(l)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } pcib = device_get_parent(pci); - KASSERT(pcib != NULL, ("iommu_get_requester(%s): NULL bridge " - "for %s", device_get_name(dev), device_get_name(pci))); + if (pcib == NULL) { + if (bootverbose) { + printf( + "iommu_get_requester(%s): NULL bridge for %s\n", + device_get_name(dev), device_get_name(pci)); + } + *rid = 0; + *requesterp = NULL; + return (ENXIO); + } /* * The parent of our "bridge" isn't another PCI bus, @@ -229,7 +253,8 @@ iommu_get_requester(device_t dev, uint16_t *rid) } } } - return (requester); + *requesterp = requester; + return (0); } struct iommu_ctx * @@ -237,10 +262,13 @@ iommu_instantiate_ctx(struct iommu_unit *unit, device_t dev, bool rmrr) { device_t requester; struct iommu_ctx *ctx; + int error; bool disabled; uint16_t rid; - requester = iommu_get_requester(dev, &rid); + error = iommu_get_requester(dev, &requester, &rid); + if (error != 0) + return (NULL); /* * If the user requested the IOMMU disabled for the device, we diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h index b1858f0df9f7..55044042c5d2 100644 --- a/sys/dev/iommu/iommu.h +++ b/sys/dev/iommu/iommu.h @@ -170,7 +170,7 @@ void iommu_domain_unload(struct iommu_domain *domain, void iommu_unit_pre_instantiate_ctx(struct iommu_unit *iommu); struct iommu_ctx *iommu_instantiate_ctx(struct iommu_unit *iommu, device_t dev, bool rmrr); -device_t iommu_get_requester(device_t dev, uint16_t *rid); +int iommu_get_requester(device_t dev, device_t *requester, uint16_t *rid); int iommu_init_busdma(struct iommu_unit *unit); void iommu_fini_busdma(struct iommu_unit *unit); diff --git a/sys/dev/irdma/irdma_cm.c b/sys/dev/irdma/irdma_cm.c index 450fae662dd8..d4d4f328fb43 100644 --- a/sys/dev/irdma/irdma_cm.c +++ b/sys/dev/irdma/irdma_cm.c @@ -1316,7 +1316,7 @@ irdma_cm_timer_tick(struct timer_list *t) struct irdma_timer_entry *send_entry, *close_entry; struct list_head *list_core_temp; struct list_head *list_node; - struct irdma_cm_core *cm_core = from_timer(cm_core, t, tcp_timer); + struct irdma_cm_core *cm_core = timer_container_of(cm_core, t, tcp_timer); struct irdma_sc_vsi *vsi; u32 settimer = 0; unsigned long timetosend; diff --git a/sys/dev/irdma/irdma_utils.c b/sys/dev/irdma/irdma_utils.c index 5fc37022981f..038f1980082b 100644 --- a/sys/dev/irdma/irdma_utils.c +++ b/sys/dev/irdma/irdma_utils.c @@ -876,7 +876,7 @@ irdma_terminate_done(struct irdma_sc_qp *qp, int timeout_occurred) static void irdma_terminate_timeout(struct timer_list *t) { - struct irdma_qp *iwqp = from_timer(iwqp, t, terminate_timer); + struct irdma_qp *iwqp = timer_container_of(iwqp, t, terminate_timer); struct irdma_sc_qp *qp = &iwqp->sc_qp; irdma_terminate_done(qp, 1); @@ -1528,7 +1528,7 @@ static void irdma_hw_stats_timeout(struct timer_list *t) { struct irdma_vsi_pestat *pf_devstat = - from_timer(pf_devstat, t, stats_timer); + timer_container_of(pf_devstat, t, stats_timer); struct irdma_sc_vsi *sc_vsi = pf_devstat->vsi; if (sc_vsi->dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c index 73c0fd1ab16f..6d08bd49bc04 100644 --- a/sys/dev/ixgbe/if_ix.c +++ b/sys/dev/ixgbe/if_ix.c @@ -184,6 +184,7 @@ static int ixgbe_if_rx_queues_alloc(if_ctx_t, caddr_t *, uint64_t *, int, int); static void ixgbe_if_queues_free(if_ctx_t); static void ixgbe_if_timer(if_ctx_t, uint16_t); +static const char *ixgbe_link_speed_to_str(u32 link_speed); static void ixgbe_if_update_admin_status(if_ctx_t); static void ixgbe_if_vlan_register(if_ctx_t, u16); static void ixgbe_if_vlan_unregister(if_ctx_t, u16); @@ -1349,8 +1350,6 @@ ixgbe_if_get_counter(if_ctx_t ctx, ift_counter cnt) return (0); case IFCOUNTER_IQDROPS: return (sc->iqdrops); - case IFCOUNTER_OQDROPS: - return (0); case IFCOUNTER_IERRORS: return (sc->ierrors); default: @@ -4027,6 +4026,33 @@ ixgbe_if_stop(if_ctx_t ctx) } /* ixgbe_if_stop */ /************************************************************************ + * ixgbe_link_speed_to_str - Convert link speed to string + * + * Helper function to convert link speed constants to human-readable + * string representations in conventional Gbps or Mbps. + ************************************************************************/ +static const char * +ixgbe_link_speed_to_str(u32 link_speed) +{ + switch (link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + return "10 Gbps"; + case IXGBE_LINK_SPEED_5GB_FULL: + return "5 Gbps"; + case IXGBE_LINK_SPEED_2_5GB_FULL: + return "2.5 Gbps"; + case IXGBE_LINK_SPEED_1GB_FULL: + return "1 Gbps"; + case IXGBE_LINK_SPEED_100_FULL: + return "100 Mbps"; + case IXGBE_LINK_SPEED_10_FULL: + return "10 Mbps"; + default: + return "Unknown"; + } +} /* ixgbe_link_speed_to_str */ + +/************************************************************************ * ixgbe_update_link_status - Update OS on link state * * Note: Only updates the OS on the cached link state. @@ -4042,9 +4068,9 @@ ixgbe_if_update_admin_status(if_ctx_t ctx) if (sc->link_up) { if (sc->link_active == false) { if (bootverbose) - device_printf(dev, "Link is up %d Gbps %s \n", - ((sc->link_speed == 128) ? 10 : 1), - "Full Duplex"); + device_printf(dev, + "Link is up %s Full Duplex\n", + ixgbe_link_speed_to_str(sc->link_speed)); sc->link_active = true; /* Update any Flow Control changes */ ixgbe_fc_enable(&sc->hw); diff --git a/sys/dev/ixgbe/ixgbe_e610.c b/sys/dev/ixgbe/ixgbe_e610.c index 95c6dca416c6..18c4612446e0 100644 --- a/sys/dev/ixgbe/ixgbe_e610.c +++ b/sys/dev/ixgbe/ixgbe_e610.c @@ -1400,40 +1400,6 @@ s32 ixgbe_aci_set_link_restart_an(struct ixgbe_hw *hw, bool ena_link) } /** - * ixgbe_is_media_cage_present - check if media cage is present - * @hw: pointer to the HW struct - * - * Identify presence of media cage using the ACI command (0x06E0). - * - * Return: true if media cage is present, else false. If no cage, then - * media type is backplane or BASE-T. - */ -static bool ixgbe_is_media_cage_present(struct ixgbe_hw *hw) -{ - struct ixgbe_aci_cmd_get_link_topo *cmd; - struct ixgbe_aci_desc desc; - - cmd = &desc.params.get_link_topo; - - ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_link_topo); - - cmd->addr.topo_params.node_type_ctx = - (IXGBE_ACI_LINK_TOPO_NODE_CTX_PORT << - IXGBE_ACI_LINK_TOPO_NODE_CTX_S); - - /* set node type */ - cmd->addr.topo_params.node_type_ctx |= - (IXGBE_ACI_LINK_TOPO_NODE_TYPE_M & - IXGBE_ACI_LINK_TOPO_NODE_TYPE_CAGE); - - /* Node type cage can be used to determine if cage is present. If AQC - * returns error (ENOENT), then no cage present. If no cage present then - * connection type is backplane or BASE-T. - */ - return ixgbe_aci_get_netlist_node(hw, cmd, NULL, NULL); -} - -/** * ixgbe_get_media_type_from_phy_type - Gets media type based on phy type * @hw: pointer to the HW struct * diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c index 43c3af056b67..261f76055901 100644 --- a/sys/dev/ixl/if_ixl.c +++ b/sys/dev/ixl/if_ixl.c @@ -1785,7 +1785,7 @@ ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt) case IFCOUNTER_OPACKETS: return (vsi->opackets); case IFCOUNTER_OERRORS: - return (vsi->oerrors); + return (if_get_counter_default(ifp, cnt) + vsi->oerrors); case IFCOUNTER_COLLISIONS: /* Collisions are by standard impossible in 40G/10G Ethernet */ return (0); @@ -1800,7 +1800,7 @@ ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt) case IFCOUNTER_IQDROPS: return (vsi->iqdrops); case IFCOUNTER_OQDROPS: - return (vsi->oqdrops); + return (if_get_counter_default(ifp, cnt) + vsi->oqdrops); case IFCOUNTER_NOPROTO: return (vsi->noproto); default: diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c index d1c572e40669..262d6b58b705 100644 --- a/sys/dev/mpr/mpr.c +++ b/sys/dev/mpr/mpr.c @@ -1729,6 +1729,7 @@ mpr_get_tunables(struct mpr_softc *sc) sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; sc->use_phynum = 1; + sc->encl_min_slots = 0; sc->max_reqframes = MPR_REQ_FRAMES; sc->max_prireqframes = MPR_PRI_REQ_FRAMES; sc->max_replyframes = MPR_REPLY_FRAMES; @@ -1748,6 +1749,7 @@ mpr_get_tunables(struct mpr_softc *sc) TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum); + TUNABLE_INT_FETCH("hw.mpr.encl_min_slots", &sc->encl_min_slots); TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes); TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes); TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes); @@ -1797,6 +1799,10 @@ mpr_get_tunables(struct mpr_softc *sc) device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.encl_min_slots", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->encl_min_slots); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes", device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes); @@ -1951,6 +1957,10 @@ mpr_setup_sysctl(struct mpr_softc *sc) SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "prp_page_alloc_fail", CTLFLAG_RD, &sc->prp_page_alloc_fail, "PRP page allocation failures"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "encl_min_slots", CTLFLAG_RW, &sc->encl_min_slots, 0, + "force enclosure minimum slots"); } static struct mpr_debug_string { diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c index f9a9ac1c53d0..38aa4dfc7ef2 100644 --- a/sys/dev/mpr/mpr_mapping.c +++ b/sys/dev/mpr/mpr_mapping.c @@ -2785,6 +2785,8 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, * DPM, if it's being used. */ if (enc_idx != MPR_ENCTABLE_BAD_IDX) { + u16 new_num_slots; + et_entry = &sc->enclosure_table[enc_idx]; if (et_entry->init_complete && !et_entry->missing_count) { @@ -2796,6 +2798,17 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, et_entry->enc_handle = le16toh(event_data-> EnclosureHandle); et_entry->start_slot = le16toh(event_data->StartSlot); + new_num_slots = le16toh(event_data->NumSlots); + if (new_num_slots < sc->encl_min_slots) { + mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d num_slots %d, overriding with %d.\n", + __func__, enc_idx, new_num_slots, sc->encl_min_slots); + new_num_slots = sc->encl_min_slots; + } + if (et_entry->num_slots != new_num_slots) { + mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d old num_slots %d, new %d.\n", + __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots); + et_entry->num_slots = new_num_slots; + } saved_phy_bits = et_entry->phy_bits; et_entry->phy_bits |= le32toh(event_data->PhyBits); if (saved_phy_bits != et_entry->phy_bits) @@ -2858,6 +2871,11 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, et_entry->start_index = MPR_MAPTABLE_BAD_IDX; et_entry->dpm_entry_num = MPR_DPM_BAD_IDX; et_entry->num_slots = le16toh(event_data->NumSlots); + if (et_entry->num_slots < sc->encl_min_slots) { + mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Enclosure %d num_slots is %d, overriding with %d.\n", + __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots); + et_entry->num_slots = sc->encl_min_slots; + } et_entry->start_slot = le16toh(event_data->StartSlot); et_entry->phy_bits = le32toh(event_data->PhyBits); } diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h index 0f1743f4266e..93f3fbffe079 100644 --- a/sys/dev/mpr/mprvar.h +++ b/sys/dev/mpr/mprvar.h @@ -366,6 +366,7 @@ struct mpr_softc { int spinup_wait_time; int use_phynum; int dump_reqs_alltypes; + int encl_min_slots; uint64_t chain_alloc_fail; uint64_t prp_page_alloc_fail; struct sysctl_ctx_list sysctl_ctx; diff --git a/sys/dev/mwl/if_mwl.c b/sys/dev/mwl/if_mwl.c index 0e2eb0b2d8fe..c885968dfe15 100644 --- a/sys/dev/mwl/if_mwl.c +++ b/sys/dev/mwl/if_mwl.c @@ -4017,7 +4017,7 @@ mkpeerinfo(MWL_HAL_PEERINFO *pi, const struct ieee80211_node *ni) pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_SHORTGI40; if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0) pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_SHORTGI20; - if (ni->ni_chw != IEEE80211_STA_RX_BW_40) + if (ni->ni_chw != NET80211_STA_RX_BW_40) pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_CHWIDTH40; } return pi; diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c index 49960b0f920a..3a1894bf754d 100644 --- a/sys/dev/nvme/nvme_ctrlr.c +++ b/sys/dev/nvme/nvme_ctrlr.c @@ -41,6 +41,9 @@ #include <sys/endian.h> #include <sys/stdarg.h> #include <vm/vm.h> +#include <vm/vm_page.h> +#include <vm/vm_extern.h> +#include <vm/vm_map.h> #include "nvme_private.h" #include "nvme_linux.h" @@ -1265,6 +1268,34 @@ nvme_ctrlr_shared_handler(void *arg) nvme_mmio_write_4(ctrlr, intmc, 1); } +#define NVME_MAX_PAGES (int)(1024 / sizeof(vm_page_t)) + +static int +nvme_user_ioctl_req(vm_offset_t addr, size_t len, bool is_read, + vm_page_t *upages, int max_pages, int *npagesp, struct nvme_request **req, + nvme_cb_fn_t cb_fn, void *cb_arg) +{ + vm_prot_t prot = VM_PROT_READ; + int err; + + if (is_read) + prot |= VM_PROT_WRITE; /* Device will write to host memory */ + err = vm_fault_hold_pages(&curproc->p_vmspace->vm_map, + addr, len, prot, upages, max_pages, npagesp); + if (err != 0) + return (err); + *req = nvme_allocate_request_null(M_WAITOK, cb_fn, cb_arg); + (*req)->payload = memdesc_vmpages(upages, len, addr & PAGE_MASK); + (*req)->payload_valid = true; + return (0); +} + +static void +nvme_user_ioctl_free(vm_page_t *pages, int npage) +{ + vm_page_unhold_pages(pages, npage); +} + static void nvme_pt_done(void *arg, const struct nvme_completion *cpl) { @@ -1287,30 +1318,28 @@ nvme_pt_done(void *arg, const struct nvme_completion *cpl) int nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr, - struct nvme_pt_command *pt, uint32_t nsid, int is_user_buffer, + struct nvme_pt_command *pt, uint32_t nsid, int is_user, int is_admin_cmd) { - struct nvme_request *req; - struct mtx *mtx; - struct buf *buf = NULL; - int ret = 0; + struct nvme_request *req; + struct mtx *mtx; + int ret = 0; + int npages = 0; + vm_page_t upages[NVME_MAX_PAGES]; if (pt->len > 0) { if (pt->len > ctrlr->max_xfer_size) { - nvme_printf(ctrlr, "pt->len (%d) " - "exceeds max_xfer_size (%d)\n", pt->len, - ctrlr->max_xfer_size); - return EIO; + nvme_printf(ctrlr, + "len (%d) exceeds max_xfer_size (%d)\n", + pt->len, ctrlr->max_xfer_size); + return (EIO); } - if (is_user_buffer) { - buf = uma_zalloc(pbuf_zone, M_WAITOK); - buf->b_iocmd = pt->is_read ? BIO_READ : BIO_WRITE; - if (vmapbuf(buf, pt->buf, pt->len, 1) < 0) { - ret = EFAULT; - goto err; - } - req = nvme_allocate_request_vaddr(buf->b_data, pt->len, - M_WAITOK, nvme_pt_done, pt); + if (is_user) { + ret = nvme_user_ioctl_req((vm_offset_t)pt->buf, pt->len, + pt->is_read, upages, nitems(upages), &npages, &req, + nvme_pt_done, pt); + if (ret != 0) + return (ret); } else req = nvme_allocate_request_vaddr(pt->buf, pt->len, M_WAITOK, nvme_pt_done, pt); @@ -1344,11 +1373,8 @@ nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr, mtx_sleep(pt, mtx, PRIBIO, "nvme_pt", 0); mtx_unlock(mtx); - if (buf != NULL) { - vunmapbuf(buf); -err: - uma_zfree(pbuf_zone, buf); - } + if (npages > 0) + nvme_user_ioctl_free(upages, npages); return (ret); } @@ -1374,8 +1400,9 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr, { struct nvme_request *req; struct mtx *mtx; - struct buf *buf = NULL; int ret = 0; + int npages = 0; + vm_page_t upages[NVME_MAX_PAGES]; /* * We don't support metadata. @@ -1386,28 +1413,16 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr, if (npc->data_len > 0 && npc->addr != 0) { if (npc->data_len > ctrlr->max_xfer_size) { nvme_printf(ctrlr, - "npc->data_len (%d) exceeds max_xfer_size (%d)\n", + "data_len (%d) exceeds max_xfer_size (%d)\n", npc->data_len, ctrlr->max_xfer_size); return (EIO); } - /* - * We only support data out or data in commands, but not both at - * once. However, there's some comands with lower bit cleared - * that are really read commands, so we should filter & 3 == 0, - * but don't. - */ - if ((npc->opcode & 0x3) == 3) - return (EINVAL); if (is_user) { - buf = uma_zalloc(pbuf_zone, M_WAITOK); - buf->b_iocmd = npc->opcode & 1 ? BIO_WRITE : BIO_READ; - if (vmapbuf(buf, (void *)(uintptr_t)npc->addr, - npc->data_len, 1) < 0) { - ret = EFAULT; - goto err; - } - req = nvme_allocate_request_vaddr(buf->b_data, - npc->data_len, M_WAITOK, nvme_npc_done, npc); + ret = nvme_user_ioctl_req(npc->addr, npc->data_len, + npc->opcode & 0x1, upages, nitems(upages), &npages, + &req, nvme_npc_done, npc); + if (ret != 0) + return (ret); } else req = nvme_allocate_request_vaddr( (void *)(uintptr_t)npc->addr, npc->data_len, @@ -1442,11 +1457,8 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr, mtx_sleep(npc, mtx, PRIBIO, "nvme_npc", 0); mtx_unlock(mtx); - if (buf != NULL) { - vunmapbuf(buf); -err: - uma_zfree(pbuf_zone, buf); - } + if (npages > 0) + nvme_user_ioctl_free(upages, npages); return (ret); } diff --git a/sys/dev/nvme/nvme_util.c b/sys/dev/nvme/nvme_util.c index 0a07653a7378..cb0ba729ac96 100644 --- a/sys/dev/nvme/nvme_util.c +++ b/sys/dev/nvme/nvme_util.c @@ -208,31 +208,33 @@ nvme_opcode_sbuf(bool admin, uint8_t opc, struct sbuf *sb) if (s == NULL) sbuf_printf(sb, "%s (%02x)", type, opc); else - sbuf_printf(sb, "%s", s); + sbuf_printf(sb, "%s (%02x)", s, opc); } void nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sb) { const char *s, *type; - uint16_t status; + uint16_t status, sc, sct; status = le16toh(cpl->status); - switch (NVME_STATUS_GET_SCT(status)) { + sc = NVME_STATUS_GET_SC(status); + sct = NVME_STATUS_GET_SCT(status); + switch (sct) { case NVME_SCT_GENERIC: - s = generic_status[NVME_STATUS_GET_SC(status)]; + s = generic_status[sc]; type = "GENERIC"; break; case NVME_SCT_COMMAND_SPECIFIC: - s = command_specific_status[NVME_STATUS_GET_SC(status)]; + s = command_specific_status[sc]; type = "COMMAND SPECIFIC"; break; case NVME_SCT_MEDIA_ERROR: - s = media_error_status[NVME_STATUS_GET_SC(status)]; + s = media_error_status[sc]; type = "MEDIA ERROR"; break; case NVME_SCT_PATH_RELATED: - s = path_related_status[NVME_STATUS_GET_SC(status)]; + s = path_related_status[sc]; type = "PATH RELATED"; break; case NVME_SCT_VENDOR_SPECIFIC: @@ -246,12 +248,11 @@ nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sb) } if (type == NULL) - sbuf_printf(sb, "RESERVED (%02x/%02x)", - NVME_STATUS_GET_SCT(status), NVME_STATUS_GET_SC(status)); + sbuf_printf(sb, "RESERVED (%02x/%02x)", sct, sc); else if (s == NULL) - sbuf_printf(sb, "%s (%02x)", type, NVME_STATUS_GET_SC(status)); + sbuf_printf(sb, "%s (%02x/%02x)", type, sct, sc); else - sbuf_printf(sb, "%s", s); + sbuf_printf(sb, "%s (%02x/%02x)", s, sct, sc); } void diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c index f68b5b7e71ff..9768030995e7 100644 --- a/sys/dev/pci/pci_user.c +++ b/sys/dev/pci/pci_user.c @@ -79,6 +79,9 @@ struct pci_conf32 { u_int8_t pc_revid; /* chip revision ID */ char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ u_int32_t pd_unit; /* device unit number */ + int pd_numa_domain; /* device NUMA domain */ + u_int32_t pc_reported_len;/* length of PCI data reported */ + char pc_spare[64]; /* space for future fields */ }; struct pci_match_conf32 { @@ -502,11 +505,58 @@ pci_conf_match_freebsd6_32(struct pci_match_conf_freebsd6_32 *matches, int num_m #endif /* COMPAT_FREEBSD32 */ #endif /* !PRE7_COMPAT */ +#ifdef COMPAT_FREEBSD14 +struct pci_conf_freebsd14 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_long pd_unit; /* device unit number */ +}; +#define PCIOCGETCONF_FREEBSD14 _IOWR('p', 5, struct pci_conf_io) + +#ifdef COMPAT_FREEBSD32 +struct pci_conf_freebsd14_32 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* device unit number */ +}; +#define PCIOCGETCONF_FREEBSD14_32 \ + _IOC_NEWTYPE(PCIOCGETCONF_FREEBSD14, struct pci_conf_io32) +#endif /* COMPAT_FREEBSD32 */ +#endif /* COMPAT_FREEBSD14 */ + union pci_conf_union { struct pci_conf pc; #ifdef COMPAT_FREEBSD32 struct pci_conf32 pc32; #endif +#ifdef COMPAT_FREEBSD14 + struct pci_conf_freebsd14 pc14; +#ifdef COMPAT_FREEBSD32 + struct pci_conf_freebsd14_32 pc14_32; +#endif +#endif #ifdef PRE7_COMPAT struct pci_conf_freebsd6 pco; #ifdef COMPAT_FREEBSD32 @@ -522,10 +572,16 @@ pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, switch (cmd) { case PCIOCGETCONF: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#endif return (pci_conf_match_native( (struct pci_match_conf *)matches, num_matches, match_buf)); #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14_32: +#endif return (pci_conf_match32((struct pci_match_conf32 *)matches, num_matches, match_buf)); #endif @@ -645,9 +701,15 @@ pci_match_conf_size(u_long cmd) switch (cmd) { case PCIOCGETCONF: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#endif return (sizeof(struct pci_match_conf)); #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14_32: +#endif return (sizeof(struct pci_match_conf32)); #endif #ifdef PRE7_COMPAT @@ -675,6 +737,14 @@ pci_conf_size(u_long cmd) case PCIOCGETCONF32: return (sizeof(struct pci_conf32)); #endif +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: + return (sizeof(struct pci_conf_freebsd14)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_FREEBSD14_32: + return (sizeof(struct pci_conf_freebsd14_32)); +#endif +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6: return (sizeof(struct pci_conf_freebsd6)); @@ -698,6 +768,9 @@ pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) switch (cmd) { case PCIOCGETCONF: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6: #endif @@ -706,6 +779,9 @@ pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14_32: +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6_32: #endif @@ -739,6 +815,9 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, switch (cmd) { case PCIOCGETCONF: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6: #endif @@ -751,6 +830,9 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14_32: +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6_32: #endif @@ -781,8 +863,17 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, pcup->pc = *pcp; return; +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: + memcpy(&pcup->pc14, pcp, sizeof(pcup->pc14)); + return; +#endif + #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14_32: +#endif pcup->pc32.pc_sel = pcp->pc_sel; pcup->pc32.pc_hdr = pcp->pc_hdr; pcup->pc32.pc_subvendor = pcp->pc_subvendor; @@ -796,8 +887,13 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, strlcpy(pcup->pc32.pd_name, pcp->pd_name, sizeof(pcup->pc32.pd_name)); pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit; + if (cmd == PCIOCGETCONF32) { + pcup->pc32.pd_numa_domain = pcp->pd_numa_domain; + pcup->pc32.pc_reported_len = + (uint32_t)offsetof(struct pci_conf32, pc_spare); + } return; -#endif +#endif /* COMPAT_FREEBSD32 */ #ifdef PRE7_COMPAT #ifdef COMPAT_FREEBSD32 @@ -1024,7 +1120,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t struct pci_map *pm; struct pci_bar_mmap *pbm; size_t confsz, iolen; - int error, ionum, i, num_patterns; + int domain, error, ionum, i, num_patterns; union pci_conf_union pcu; #ifdef PRE7_COMPAT struct pci_io iodata; @@ -1044,6 +1140,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: #endif +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_FREEBSD14_32: +#endif +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6: #ifdef COMPAT_FREEBSD32 @@ -1069,6 +1171,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF32: #endif +#ifdef COMPAT_FREEBSD14 + case PCIOCGETCONF_FREEBSD14: +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_FREEBSD14_32: +#endif +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_FREEBSD6: #ifdef COMPAT_FREEBSD32 @@ -1201,6 +1309,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t dinfo->conf.pd_unit = 0; } + if (dinfo->cfg.dev != NULL && + bus_get_domain(dinfo->cfg.dev, &domain) == 0) + dinfo->conf.pd_numa_domain = domain; + else + dinfo->conf.pd_numa_domain = 0; + if (pattern_buf == NULL || pci_conf_match(cmd, pattern_buf, num_patterns, &dinfo->conf) == 0) { @@ -1217,6 +1331,9 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t break; } + dinfo->conf.pc_reported_len = + offsetof(struct pci_conf, pc_spare); + pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); error = copyout(&pcu, (caddr_t)cio->matches + diff --git a/sys/dev/qat/qat_common/adf_gen4_timer.c b/sys/dev/qat/qat_common/adf_gen4_timer.c index 96b65cdff181..2c74d09418e5 100644 --- a/sys/dev/qat/qat_common/adf_gen4_timer.c +++ b/sys/dev/qat/qat_common/adf_gen4_timer.c @@ -57,7 +57,7 @@ end: static void timer_handler(struct timer_list *tl) { - struct adf_int_timer *int_timer = from_timer(int_timer, tl, timer); + struct adf_int_timer *int_timer = timer_container_of(int_timer, tl, timer); struct adf_accel_dev *accel_dev = int_timer->accel_dev; struct adf_hb_timer_data *hb_timer_data = NULL; u64 timeout_val = adf_get_next_timeout(int_timer->timeout_val); diff --git a/sys/dev/qlnx/qlnxe/ecore_dev.c b/sys/dev/qlnx/qlnxe/ecore_dev.c index 6187ecdbc446..389a95a4164c 100644 --- a/sys/dev/qlnx/qlnxe/ecore_dev.c +++ b/sys/dev/qlnx/qlnxe/ecore_dev.c @@ -5268,7 +5268,7 @@ ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn, } DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%08x usec]\n", + "Read default link: Speed %u Mb/sec, Adv. Speeds 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x EEE: %02x [%u usec]\n", link->speed.forced_speed, link->speed.advertised_speeds, link->speed.autoneg, link->pause.autoneg, p_caps->default_eee, p_caps->eee_lpi_timer); @@ -6860,7 +6860,7 @@ int __ecore_configure_pf_max_bandwidth(struct ecore_hwfn *p_hwfn, p_hwfn->qm_info.pf_rl); DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Configured MAX bandwidth to be %08x Mb/sec\n", + "Configured MAX bandwidth to be %u Mb/sec\n", p_link->speed); return rc; @@ -6918,7 +6918,7 @@ int __ecore_configure_pf_min_bandwidth(struct ecore_hwfn *p_hwfn, rc = ecore_init_pf_wfq(p_hwfn, p_ptt, p_hwfn->rel_pf_id, min_bw); DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Configured MIN bandwidth to be %d Mb/sec\n", + "Configured MIN bandwidth to be %u Mb/sec\n", p_link->min_pf_rate); return rc; diff --git a/sys/dev/qlnx/qlnxe/ecore_mcp.c b/sys/dev/qlnx/qlnxe/ecore_mcp.c index ab14b1eb5186..6d1e5fe24d06 100644 --- a/sys/dev/qlnx/qlnxe/ecore_mcp.c +++ b/sys/dev/qlnx/qlnxe/ecore_mcp.c @@ -1638,7 +1638,7 @@ enum _ecore_status_t ecore_mcp_set_link(struct ecore_hwfn *p_hwfn, if (b_up) DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, - "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x\n", + "Configuring Link: Speed %u Mb/sec, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x\n", phy_cfg.speed, phy_cfg.pause, phy_cfg.adv_speed, phy_cfg.loopback_mode); else diff --git a/sys/dev/qlnx/qlnxe/qlnx_def.h b/sys/dev/qlnx/qlnxe/qlnx_def.h index 4342bba89587..796845f3f8c6 100644 --- a/sys/dev/qlnx/qlnxe/qlnx_def.h +++ b/sys/dev/qlnx/qlnxe/qlnx_def.h @@ -696,22 +696,6 @@ extern int qlnx_alloc_mem_sb(qlnx_host_t *ha, struct ecore_sb_info *sb_info, * Some OS specific stuff */ -#if (defined IFM_100G_SR4) -#define QLNX_IFM_100G_SR4 IFM_100G_SR4 -#define QLNX_IFM_100G_LR4 IFM_100G_LR4 -#define QLNX_IFM_100G_CR4 IFM_100G_CR4 -#else -#define QLNX_IFM_100G_SR4 IFM_UNKNOWN -#define QLNX_IFM_100G_LR4 IFM_UNKNOWN -#endif /* #if (defined IFM_100G_SR4) */ - -#if (defined IFM_25G_SR) -#define QLNX_IFM_25G_SR IFM_25G_SR -#define QLNX_IFM_25G_CR IFM_25G_CR -#else -#define QLNX_IFM_25G_SR IFM_UNKNOWN -#define QLNX_IFM_25G_CR IFM_UNKNOWN -#endif /* #if (defined IFM_25G_SR) */ #define QLNX_INC_IERRORS(ifp) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1) #define QLNX_INC_IQDROPS(ifp) if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1) diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c index 4ad190374f87..9963f472c615 100644 --- a/sys/dev/qlnx/qlnxe/qlnx_os.c +++ b/sys/dev/qlnx/qlnxe/qlnx_os.c @@ -2375,18 +2375,15 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha) ifmedia_add(&ha->media, (IFM_ETHER | IFM_40G_CR4), 0, NULL); } else if ((device_id == QLOGIC_PCI_DEVICE_ID_1656) || (device_id == QLOGIC_PCI_DEVICE_ID_8070)) { - ifmedia_add(&ha->media, (IFM_ETHER | QLNX_IFM_25G_SR), 0, NULL); - ifmedia_add(&ha->media, (IFM_ETHER | QLNX_IFM_25G_CR), 0, NULL); + ifmedia_add(&ha->media, (IFM_ETHER | IFM_25G_SR), 0, NULL); + ifmedia_add(&ha->media, (IFM_ETHER | IFM_25G_CR), 0, NULL); } else if (device_id == QLOGIC_PCI_DEVICE_ID_1654) { ifmedia_add(&ha->media, (IFM_ETHER | IFM_50G_KR2), 0, NULL); ifmedia_add(&ha->media, (IFM_ETHER | IFM_50G_CR2), 0, NULL); } else if (device_id == QLOGIC_PCI_DEVICE_ID_1644) { - ifmedia_add(&ha->media, - (IFM_ETHER | QLNX_IFM_100G_LR4), 0, NULL); - ifmedia_add(&ha->media, - (IFM_ETHER | QLNX_IFM_100G_SR4), 0, NULL); - ifmedia_add(&ha->media, - (IFM_ETHER | QLNX_IFM_100G_CR4), 0, NULL); + ifmedia_add(&ha->media, (IFM_ETHER | IFM_100G_LR4), 0, NULL); + ifmedia_add(&ha->media, (IFM_ETHER | IFM_100G_SR4), 0, NULL); + ifmedia_add(&ha->media, (IFM_ETHER | IFM_100G_CR4), 0, NULL); } ifmedia_add(&ha->media, (IFM_ETHER | IFM_FDX), 0, NULL); @@ -2724,7 +2721,9 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data) case SIOCSIFMEDIA: case SIOCGIFMEDIA: - QL_DPRINT4(ha, "SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n", cmd); + case SIOCGIFXMEDIA: + QL_DPRINT4(ha, + "SIOCSIFMEDIA/SIOCGIFMEDIA/SIOCGIFXMEDIA (0x%lx)\n", cmd); ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd); break; @@ -3808,11 +3807,11 @@ qlnx_get_optics(qlnx_host_t *ha, struct qlnx_link_output *if_link) case MEDIA_MODULE_FIBER: case MEDIA_UNSPECIFIED: if (if_link->speed == (100 * 1000)) - ifm_type = QLNX_IFM_100G_SR4; + ifm_type = IFM_100G_SR4; else if (if_link->speed == (40 * 1000)) ifm_type = IFM_40G_SR4; else if (if_link->speed == (25 * 1000)) - ifm_type = QLNX_IFM_25G_SR; + ifm_type = IFM_25G_SR; else if (if_link->speed == (10 * 1000)) ifm_type = (IFM_10G_LR | IFM_10G_SR); else if (if_link->speed == (1 * 1000)) @@ -3822,11 +3821,11 @@ qlnx_get_optics(qlnx_host_t *ha, struct qlnx_link_output *if_link) case MEDIA_DA_TWINAX: if (if_link->speed == (100 * 1000)) - ifm_type = QLNX_IFM_100G_CR4; + ifm_type = IFM_100G_CR4; else if (if_link->speed == (40 * 1000)) ifm_type = IFM_40G_CR4; else if (if_link->speed == (25 * 1000)) - ifm_type = QLNX_IFM_25G_CR; + ifm_type = IFM_25G_CR; else if (if_link->speed == (10 * 1000)) ifm_type = IFM_10G_TWINAX; diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c index 84ec174bd08e..2d7af254c52c 100644 --- a/sys/dev/random/random_harvestq.c +++ b/sys/dev/random/random_harvestq.c @@ -103,8 +103,10 @@ static const char *random_source_descr[ENTROPYSOURCE]; volatile int random_kthread_control; -/* Allow the sysadmin to select the broad category of - * entropy types to harvest. +/* + * Allow the sysadmin to select the broad category of entropy types to harvest. + * + * Updates are synchronized by the harvest mutex. */ __read_frequently u_int hc_source_mask; @@ -278,8 +280,15 @@ random_sources_feed(void) epoch_enter_preempt(rs_epoch, &et); CK_LIST_FOREACH(rrs, &source_list, rrs_entries) { for (i = 0; i < npools; i++) { + if (rrs->rrs_source->rs_read == NULL) { + /* Source pushes entropy asynchronously. */ + continue; + } n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); - KASSERT((n <= sizeof(entropy)), ("%s: rs_read returned too much data (%u > %zu)", __func__, n, sizeof(entropy))); + KASSERT((n <= sizeof(entropy)), + ("%s: rs_read returned too much data (%u > %zu)", + __func__, n, sizeof(entropy))); + /* * Sometimes the HW entropy source doesn't have anything * ready for us. This isn't necessarily untrustworthy. @@ -334,7 +343,17 @@ copy_event(uint32_t dst[static HARVESTSIZE + 1], { memset(dst, 0, sizeof(uint32_t) * (HARVESTSIZE + 1)); memcpy(dst, event->he_entropy, event->he_size); - dst[HARVESTSIZE] = event->he_somecounter; + if (event->he_source <= RANDOM_ENVIRONMENTAL_END) { + /* + * For pure entropy sources the timestamp counter is generally + * quite determinstic since samples are taken at regular + * intervals, so does not contribute much to the entropy. To + * make health tests more effective, exclude it from the sample, + * since it might otherwise defeat the health tests in a + * scenario where the source is stuck. + */ + dst[HARVESTSIZE] = event->he_somecounter; + } } static void @@ -464,11 +483,12 @@ SYSCTL_BOOL(_kern_random, OID_AUTO, nist_healthtest_enabled, "Enable NIST SP 800-90B health tests for noise sources"); static void -random_healthtest_init(enum random_entropy_source source) +random_healthtest_init(enum random_entropy_source source, int min_entropy) { struct health_test_softc *ht; ht = &healthtest[source]; + memset(ht, 0, sizeof(*ht)); KASSERT(ht->ht_state == INIT, ("%s: health test state is %d for source %d", __func__, ht->ht_state, source)); @@ -485,20 +505,62 @@ random_healthtest_init(enum random_entropy_source source) } /* - * Set cutoff values for the two tests, assuming that each sample has - * min-entropy of 1 bit and allowing for an error rate of 1 in 2^{34}. - * With a sample rate of RANDOM_KTHREAD_HZ, we expect to see an false - * positive once in ~54.5 years. + * Set cutoff values for the two tests, given a min-entropy estimate for + * the source and allowing for an error rate of 1 in 2^{34}. With a + * min-entropy estimate of 1 bit and a sample rate of RANDOM_KTHREAD_HZ, + * we expect to see an false positive once in ~54.5 years. * * The RCT limit comes from the formula in section 4.4.1. * - * The APT cutoff is calculated using the formula in section 4.4.2 + * The APT cutoffs are calculated using the formula in section 4.4.2 * footnote 10 with the number of Bernoulli trials changed from W to * W-1, since the test as written counts the number of samples equal to - * the first sample in the window, and thus tests W-1 samples. + * the first sample in the window, and thus tests W-1 samples. We + * provide cutoffs for estimates up to sizeof(uint32_t)*HARVESTSIZE*8 + * bits. */ - ht->ht_rct_limit = 35; - ht->ht_apt_cutoff = 330; + const int apt_cutoffs[] = { + [1] = 329, + [2] = 195, + [3] = 118, + [4] = 73, + [5] = 48, + [6] = 33, + [7] = 23, + [8] = 17, + [9] = 13, + [10] = 11, + [11] = 9, + [12] = 8, + [13] = 7, + [14] = 6, + [15] = 5, + [16] = 5, + [17 ... 19] = 4, + [20 ... 25] = 3, + [26 ... 42] = 2, + [43 ... 64] = 1, + }; + const int error_rate = 34; + + if (min_entropy == 0) { + /* + * For environmental sources, the main source of entropy is the + * associated timecounter value. Since these sources can be + * influenced by unprivileged users, we conservatively use a + * min-entropy estimate of 1 bit per sample. For "pure" + * sources, we assume 8 bits per sample, as such sources provide + * a variable amount of data per read and in particular might + * only provide a single byte at a time. + */ + min_entropy = source >= RANDOM_PURE_START ? 8 : 1; + } else if (min_entropy < 0 || min_entropy >= nitems(apt_cutoffs)) { + panic("invalid min_entropy %d for %s", min_entropy, + random_source_descr[source]); + } + + ht->ht_rct_limit = 1 + howmany(error_rate, min_entropy); + ht->ht_apt_cutoff = apt_cutoffs[min_entropy]; } static int @@ -533,9 +595,9 @@ random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS) _RANDOM_HARVEST_ETHER_OFF | _RANDOM_HARVEST_UMA_OFF; int error; - u_int value, orig_value; + u_int value; - orig_value = value = hc_source_mask; + value = atomic_load_int(&hc_source_mask); error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); @@ -546,12 +608,14 @@ random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS) /* * Disallow userspace modification of pure entropy sources. */ + RANDOM_HARVEST_LOCK(); hc_source_mask = (value & ~user_immutable_mask) | - (orig_value & user_immutable_mask); + (hc_source_mask & user_immutable_mask); + RANDOM_HARVEST_UNLOCK(); return (0); } SYSCTL_PROC(_kern_random_harvest, OID_AUTO, mask, - CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, + CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, random_check_uint_harvestmask, "IU", "Entropy harvesting mask"); @@ -563,9 +627,16 @@ random_print_harvestmask(SYSCTL_HANDLER_ARGS) error = sysctl_wire_old_buffer(req, 0); if (error == 0) { + u_int mask; + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); - for (i = ENTROPYSOURCE - 1; i >= 0; i--) - sbuf_cat(&sbuf, (hc_source_mask & (1 << i)) ? "1" : "0"); + mask = atomic_load_int(&hc_source_mask); + for (i = ENTROPYSOURCE - 1; i >= 0; i--) { + bool present; + + present = (mask & (1u << i)) != 0; + sbuf_cat(&sbuf, present ? "1" : "0"); + } error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); } @@ -619,16 +690,21 @@ random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS) first = true; error = sysctl_wire_old_buffer(req, 0); if (error == 0) { + u_int mask; + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); + mask = atomic_load_int(&hc_source_mask); for (i = ENTROPYSOURCE - 1; i >= 0; i--) { - if (i >= RANDOM_PURE_START && - (hc_source_mask & (1 << i)) == 0) + bool present; + + present = (mask & (1u << i)) != 0; + if (i >= RANDOM_PURE_START && !present) continue; if (!first) sbuf_cat(&sbuf, ","); - sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "[" : ""); + sbuf_cat(&sbuf, !present ? "[" : ""); sbuf_cat(&sbuf, random_source_descr[i]); - sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "]" : ""); + sbuf_cat(&sbuf, !present ? "]" : ""); first = false; } error = sbuf_finish(&sbuf); @@ -652,8 +728,8 @@ random_harvestq_init(void *unused __unused) RANDOM_HARVEST_INIT_LOCK(); harvest_context.hc_active_buf = 0; - for (int i = 0; i < ENTROPYSOURCE; i++) - random_healthtest_init(i); + for (int i = RANDOM_START; i <= RANDOM_ENVIRONMENTAL_END; i++) + random_healthtest_init(i, 0); } SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_init, NULL); @@ -835,20 +911,6 @@ random_harvest_direct_(const void *entropy, u_int size, enum random_entropy_sour } void -random_harvest_register_source(enum random_entropy_source source) -{ - - hc_source_mask |= (1 << source); -} - -void -random_harvest_deregister_source(enum random_entropy_source source) -{ - - hc_source_mask &= ~(1 << source); -} - -void random_source_register(const struct random_source *rsource) { struct random_sources *rrs; @@ -858,11 +920,12 @@ random_source_register(const struct random_source *rsource) rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK); rrs->rrs_source = rsource; - random_harvest_register_source(rsource->rs_source); - printf("random: registering fast source %s\n", rsource->rs_ident); + random_healthtest_init(rsource->rs_source, rsource->rs_min_entropy); + RANDOM_HARVEST_LOCK(); + hc_source_mask |= (1 << rsource->rs_source); CK_LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); RANDOM_HARVEST_UNLOCK(); } @@ -874,9 +937,8 @@ random_source_deregister(const struct random_source *rsource) KASSERT(rsource != NULL, ("invalid input to %s", __func__)); - random_harvest_deregister_source(rsource->rs_source); - RANDOM_HARVEST_LOCK(); + hc_source_mask &= ~(1 << rsource->rs_source); CK_LIST_FOREACH(rrs, &source_list, rrs_entries) if (rrs->rrs_source == rsource) { CK_LIST_REMOVE(rrs, rrs_entries); diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 6d742447ea8b..a6ca66c7d92e 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -52,7 +52,9 @@ random_check_uint_##name(SYSCTL_HANDLER_ARGS) \ } #endif /* SYSCTL_DECL */ +#ifdef MALLOC_DECLARE MALLOC_DECLARE(M_ENTROPY); +#endif extern bool random_bypass_before_seeding; extern bool read_random_bypassed_before_seeding; @@ -101,6 +103,7 @@ struct random_source { const char *rs_ident; enum random_entropy_source rs_source; random_source_read_t *rs_read; + int rs_min_entropy; }; void random_source_register(const struct random_source *); diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 091ab2db72ec..67864c2de388 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -3558,6 +3558,7 @@ re_ioctl(if_t ifp, u_long command, caddr_t data) static void re_watchdog(struct rl_softc *sc) { + struct epoch_tracker et; if_t ifp; RL_LOCK_ASSERT(sc); @@ -3578,7 +3579,9 @@ re_watchdog(struct rl_softc *sc) if_printf(ifp, "watchdog timeout\n"); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + NET_EPOCH_ENTER(et); re_rxeof(sc, NULL); + NET_EPOCH_EXIT(et); if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); re_init_locked(sc); if (!if_sendq_empty(ifp)) diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c index 7a547e13cafa..25287f222270 100644 --- a/sys/dev/rtwn/if_rtwn.c +++ b/sys/dev/rtwn/if_rtwn.c @@ -268,6 +268,9 @@ rtwn_attach(struct rtwn_softc *sc) ic->ic_flags_ext |= IEEE80211_FEXT_WATCHDOG; #endif + /* Enable seqno offload */ + ic->ic_flags_ext |= IEEE80211_FEXT_SEQNO_OFFLOAD; + /* Adjust capabilities. */ rtwn_adj_devcaps(sc); diff --git a/sys/dev/rtwn/if_rtwn_tx.c b/sys/dev/rtwn/if_rtwn_tx.c index 2c9c246dfbb4..fa7f35f2de83 100644 --- a/sys/dev/rtwn/if_rtwn_tx.c +++ b/sys/dev/rtwn/if_rtwn_tx.c @@ -183,6 +183,10 @@ rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, } } + /* seqno allocate, only if AMPDU isn't running */ + if ((m->m_flags & M_AMPDU_MPDU) == 0) + ieee80211_output_seqno_assign(ni, -1, m); + cipher = IEEE80211_CIPHER_NONE; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m); @@ -229,6 +233,10 @@ rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, uint8_t type; u_int cipher; + /* seqno allocate, only if AMPDU isn't running */ + if ((m->m_flags & M_AMPDU_MPDU) == 0) + ieee80211_output_seqno_assign(ni, -1, m); + /* Encrypt the frame if need be. */ cipher = IEEE80211_CIPHER_NONE; if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx.c b/sys/dev/rtwn/rtl8192c/r92c_tx.c index 6b013de0c536..ba2f60bd9295 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_tx.c +++ b/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -452,11 +452,10 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, } else { uint16_t seqno; - if (m->m_flags & M_AMPDU_MPDU) { - seqno = ni->ni_txseqs[tid] % IEEE80211_SEQ_RANGE; - ni->ni_txseqs[tid]++; - } else - seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; + if (m->m_flags & M_AMPDU_MPDU) + ieee80211_output_seqno_assign(ni, -1, m); + + seqno = M_SEQNO_GET(m); /* Set sequence number. */ txd->txdseq = htole16(seqno); @@ -511,7 +510,7 @@ r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, rtwn_r92c_tx_setup_hwseq(sc, txd); } else { /* Set sequence number. */ - txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); + txd->txdseq |= htole16(M_SEQNO_GET(m)); } } diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx.c b/sys/dev/rtwn/rtl8812a/r12a_tx.c index acb238316559..6a7af0a9b674 100644 --- a/sys/dev/rtwn/rtl8812a/r12a_tx.c +++ b/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -101,12 +101,12 @@ r12a_tx_set_vht_bw(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) prim_chan = r12a_get_primary_channel(sc, ni->ni_chan); - if (ieee80211_vht_check_tx_bw(ni, IEEE80211_STA_RX_BW_80)) { + if (ieee80211_vht_check_tx_bw(ni, NET80211_STA_RX_BW_80)) { txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, R12A_TXDW5_DATA_BW80)); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, prim_chan)); - } else if (ieee80211_vht_check_tx_bw(ni, IEEE80211_STA_RX_BW_40)) { + } else if (ieee80211_vht_check_tx_bw(ni, NET80211_STA_RX_BW_40)) { txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, R12A_TXDW5_DATA_BW40)); txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, @@ -433,12 +433,9 @@ r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, } else { uint16_t seqno; - if (m->m_flags & M_AMPDU_MPDU) { - seqno = ni->ni_txseqs[tid]; - ni->ni_txseqs[tid]++; - } else - seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; - + if (m->m_flags & M_AMPDU_MPDU) + ieee80211_output_seqno_assign(ni, -1, m); + seqno = M_SEQNO_GET(m); /* Set sequence number. */ txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno)); } @@ -493,8 +490,7 @@ r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); } else { /* Set sequence number. */ - txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, - M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE)); + txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, M_SEQNO_GET(m))); } } diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index 900578b73de4..80028063bb0d 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -133,6 +133,7 @@ static const struct { { HDA_INTEL_PCH, "Intel Ibex Peak", 0, 0 }, { HDA_INTEL_PCH2, "Intel Ibex Peak", 0, 0 }, { HDA_INTEL_ELLK, "Intel Elkhart Lake", 0, 0 }, + { HDA_INTEL_ELLK2, "Intel Elkhart Lake", 0, 0 }, { HDA_INTEL_JLK2, "Intel Jasper Lake", 0, 0 }, { HDA_INTEL_BXTNP, "Intel Broxton-P", 0, 0 }, { HDA_INTEL_SCH, "Intel SCH", 0, 0 }, @@ -1773,17 +1774,17 @@ hdac_detach(device_t dev) struct hdac_softc *sc = device_get_softc(dev); int i, error; + callout_drain(&sc->poll_callout); + hdac_irq_free(sc); + taskqueue_drain(taskqueue_thread, &sc->unsolq_task); + error = bus_generic_detach(dev); if (error != 0) return (error); hdac_lock(sc); - callout_stop(&sc->poll_callout); hdac_reset(sc, false); hdac_unlock(sc); - callout_drain(&sc->poll_callout); - taskqueue_drain(taskqueue_thread, &sc->unsolq_task); - hdac_irq_free(sc); for (i = 0; i < sc->num_ss; i++) hdac_dma_free(sc, &sc->streams[i].bdl); @@ -2206,4 +2207,4 @@ static driver_t hdac_driver = { sizeof(struct hdac_softc), }; -DRIVER_MODULE(snd_hda, pci, hdac_driver, NULL, NULL); +DRIVER_MODULE_ORDERED(snd_hda, pci, hdac_driver, NULL, NULL, SI_ORDER_ANY); diff --git a/sys/dev/sound/pci/hda/hdac.h b/sys/dev/sound/pci/hda/hdac.h index 223434a214b1..09a17f702019 100644 --- a/sys/dev/sound/pci/hda/hdac.h +++ b/sys/dev/sound/pci/hda/hdac.h @@ -66,6 +66,7 @@ #define HDA_INTEL_PCH HDA_MODEL_CONSTRUCT(INTEL, 0x3b56) #define HDA_INTEL_PCH2 HDA_MODEL_CONSTRUCT(INTEL, 0x3b57) #define HDA_INTEL_ELLK HDA_MODEL_CONSTRUCT(INTEL, 0x4b55) +#define HDA_INTEL_ELLK2 HDA_MODEL_CONSTRUCT(INTEL, 0x4b58) #define HDA_INTEL_JLK2 HDA_MODEL_CONSTRUCT(INTEL, 0x4dc8) #define HDA_INTEL_BXTNP HDA_MODEL_CONSTRUCT(INTEL, 0x5a98) #define HDA_INTEL_MACBOOKPRO92 HDA_MODEL_CONSTRUCT(INTEL, 0x7270) diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c index 876dd0bcc40d..067e7ccae8f9 100644 --- a/sys/dev/tpm/tpm20.c +++ b/sys/dev/tpm/tpm20.c @@ -25,8 +25,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> #include <sys/random.h> +#include <dev/random/randomdev.h> #include "tpm20.h" @@ -184,6 +184,13 @@ tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data, return (ENOTTY); } +#ifdef TPM_HARVEST +static const struct random_source random_tpm = { + .rs_ident = "TPM", + .rs_source = RANDOM_PURE_TPM, +}; +#endif + int tpm20_init(struct tpm_sc *sc) { @@ -206,7 +213,7 @@ tpm20_init(struct tpm_sc *sc) tpm20_release(sc); #ifdef TPM_HARVEST - random_harvest_register_source(RANDOM_PURE_TPM); + random_source_register(&random_tpm); TIMEOUT_TASK_INIT(taskqueue_thread, &sc->harvest_task, 0, tpm20_harvest, sc); taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task, 0); @@ -223,7 +230,7 @@ tpm20_release(struct tpm_sc *sc) #ifdef TPM_HARVEST if (device_is_attached(sc->dev)) taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task); - random_harvest_deregister_source(RANDOM_PURE_TPM); + random_source_deregister(&random_tpm); #endif if (sc->buf != NULL) diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h index b96d82ff836e..b055d2d2d769 100644 --- a/sys/dev/ufshci/ufshci.h +++ b/sys/dev/ufshci/ufshci.h @@ -716,6 +716,42 @@ struct ufshci_device_descriptor { _Static_assert(sizeof(struct ufshci_device_descriptor) == 89, "bad size for ufshci_device_descriptor"); +/* Defines the bit field of dExtendedUfsFeaturesSupport. */ +enum ufshci_desc_wb_ext_ufs_feature { + UFSHCI_DESC_EXT_UFS_FEATURE_FFU = (1 << 0), + UFSHCI_DESC_EXT_UFS_FEATURE_PSA = (1 << 1), + UFSHCI_DESC_EXT_UFS_FEATURE_DEV_LIFE_SPAN = (1 << 2), + UFSHCI_DESC_EXT_UFS_FEATURE_REFRESH_OP = (1 << 3), + UFSHCI_DESC_EXT_UFS_FEATURE_TOO_HIGH_TEMP = (1 << 4), + UFSHCI_DESC_EXT_UFS_FEATURE_TOO_LOW_TEMP = (1 << 5), + UFSHCI_DESC_EXT_UFS_FEATURE_EXT_TEMP = (1 << 6), + UFSHCI_DESC_EXT_UFS_FEATURE_HPB_SUPPORT = (1 << 7), + UFSHCI_DESC_EXT_UFS_FEATURE_WRITE_BOOSTER = (1 << 8), + UFSHCI_DESC_EXT_UFS_FEATURE_PERF_THROTTLING = (1 << 9), + UFSHCI_DESC_EXT_UFS_FEATURE_ADVANCED_RPMB = (1 << 10), + UFSHCI_DESC_EXT_UFS_FEATURE_ZONED_UFS_EXTENSION = (1 << 11), + UFSHCI_DESC_EXT_UFS_FEATURE_DEV_LEVEL_EXCEPTION = (1 << 12), + UFSHCI_DESC_EXT_UFS_FEATURE_HID = (1 << 13), + UFSHCI_DESC_EXT_UFS_FEATURE_BARRIER = (1 << 14), + UFSHCI_DESC_EXT_UFS_FEATURE_CLEAR_ERROR_HISTORY = (1 << 15), + UFSHCI_DESC_EXT_UFS_FEATURE_EXT_IID = (1 << 16), + UFSHCI_DESC_EXT_UFS_FEATURE_FBO = (1 << 17), + UFSHCI_DESC_EXT_UFS_FEATURE_FAST_RECOVERY_MODE = (1 << 18), + UFSHCI_DESC_EXT_UFS_FEATURE_RPMB_VENDOR_CMD = (1 << 19), +}; + +/* Defines the bit field of bWriteBoosterBufferType. */ +enum ufshci_desc_wb_buffer_type { + UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED = 0x00, + UFSHCI_DESC_WB_BUF_TYPE_SINGLE_SHARED = 0x01, +}; + +/* Defines the bit field of bWriteBoosterBufferPreserveUserSpaceEn. */ +enum ufshci_desc_user_space_config { + UFSHCI_DESC_WB_BUF_USER_SPACE_REDUCTION = 0x00, + UFSHCI_DESC_WB_BUF_PRESERVE_USER_SPACE = 0x01, +}; + /* * UFS Spec 4.1, section 14.1.5.3 "Configuration Descriptor" * ConfigurationDescriptor use big-endian byte ordering. @@ -1014,4 +1050,37 @@ enum ufshci_attributes { UFSHCI_ATTR_B_REFRESH_METHOD = 0x2f, }; +/* bAvailableWriteBoosterBufferSize codes (UFS WriteBooster abailable buffer + * left %) */ +enum ufshci_wb_available_buffer_Size { + UFSHCI_ATTR_WB_AVAILABLE_0 = 0x00, /* 0% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_10 = 0x01, /* 10% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_20 = 0x02, /* 20% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_30 = 0x03, /* 30% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_40 = 0x04, /* 40% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_50 = 0x05, /* 50% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_60 = 0x06, /* 60% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_70 = 0x07, /* 70% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_80 = 0x08, /* 80% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_90 = 0x09, /* 90% buffer remains */ + UFSHCI_ATTR_WB_AVAILABLE_100 = 0x0A, /* 100% buffer remains */ +}; + +/* bWriteBoosterBufferLifeTimeEst codes (UFS WriteBooster buffer life %) */ +enum ufshci_wb_lifetime { + UFSHCI_ATTR_WB_LIFE_DISABLED = 0x00, /* Info not available */ + UFSHCI_ATTR_WB_LIFE_0_10 = 0x01, /* 0%–10% used */ + UFSHCI_ATTR_WB_LIFE_10_20 = 0x02, /* 10%–20% used */ + UFSHCI_ATTR_WB_LIFE_20_30 = 0x03, /* 20%–30% used */ + UFSHCI_ATTR_WB_LIFE_30_40 = 0x04, /* 30%–40% used */ + UFSHCI_ATTR_WB_LIFE_40_50 = 0x05, /* 40%–50% used */ + UFSHCI_ATTR_WB_LIFE_50_60 = 0x06, /* 50%–60% used */ + UFSHCI_ATTR_WB_LIFE_60_70 = 0x07, /* 60%–70% used */ + UFSHCI_ATTR_WB_LIFE_70_80 = 0x08, /* 70%–80% used */ + UFSHCI_ATTR_WB_LIFE_80_90 = 0x09, /* 80%–90% used */ + UFSHCI_ATTR_WB_LIFE_90_100 = 0x0A, /* 90%–100% used */ + UFSHCI_ATTR_WB_LIFE_EXCEEDED = + 0x0B, /* Exceeded estimated life (treat as WB disabled) */ +}; + #endif /* __UFSHCI_H__ */ diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c index 37bd32665b2b..36be94b8b8b7 100644 --- a/sys/dev/ufshci/ufshci_ctrlr.c +++ b/sys/dev/ufshci/ufshci_ctrlr.c @@ -61,7 +61,7 @@ ufshci_ctrlr_enable_host_ctrlr(struct ufshci_controller *ctrlr) int ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) { - uint32_t ver, cap, hcs, ie; + uint32_t ver, cap, hcs, ie, ahit; uint32_t timeout_period, retry_count; int error; @@ -127,6 +127,13 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) if (error) return (error); + /* Read the UECPA register to clear */ + ufshci_mmio_read_4(ctrlr, uecpa); + + /* Diable Auto-hibernate */ + ahit = 0; + ufshci_mmio_write_4(ctrlr, ahit, ahit); + /* * The device_present(UFSHCI_HCS_REG_DP) bit becomes true if the host * controller has successfully received a Link Startup UIC command @@ -139,6 +146,16 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) return (ENXIO); } + /* Allocate and initialize UTP Task Management Request List. */ + error = ufshci_utmr_req_queue_construct(ctrlr); + if (error) + return (error); + + /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ + error = ufshci_utr_req_queue_construct(ctrlr); + if (error) + return (error); + /* Enable additional interrupts by programming the IE register. */ ie = ufshci_mmio_read_4(ctrlr, ie); ie |= UFSHCIM(UFSHCI_IE_REG_UTRCE); /* UTR Completion */ @@ -153,19 +170,12 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev) /* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */ - /* Allocate and initialize UTP Task Management Request List. */ - error = ufshci_utmr_req_queue_construct(ctrlr); - if (error) - return (error); - - /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */ - error = ufshci_utr_req_queue_construct(ctrlr); - if (error) - return (error); - /* TODO: Separate IO and Admin slot */ - /* max_hw_pend_io is the number of slots in the transfer_req_queue */ - ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries; + /* + * max_hw_pend_io is the number of slots in the transfer_req_queue. + * Reduce num_entries by one to reserve an admin slot. + */ + ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries - 1; return (0); } @@ -342,18 +352,19 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr) return; } - /* Read Controller Descriptor (Device, Geometry)*/ + /* Read Controller Descriptor (Device, Geometry) */ if (ufshci_dev_get_descriptor(ctrlr) != 0) { ufshci_ctrlr_fail(ctrlr, false); return; } - /* TODO: Configure Write Protect */ + if (ufshci_dev_config_write_booster(ctrlr)) { + ufshci_ctrlr_fail(ctrlr, false); + return; + } /* TODO: Configure Background Operations */ - /* TODO: Configure Write Booster */ - if (ufshci_sim_attach(ctrlr) != 0) { ufshci_ctrlr_fail(ctrlr, false); return; diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c index a0e32914e2aa..dd196b1d638b 100644 --- a/sys/dev/ufshci/ufshci_dev.c +++ b/sys/dev/ufshci/ufshci_dev.c @@ -60,6 +60,14 @@ ufshci_dev_read_geometry_descriptor(struct ufshci_controller *ctrlr, } static int +ufshci_dev_read_unit_descriptor(struct ufshci_controller *ctrlr, uint8_t lun, + struct ufshci_unit_descriptor *desc) +{ + return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_UNIT, lun, 0, + desc, sizeof(struct ufshci_unit_descriptor))); +} + +static int ufshci_dev_read_flag(struct ufshci_controller *ctrlr, enum ufshci_flags flag_type, uint8_t *flag) { @@ -114,6 +122,61 @@ ufshci_dev_set_flag(struct ufshci_controller *ctrlr, } static int +ufshci_dev_clear_flag(struct ufshci_controller *ctrlr, + enum ufshci_flags flag_type) +{ + struct ufshci_completion_poll_status status; + struct ufshci_query_param param; + + param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST; + param.opcode = UFSHCI_QUERY_OPCODE_CLEAR_FLAG; + param.type = flag_type; + param.index = 0; + param.selector = 0; + param.value = 0; + + status.done = 0; + ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb, + &status, param); + ufshci_completion_poll(&status); + if (status.error) { + ufshci_printf(ctrlr, "ufshci_dev_clear_flag failed!\n"); + return (ENXIO); + } + + return (0); +} + +static int +ufshci_dev_read_attribute(struct ufshci_controller *ctrlr, + enum ufshci_attributes attr_type, uint8_t index, uint8_t selector, + uint64_t *value) +{ + struct ufshci_completion_poll_status status; + struct ufshci_query_param param; + + param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST; + param.opcode = UFSHCI_QUERY_OPCODE_READ_ATTRIBUTE; + param.type = attr_type; + param.index = index; + param.selector = selector; + param.value = 0; + + status.done = 0; + ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb, + &status, param); + ufshci_completion_poll(&status); + if (status.error) { + ufshci_printf(ctrlr, "ufshci_dev_read_attribute failed!\n"); + return (ENXIO); + } + + *value = status.cpl.response_upiu.query_response_upiu.value_64; + + return (0); +} + +static int ufshci_dev_write_attribute(struct ufshci_controller *ctrlr, enum ufshci_attributes attr_type, uint8_t index, uint8_t selector, uint64_t value) @@ -270,7 +333,7 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr) */ const uint32_t fast_mode = 1; const uint32_t rx_bit_shift = 4; - const uint32_t power_mode = (fast_mode << rx_bit_shift) | fast_mode; + uint32_t power_mode, peer_granularity; /* Update lanes with available TX/RX lanes */ if (ufshci_uic_send_dme_get(ctrlr, PA_AvailTxDataLanes, @@ -295,6 +358,20 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr) ctrlr->rx_lanes)) return (ENXIO); + if (ctrlr->quirks & UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY) { + /* Before changing gears, first change the number of lanes. */ + if (ufshci_uic_send_dme_get(ctrlr, PA_PWRMode, &power_mode)) + return (ENXIO); + if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, power_mode)) + return (ENXIO); + + /* Wait for power mode changed. */ + if (ufshci_uic_power_mode_ready(ctrlr)) { + ufshci_reg_dump(ctrlr); + return (ENXIO); + } + } + /* Set HS-GEAR to max gear */ ctrlr->hs_gear = ctrlr->max_rx_hs_gear; if (ufshci_uic_send_dme_set(ctrlr, PA_TxGear, ctrlr->hs_gear)) @@ -346,6 +423,7 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr) return (ENXIO); /* Set TX/RX PWRMode */ + power_mode = (fast_mode << rx_bit_shift) | fast_mode; if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, power_mode)) return (ENXIO); @@ -366,7 +444,8 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr) pause_sbt("ufshci", ustosbt(1250), 0, C_PREL(1)); /* Test with dme_peer_get to make sure there are no errors. */ - if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity, NULL)) + if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity, + &peer_granularity)) return (ENXIO); } @@ -398,7 +477,7 @@ ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr) return (error); ver = be16toh(device->dev_desc.wSpecVersion); - ufshci_printf(ctrlr, "UFS device spec version %u.%u%u\n", + ufshci_printf(ctrlr, "UFS device spec version %u.%u.%u\n", UFSHCIV(UFSHCI_VER_REG_MJR, ver), UFSHCIV(UFSHCI_VER_REG_MNR, ver), UFSHCIV(UFSHCI_VER_REG_VS, ver)); ufshci_printf(ctrlr, "%u enabled LUNs found\n", @@ -426,3 +505,273 @@ ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr) return (0); } + +static int +ufshci_dev_enable_write_booster(struct ufshci_controller *ctrlr) +{ + struct ufshci_device *dev = &ctrlr->ufs_dev; + int error; + + /* Enable WriteBooster */ + error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN); + if (error) { + ufshci_printf(ctrlr, "Failed to enable WriteBooster\n"); + return (error); + } + dev->is_wb_enabled = true; + + /* Enable WriteBooster buffer flush during hibernate */ + error = ufshci_dev_set_flag(ctrlr, + UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE); + if (error) { + ufshci_printf(ctrlr, + "Failed to enable WriteBooster buffer flush during hibernate\n"); + return (error); + } + + /* Enable WriteBooster buffer flush */ + error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN); + if (error) { + ufshci_printf(ctrlr, + "Failed to enable WriteBooster buffer flush\n"); + return (error); + } + dev->is_wb_flush_enabled = true; + + return (0); +} + +static int +ufshci_dev_disable_write_booster(struct ufshci_controller *ctrlr) +{ + struct ufshci_device *dev = &ctrlr->ufs_dev; + int error; + + /* Disable WriteBooster buffer flush */ + error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN); + if (error) { + ufshci_printf(ctrlr, + "Failed to disable WriteBooster buffer flush\n"); + return (error); + } + dev->is_wb_flush_enabled = false; + + /* Disable WriteBooster buffer flush during hibernate */ + error = ufshci_dev_clear_flag(ctrlr, + UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE); + if (error) { + ufshci_printf(ctrlr, + "Failed to disable WriteBooster buffer flush during hibernate\n"); + return (error); + } + + /* Disable WriteBooster */ + error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN); + if (error) { + ufshci_printf(ctrlr, "Failed to disable WriteBooster\n"); + return (error); + } + dev->is_wb_enabled = false; + + return (0); +} + +static int +ufshci_dev_is_write_booster_buffer_life_time_left( + struct ufshci_controller *ctrlr, bool *is_life_time_left) +{ + struct ufshci_device *dev = &ctrlr->ufs_dev; + uint8_t buffer_lun; + uint64_t life_time; + uint32_t error; + + if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED) + buffer_lun = dev->wb_dedicated_lu; + else + buffer_lun = 0; + + error = ufshci_dev_read_attribute(ctrlr, + UFSHCI_ATTR_B_WB_BUFFER_LIFE_TIME_EST, buffer_lun, 0, &life_time); + if (error) + return (error); + + *is_life_time_left = (life_time != UFSHCI_ATTR_WB_LIFE_EXCEEDED); + + return (0); +} + +/* + * This function is not yet in use. It will be used when suspend/resume is + * implemented. + */ +static __unused int +ufshci_dev_need_write_booster_buffer_flush(struct ufshci_controller *ctrlr, + bool *need_flush) +{ + struct ufshci_device *dev = &ctrlr->ufs_dev; + bool is_life_time_left = false; + uint64_t available_buffer_size, current_buffer_size; + uint8_t buffer_lun; + uint32_t error; + + *need_flush = false; + + if (!dev->is_wb_enabled) + return (0); + + error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr, + &is_life_time_left); + if (error) + return (error); + + if (!is_life_time_left) + return (ufshci_dev_disable_write_booster(ctrlr)); + + if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED) + buffer_lun = dev->wb_dedicated_lu; + else + buffer_lun = 0; + + error = ufshci_dev_read_attribute(ctrlr, + UFSHCI_ATTR_B_AVAILABLE_WB_BUFFER_SIZE, buffer_lun, 0, + &available_buffer_size); + if (error) + return (error); + + switch (dev->wb_user_space_config_option) { + case UFSHCI_DESC_WB_BUF_USER_SPACE_REDUCTION: + *need_flush = (available_buffer_size <= + UFSHCI_ATTR_WB_AVAILABLE_10); + break; + case UFSHCI_DESC_WB_BUF_PRESERVE_USER_SPACE: + /* + * In PRESERVE USER SPACE mode, flush should be performed when + * the current buffer is greater than 0 and the available buffer + * below write_booster_flush_threshold is left. + */ + error = ufshci_dev_read_attribute(ctrlr, + UFSHCI_ATTR_D_CURRENT_WB_BUFFER_SIZE, buffer_lun, 0, + ¤t_buffer_size); + if (error) + return (error); + + if (current_buffer_size == 0) + return (0); + + *need_flush = (available_buffer_size < + dev->write_booster_flush_threshold); + break; + default: + ufshci_printf(ctrlr, + "Invalid bWriteBoosterBufferPreserveUserSpaceEn value"); + return (EINVAL); + } + + /* + * TODO: Need to handle WRITEBOOSTER_FLUSH_NEEDED exception case from + * wExceptionEventStatus attribute. + */ + + return (0); +} + +int +ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr) +{ + struct ufshci_device *dev = &ctrlr->ufs_dev; + uint32_t extended_ufs_feature_support; + uint32_t alloc_units; + struct ufshci_unit_descriptor unit_desc; + uint8_t lun; + bool is_life_time_left; + uint32_t mega_byte = 1024 * 1024; + uint32_t error = 0; + + extended_ufs_feature_support = be32toh( + dev->dev_desc.dExtendedUfsFeaturesSupport); + if (!(extended_ufs_feature_support & + UFSHCI_DESC_EXT_UFS_FEATURE_WRITE_BOOSTER)) { + /* This device does not support Write Booster */ + return (0); + } + + if (ufshci_dev_enable_write_booster(ctrlr)) + return (0); + + /* Get WriteBooster buffer parameters */ + dev->wb_buffer_type = dev->dev_desc.bWriteBoosterBufferType; + dev->wb_user_space_config_option = + dev->dev_desc.bWriteBoosterBufferPreserveUserSpaceEn; + + /* + * Find the size of the write buffer. + * With LU-dedicated (00h), the WriteBooster buffer is assigned + * exclusively to one chosen LU (not one-per-LU), whereas Shared (01h) + * uses a single device-wide buffer shared by multiple LUs. + */ + if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_SINGLE_SHARED) { + alloc_units = be32toh( + dev->dev_desc.dNumSharedWriteBoosterBufferAllocUnits); + ufshci_printf(ctrlr, + "WriteBooster buffer type = Shared, alloc_units=%d\n", + alloc_units); + } else if (dev->wb_buffer_type == + UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED) { + ufshci_printf(ctrlr, "WriteBooster buffer type = Dedicated\n"); + for (lun = 0; lun < ctrlr->max_lun_count; lun++) { + /* Find a dedicated buffer using a unit descriptor */ + if (ufshci_dev_read_unit_descriptor(ctrlr, lun, + &unit_desc)) + continue; + + alloc_units = be32toh( + unit_desc.dLUNumWriteBoosterBufferAllocUnits); + if (alloc_units) { + dev->wb_dedicated_lu = lun; + break; + } + } + } else { + ufshci_printf(ctrlr, + "Not supported WriteBooster buffer type: 0x%x\n", + dev->wb_buffer_type); + goto out; + } + + if (alloc_units == 0) { + ufshci_printf(ctrlr, "The WriteBooster buffer size is zero\n"); + goto out; + } + + dev->wb_buffer_size_mb = alloc_units * + dev->geo_desc.bAllocationUnitSize * + (be32toh(dev->geo_desc.dSegmentSize)) / + (mega_byte / UFSHCI_SECTOR_SIZE); + + /* Set to flush when 40% of the available buffer size remains */ + dev->write_booster_flush_threshold = UFSHCI_ATTR_WB_AVAILABLE_40; + + /* + * Check if WriteBooster Buffer lifetime is left. + * WriteBooster Buffer lifetime — percent of life used based on P/E + * cycles. If "preserve user space" is enabled, writes to normal user + * space also consume WB life since the area is shared. + */ + error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr, + &is_life_time_left); + if (error) + goto out; + + if (!is_life_time_left) { + ufshci_printf(ctrlr, + "There is no WriteBooster buffer life time left.\n"); + goto out; + } + + ufshci_printf(ctrlr, "WriteBooster Enabled\n"); + return (0); +out: + ufshci_dev_disable_write_booster(ctrlr); + return (error); +} + diff --git a/sys/dev/ufshci/ufshci_pci.c b/sys/dev/ufshci/ufshci_pci.c index 65a69ee0b518..d64b7526f713 100644 --- a/sys/dev/ufshci/ufshci_pci.c +++ b/sys/dev/ufshci/ufshci_pci.c @@ -53,7 +53,8 @@ static struct _pcsid { { 0x98fa8086, "Intel Lakefield UFS Host Controller", UFSHCI_REF_CLK_19_2MHz, UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE | - UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE }, + UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE | + UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY }, { 0x54ff8086, "Intel UFS Host Controller", UFSHCI_REF_CLK_19_2MHz }, { 0x00000000, NULL } }; diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h index 1a2742ae2e80..2e033f84c373 100644 --- a/sys/dev/ufshci/ufshci_private.h +++ b/sys/dev/ufshci/ufshci_private.h @@ -46,6 +46,8 @@ MALLOC_DECLARE(M_UFSHCI); #define UFSHCI_UTR_ENTRIES (32) #define UFSHCI_UTRM_ENTRIES (8) +#define UFSHCI_SECTOR_SIZE (512) + struct ufshci_controller; struct ufshci_completion_poll_status { @@ -214,6 +216,15 @@ struct ufshci_device { struct ufshci_geometry_descriptor geo_desc; uint32_t unipro_version; + + /* WriteBooster */ + bool is_wb_enabled; + bool is_wb_flush_enabled; + uint32_t wb_buffer_type; + uint32_t wb_buffer_size_mb; + uint32_t wb_user_space_config_option; + uint8_t wb_dedicated_lu; + uint32_t write_booster_flush_threshold; }; /* @@ -229,7 +240,8 @@ struct ufshci_controller { 2 /* Need an additional 200 ms of PA_TActivate */ #define UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE \ 4 /* Need to wait 1250us after power mode change */ - +#define UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY \ + 8 /* Need to change the number of lanes before changing HS-GEAR. */ uint32_t ref_clk; struct cam_sim *ufshci_sim; @@ -356,6 +368,7 @@ int ufshci_dev_init_unipro(struct ufshci_controller *ctrlr); int ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr); int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr); int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr); +int ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr); /* Controller Command */ void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr, diff --git a/sys/dev/ufshci/ufshci_reg.h b/sys/dev/ufshci/ufshci_reg.h index 6c9b3e2c8c04..6d5768505102 100644 --- a/sys/dev/ufshci/ufshci_reg.h +++ b/sys/dev/ufshci/ufshci_reg.h @@ -274,7 +274,7 @@ struct ufshci_registers { #define UFSHCI_HCS_REG_UTMRLRDY_MASK (0x1) #define UFSHCI_HCS_REG_UCRDY_SHIFT (3) #define UFSHCI_HCS_REG_UCRDY_MASK (0x1) -#define UFSHCI_HCS_REG_UPMCRS_SHIFT (7) +#define UFSHCI_HCS_REG_UPMCRS_SHIFT (8) #define UFSHCI_HCS_REG_UPMCRS_MASK (0x7) #define UFSHCI_HCS_REG_UTPEC_SHIFT (12) #define UFSHCI_HCS_REG_UTPEC_MASK (0xF) diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c index 5e5069f12e5f..56bc06b13f3c 100644 --- a/sys/dev/ufshci/ufshci_sysctl.c +++ b/sys/dev/ufshci/ufshci_sysctl.c @@ -152,6 +152,7 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr) struct sysctl_ctx_list *ctrlr_ctx; struct sysctl_oid *ctrlr_tree, *que_tree, *ioq_tree; struct sysctl_oid_list *ctrlr_list, *ioq_list; + struct ufshci_device *dev = &ctrlr->ufs_dev; #define QUEUE_NAME_LENGTH 16 char queue_name[QUEUE_NAME_LENGTH]; int i; @@ -177,6 +178,25 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr) SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "cap", CTLFLAG_RD, &ctrlr->cap, 0, "Number of I/O queue pairs"); + SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_enabled", + CTLFLAG_RD, &dev->is_wb_enabled, 0, "WriteBooster enable/disable"); + + SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_flush_enabled", + CTLFLAG_RD, &dev->is_wb_flush_enabled, 0, + "WriteBooster flush enable/disable"); + + SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_type", + CTLFLAG_RD, &dev->wb_buffer_type, 0, "WriteBooster type"); + + SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_size_mb", + CTLFLAG_RD, &dev->wb_buffer_size_mb, 0, + "WriteBooster buffer size in MB"); + + SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, + "wb_user_space_config_option", CTLFLAG_RD, + &dev->wb_user_space_config_option, 0, + "WriteBooster preserve user space mode"); + SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period, 0, ufshci_sysctl_timeout_period, "IU", diff --git a/sys/dev/ufshci/ufshci_uic_cmd.c b/sys/dev/ufshci/ufshci_uic_cmd.c index 2c5f635dc11e..b9c867ff7065 100644 --- a/sys/dev/ufshci/ufshci_uic_cmd.c +++ b/sys/dev/ufshci/ufshci_uic_cmd.c @@ -14,7 +14,7 @@ int ufshci_uic_power_mode_ready(struct ufshci_controller *ctrlr) { - uint32_t is; + uint32_t is, hcs; int timeout; /* Wait for the IS flag to change */ @@ -40,6 +40,15 @@ ufshci_uic_power_mode_ready(struct ufshci_controller *ctrlr) DELAY(10); } + /* Check HCS power mode change request status */ + hcs = ufshci_mmio_read_4(ctrlr, hcs); + if (UFSHCIV(UFSHCI_HCS_REG_UPMCRS, hcs) != 0x01) { + ufshci_printf(ctrlr, + "Power mode change request status error: 0x%x\n", + UFSHCIV(UFSHCI_HCS_REG_UPMCRS, hcs)); + return (ENXIO); + } + return (0); } @@ -112,6 +121,7 @@ ufshci_uic_send_cmd(struct ufshci_controller *ctrlr, struct ufshci_uic_cmd *uic_cmd, uint32_t *return_value) { int error; + uint32_t config_result_code; mtx_lock(&ctrlr->uic_cmd_lock); @@ -134,6 +144,13 @@ ufshci_uic_send_cmd(struct ufshci_controller *ctrlr, if (error) return (ENXIO); + config_result_code = ufshci_mmio_read_4(ctrlr, ucmdarg2); + if (config_result_code) { + ufshci_printf(ctrlr, + "Failed to send UIC command. (config result code = 0x%x)\n", + config_result_code); + } + if (return_value != NULL) *return_value = ufshci_mmio_read_4(ctrlr, ucmdarg3); diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 5be592512196..788b2b718062 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -156,6 +156,7 @@ struct xhci_std_temp { static void xhci_do_poll(struct usb_bus *); static void xhci_device_done(struct usb_xfer *, usb_error_t); +static void xhci_get_xecp(struct xhci_softc *); static void xhci_root_intr(struct xhci_softc *); static void xhci_free_device_ext(struct usb_device *); static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, @@ -566,6 +567,8 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) device_printf(self, "%d bytes context size, %d-bit DMA\n", sc->sc_ctx_is_64_byte ? 64 : 32, (int)sc->sc_bus.dma_bits); + xhci_get_xecp(sc); + /* enable 64Kbyte control endpoint quirk */ sc->sc_bus.control_ep_quirk = (xhcictlquirk ? 1 : 0); @@ -654,6 +657,88 @@ xhci_uninit(struct xhci_softc *sc) } static void +xhci_get_xecp(struct xhci_softc *sc) +{ + + uint32_t hccp1; + uint32_t eec; + uint32_t eecp; + bool first = true; + + hccp1 = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + if (XHCI_HCS0_XECP(hccp1) == 0) { + device_printf(sc->sc_bus.parent, + "xECP: no capabilities found\n"); + return; + } + + /* + * Parse the xECP Capabilities table and print known caps. + * Implemented, vendor and reserved xECP Capabilities values are + * documented in Table 7.2 of eXtensible Host Controller Interface for + * Universal Serial Bus (xHCI) Rev 1.2b 2023. + */ + device_printf(sc->sc_bus.parent, "xECP capabilities <"); + + eec = -1; + for (eecp = XHCI_HCS0_XECP(hccp1) << 2; + eecp != 0 && XHCI_XECP_NEXT(eec) != 0; + eecp += XHCI_XECP_NEXT(eec) << 2) { + eec = XREAD4(sc, capa, eecp); + + uint8_t xecpid = XHCI_XECP_ID(eec); + + if ((xecpid >= 11 && xecpid <= 16) || + (xecpid >= 19 && xecpid <= 191)) { + if (!first) + printf(","); + printf("RES(%x)", xecpid); + } else if (xecpid > 191) { + if (!first) + printf(","); + printf("VEND(%x)", xecpid); + } else { + if (!first) + printf(","); + switch (xecpid) + { + case XHCI_ID_USB_LEGACY: + printf("LEGACY"); + break; + case XHCI_ID_PROTOCOLS: + printf("PROTO"); + break; + case XHCI_ID_POWER_MGMT: + printf("POWER"); + break; + case XHCI_ID_VIRTUALIZATION: + printf("VIRT"); + break; + case XHCI_ID_MSG_IRQ: + printf("MSG IRQ"); + break; + case XHCI_ID_USB_LOCAL_MEM: + printf("LOCAL MEM"); + break; + case XHCI_ID_USB_DEBUG: + printf("DEBUG"); + break; + case XHCI_ID_EXT_MSI: + printf("EXT MSI"); + break; + case XHCI_ID_USB3_TUN: + printf("TUN"); + break; + + } + } + first = false; + } + printf(">\n"); +} + +static void xhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) { struct xhci_softc *sc = XHCI_BUS2SC(bus); diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c index d5cfd228a429..820fb2f738a1 100644 --- a/sys/dev/usb/controller/xhci_pci.c +++ b/sys/dev/usb/controller/xhci_pci.c @@ -178,6 +178,8 @@ xhci_pci_match(device_t self) return ("Intel Tiger Lake-H USB 3.2 controller"); case 0x461e8086: return ("Intel Alder Lake-P Thunderbolt 4 USB controller"); + case 0x4b7d8086: + return ("Intel Elkhart Lake USB 3.1 controller"); case 0x51ed8086: return ("Intel Alder Lake USB 3.2 controller"); case 0x5aa88086: diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h index 9d0b6e2f4b4b..821897155544 100644 --- a/sys/dev/usb/controller/xhcireg.h +++ b/sys/dev/usb/controller/xhcireg.h @@ -205,6 +205,11 @@ #define XHCI_ID_VIRTUALIZATION 0x0004 #define XHCI_ID_MSG_IRQ 0x0005 #define XHCI_ID_USB_LOCAL_MEM 0x0006 +/* values 7-9 are reserved */ +#define XHCI_ID_USB_DEBUG 0x000a +/* values 11-16 are reserved */ +#define XHCI_ID_EXT_MSI 0x0011 +#define XHCI_ID_USB3_TUN 0x0012 /* XHCI register R/W wrappers */ #define XREAD1(sc, what, a) \ diff --git a/sys/dev/usb/net/if_umb.c b/sys/dev/usb/net/if_umb.c index f640b4224aad..b1082b117259 100644 --- a/sys/dev/usb/net/if_umb.c +++ b/sys/dev/usb/net/if_umb.c @@ -177,9 +177,7 @@ static void umb_ncm_setup(struct umb_softc *, struct usb_config *); static void umb_close_bulkpipes(struct umb_softc *); static int umb_ioctl(if_t , u_long, caddr_t); static void umb_init(void *); -#ifdef DEV_NETMAP static void umb_input(if_t , struct mbuf *); -#endif static int umb_output(if_t , struct mbuf *, const struct sockaddr *, struct route *); static void umb_start(if_t ); @@ -585,9 +583,7 @@ umb_attach_task(struct usb_proc_msg *msg) if_setsoftc(ifp, sc); if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_POINTOPOINT); if_setioctlfn(ifp, umb_ioctl); -#ifdef DEV_NETMAP if_setinputfn(ifp, umb_input); -#endif if_setoutputfn(ifp, umb_output); if_setstartfn(ifp, umb_start); if_setinitfn(ifp, umb_init); diff --git a/sys/dev/usb/wlan/if_rsu.c b/sys/dev/usb/wlan/if_rsu.c index 07f7b6f3a708..e976948f6849 100644 --- a/sys/dev/usb/wlan/if_rsu.c +++ b/sys/dev/usb/wlan/if_rsu.c @@ -371,18 +371,16 @@ rsu_update_chw(struct ieee80211com *ic) /* * notification from net80211 that it'd like to do A-MPDU on the given TID. - * - * Note: this actually hangs traffic at the present moment, so don't use it. - * The firmware debug does indiciate it's sending and establishing a TX AMPDU - * session, but then no traffic flows. */ static int rsu_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { -#if 0 struct rsu_softc *sc = ni->ni_ic->ic_softc; struct r92s_add_ba_req req; + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: called, tid=%d\n", + __func__, tap->txa_tid); + /* Don't enable if it's requested or running */ if (IEEE80211_AMPDU_REQUESTED(tap)) return (0); @@ -397,23 +395,30 @@ rsu_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) return (0); /* Send the firmware command */ - RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: establishing AMPDU TX for TID %d\n", + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, + "%s: establishing AMPDU TX for TID %d\n", __func__, tap->txa_tid); RSU_LOCK(sc); - if (rsu_fw_cmd(sc, R92S_CMD_ADDBA_REQ, &req, sizeof(req)) != 1) { + if (rsu_fw_cmd(sc, R92S_CMD_ADDBA_REQ, &req, sizeof(req)) != 0) { RSU_UNLOCK(sc); + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: AMPDU TX cmd failure\n", + __func__); /* Mark failure */ - (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 0); + ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 0); + /* Return 0, we've been driving this ourselves */ return (0); } RSU_UNLOCK(sc); + RSU_DPRINTF(sc, RSU_DEBUG_AMPDU, "%s: AMPDU TX cmd success\n", + __func__); + /* Mark success; we don't get any further notifications */ - (void) ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 1); -#endif - /* Return 0, we're driving this ourselves */ + ieee80211_ampdu_tx_request_active_ext(ni, tap->txa_tid, 1); + + /* Return 0, we've been driving this ourselves */ return (0); } @@ -563,9 +568,7 @@ rsu_attach(device_t self) /* Enable basic HT */ ic->ic_htcaps = IEEE80211_HTC_HT | -#if 0 IEEE80211_HTC_AMPDU | -#endif IEEE80211_HTC_AMSDU | IEEE80211_HTCAP_MAXAMSDU_3839 | IEEE80211_HTCAP_SMPS_OFF; @@ -576,6 +579,7 @@ rsu_attach(device_t self) ic->ic_rxstream = sc->sc_nrxstream; } ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD; + ic->ic_flags_ext |= IEEE80211_FEXT_SEQNO_OFFLOAD; rsu_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, ic->ic_channels); @@ -1537,6 +1541,10 @@ rsu_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, is_checked = 1; k->wk_flags |= IEEE80211_KEY_SWCRYPT; } else + /* + * TODO: should allocate these from the CAM space; + * skipping over the fixed slots and _BC / _BSS. + */ *keyix = R92S_MACID_BSS; } @@ -2166,7 +2174,7 @@ rsu_event_addba_req_report(struct rsu_softc *sc, uint8_t *buf, int len) __func__, ether_sprintf(ba->mac_addr), (int) ba->tid, - (int) le16toh(ba->ssn)); + (int) le16toh(ba->ssn) >> 4); /* XXX do node lookup; this is STA specific */ @@ -2212,6 +2220,11 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) if (vap->iv_state == IEEE80211_S_AUTH) rsu_event_join_bss(sc, buf, len); break; + + /* TODO: what about R92S_EVT_ADD_STA? and decoding macid? */ + /* It likely is required for IBSS/AP mode */ + + /* TODO: should I be doing this transition in AP mode? */ case R92S_EVT_DEL_STA: RSU_DPRINTF(sc, RSU_DEBUG_FWCMD | RSU_DEBUG_STATE, "%s: disassociated from %s\n", __func__, @@ -2229,6 +2242,7 @@ rsu_rx_event(struct rsu_softc *sc, uint8_t code, uint8_t *buf, int len) break; case R92S_EVT_FWDBG: buf[60] = '\0'; + /* TODO: some are \n terminated, some aren't, sigh */ RSU_DPRINTF(sc, RSU_DEBUG_FWDBG, "FWDBG: %s\n", (char *)buf); break; case R92S_EVT_ADDBA_REQ_REPORT: @@ -2782,6 +2796,9 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, if (rate != 0) ridx = rate2ridx(rate); + /* Assign sequence number, A-MPDU or otherwise */ + ieee80211_output_seqno_assign(ni, -1, m0); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { k = ieee80211_crypto_encap(ni, m0); if (k == NULL) { @@ -2838,8 +2855,10 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, SM(R92S_TXDW0_OFFSET, sizeof(*txd)) | R92S_TXDW0_OWN | R92S_TXDW0_FSG | R92S_TXDW0_LSG); + /* TODO: correct macid here? It should be in the node */ txd->txdw1 |= htole32( SM(R92S_TXDW1_MACID, R92S_MACID_BSS) | SM(R92S_TXDW1_QSEL, qid)); + if (!hasqos) txd->txdw1 |= htole32(R92S_TXDW1_NONQOS); if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWENCRYPT)) { @@ -2860,8 +2879,13 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, SM(R92S_TXDW1_CIPHER, cipher) | SM(R92S_TXDW1_KEYIDX, k->wk_keyix)); } - /* XXX todo: set AGGEN bit if appropriate? */ - txd->txdw2 |= htole32(R92S_TXDW2_BK); + + /* + * Note: no need to set TXDW2_AGGEN/TXDW2_BK to mark + * A-MPDU and non-AMPDU candidates; the firmware will + * handle this for us. + */ + if (ismcast) txd->txdw2 |= htole32(R92S_TXDW2_BMCAST); @@ -2880,8 +2904,11 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni, } /* - * Firmware will use and increment the sequence number for the - * specified priority. + * Pass in prio here, NOT the sequence number. + * + * The hardware is in theory incrementing sequence numbers + * for us, but I haven't yet figured out exactly when/how + * it's supposed to work. */ txd->txdw3 |= htole32(SM(R92S_TXDW3_SEQ, prio)); @@ -3481,7 +3508,8 @@ rsu_load_firmware(struct rsu_softc *sc) dmem.vcs_mode = R92S_VCS_MODE_RTS_CTS; dmem.turbo_mode = 0; dmem.bw40_en = !! (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40); - dmem.amsdu2ampdu_en = !! (sc->sc_ht); + /* net80211 handles AMSDUs just fine */ + dmem.amsdu2ampdu_en = 0; dmem.ampdu_en = !! (sc->sc_ht); dmem.agg_offload = !! (sc->sc_ht); dmem.qos_en = 1; diff --git a/sys/dev/usb/wlan/if_rsureg.h b/sys/dev/usb/wlan/if_rsureg.h index fb706a4d9b1a..e2074e1dd2ad 100644 --- a/sys/dev/usb/wlan/if_rsureg.h +++ b/sys/dev/usb/wlan/if_rsureg.h @@ -593,7 +593,14 @@ struct r92s_event_join_bss { struct ndis_wlan_bssid_ex bss; } __packed; -#define R92S_MACID_BSS 5 /* XXX hardcoded somewhere */ +/* + * This is hard-coded in the firmware for a STA mode + * BSS join. If you turn on FWDEBUG, you'll see this + * in the logs: + * + * rsu0: FWDBG: mac id #5: 0000005b, 000fffff, 00000000 + */ +#define R92S_MACID_BSS 5 /* Rx MAC descriptor. */ struct r92s_rx_stat { diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 97c790dd5b81..147aa4044057 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -882,6 +882,7 @@ run_attach(device_t self) ic->ic_flags |= IEEE80211_F_DATAPAD; ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; + ic->ic_flags_ext |= IEEE80211_FEXT_SEQNO_OFFLOAD; run_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, ic->ic_channels); @@ -3522,6 +3523,9 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) data->ni = ni; data->ridx = ridx; + /* Assign sequence number now, regardless of A-MPDU TX or otherwise (for now) */ + ieee80211_output_seqno_assign(ni, -1, m); + run_set_tx_desc(sc, data); /* @@ -3627,6 +3631,9 @@ run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) data->ni = ni; data->ridx = ridx; + /* Assign sequence number now, regardless of A-MPDU TX or otherwise (for now) */ + ieee80211_output_seqno_assign(ni, -1, m); + run_set_tx_desc(sc, data); RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "sending mgt frame len=%d rate=%d\n", @@ -3771,6 +3778,9 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, break; data->ridx = ridx; + /* Assign sequence number now, regardless of A-MPDU TX or otherwise (for now) */ + ieee80211_output_seqno_assign(ni, -1, m); + run_set_tx_desc(sc, data); RUN_DPRINTF(sc, RUN_DEBUG_XMIT, "sending raw frame len=%u rate=%u\n", @@ -6416,6 +6426,10 @@ run_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { /* For now, no A-MPDU TX support in the driver */ + /* + * TODO: maybe we needed to enable seqno generation too? + * What other TX desc bits are missing/needed? + */ return (0); } diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c index 867da80a53a8..528ff3372097 100644 --- a/sys/dev/virtio/network/if_vtnet.c +++ b/sys/dev/virtio/network/if_vtnet.c @@ -133,12 +133,14 @@ static int vtnet_rxq_replace_lro_nomrg_buf(struct vtnet_rxq *, static int vtnet_rxq_replace_buf(struct vtnet_rxq *, struct mbuf *, int); static int vtnet_rxq_enqueue_buf(struct vtnet_rxq *, struct mbuf *); static int vtnet_rxq_new_buf(struct vtnet_rxq *); +#if defined(INET) || defined(INET6) static int vtnet_rxq_csum_needs_csum(struct vtnet_rxq *, struct mbuf *, - uint16_t, int, struct virtio_net_hdr *); -static int vtnet_rxq_csum_data_valid(struct vtnet_rxq *, struct mbuf *, - uint16_t, int, struct virtio_net_hdr *); + bool, int, struct virtio_net_hdr *); +static void vtnet_rxq_csum_data_valid(struct vtnet_rxq *, struct mbuf *, + int); static int vtnet_rxq_csum(struct vtnet_rxq *, struct mbuf *, struct virtio_net_hdr *); +#endif static void vtnet_rxq_discard_merged_bufs(struct vtnet_rxq *, int); static void vtnet_rxq_discard_buf(struct vtnet_rxq *, struct mbuf *); static int vtnet_rxq_merged_eof(struct vtnet_rxq *, struct mbuf *, int); @@ -1178,6 +1180,7 @@ vtnet_setup_interface(struct vtnet_softc *sc) if (sc->vtnet_max_mtu >= ETHERMTU_JUMBO) if_setcapabilitiesbit(ifp, IFCAP_JUMBO_MTU, 0); if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); + if_setcapabilitiesbit(ifp, IFCAP_HWSTATS, 0); /* * Capabilities after here are not enabled by default. @@ -1760,164 +1763,165 @@ vtnet_rxq_new_buf(struct vtnet_rxq *rxq) return (error); } +#if defined(INET) || defined(INET6) static int -vtnet_rxq_csum_needs_csum(struct vtnet_rxq *rxq, struct mbuf *m, uint16_t etype, - int hoff, struct virtio_net_hdr *hdr) +vtnet_rxq_csum_needs_csum(struct vtnet_rxq *rxq, struct mbuf *m, bool isipv6, + int protocol, struct virtio_net_hdr *hdr) { struct vtnet_softc *sc; - int error; - sc = rxq->vtnrx_sc; + /* + * The packet is likely from another VM on the same host or from the + * host that itself performed checksum offloading so Tx/Rx is basically + * a memcpy and the checksum has little value so far. + */ + + KASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP, + ("%s: unsupported IP protocol %d", __func__, protocol)); /* - * NEEDS_CSUM corresponds to Linux's CHECKSUM_PARTIAL, but FreeBSD does - * not have an analogous CSUM flag. The checksum has been validated, - * but is incomplete (TCP/UDP pseudo header). - * - * The packet is likely from another VM on the same host that itself - * performed checksum offloading so Tx/Rx is basically a memcpy and - * the checksum has little value. - * - * Default to receiving the packet as-is for performance reasons, but - * this can cause issues if the packet is to be forwarded because it - * does not contain a valid checksum. This patch may be helpful: - * https://reviews.freebsd.org/D6611. In the meantime, have the driver - * compute the checksum if requested. - * - * BMV: Need to add an CSUM_PARTIAL flag? + * If the user don't want us to fix it up here by computing the + * checksum, just forward the order to compute the checksum by setting + * the corresponding mbuf flag (e.g., CSUM_TCP). */ + sc = rxq->vtnrx_sc; if ((sc->vtnet_flags & VTNET_FLAG_FIXUP_NEEDS_CSUM) == 0) { - error = vtnet_rxq_csum_data_valid(rxq, m, etype, hoff, hdr); - return (error); + switch (protocol) { + case IPPROTO_TCP: + m->m_pkthdr.csum_flags |= + (isipv6 ? CSUM_TCP_IPV6 : CSUM_TCP); + break; + case IPPROTO_UDP: + m->m_pkthdr.csum_flags |= + (isipv6 ? CSUM_UDP_IPV6 : CSUM_UDP); + break; + } + m->m_pkthdr.csum_data = hdr->csum_offset; + return (0); } /* * Compute the checksum in the driver so the packet will contain a * valid checksum. The checksum is at csum_offset from csum_start. */ - switch (etype) { -#if defined(INET) || defined(INET6) - case ETHERTYPE_IP: - case ETHERTYPE_IPV6: { - int csum_off, csum_end; - uint16_t csum; - - csum_off = hdr->csum_start + hdr->csum_offset; - csum_end = csum_off + sizeof(uint16_t); + int csum_off, csum_end; + uint16_t csum; - /* Assume checksum will be in the first mbuf. */ - if (m->m_len < csum_end || m->m_pkthdr.len < csum_end) - return (1); + csum_off = hdr->csum_start + hdr->csum_offset; + csum_end = csum_off + sizeof(uint16_t); - /* - * Like in_delayed_cksum()/in6_delayed_cksum(), compute the - * checksum and write it at the specified offset. We could - * try to verify the packet: csum_start should probably - * correspond to the start of the TCP/UDP header. - * - * BMV: Need to properly handle UDP with zero checksum. Is - * the IPv4 header checksum implicitly validated? - */ - csum = in_cksum_skip(m, m->m_pkthdr.len, hdr->csum_start); - *(uint16_t *)(mtodo(m, csum_off)) = csum; - m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - m->m_pkthdr.csum_data = 0xFFFF; - break; - } -#endif - default: - sc->vtnet_stats.rx_csum_bad_ethtype++; + /* Assume checksum will be in the first mbuf. */ + if (m->m_len < csum_end || m->m_pkthdr.len < csum_end) { + sc->vtnet_stats.rx_csum_bad_offset++; return (1); } + /* + * Like in_delayed_cksum()/in6_delayed_cksum(), compute the + * checksum and write it at the specified offset. We could + * try to verify the packet: csum_start should probably + * correspond to the start of the TCP/UDP header. + * + * BMV: Need to properly handle UDP with zero checksum. Is + * the IPv4 header checksum implicitly validated? + */ + csum = in_cksum_skip(m, m->m_pkthdr.len, hdr->csum_start); + *(uint16_t *)(mtodo(m, csum_off)) = csum; + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; + return (0); } +static void +vtnet_rxq_csum_data_valid(struct vtnet_rxq *rxq, struct mbuf *m, int protocol) +{ + KASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP, + ("%s: unsupported IP protocol %d", __func__, protocol)); + + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; +} + static int -vtnet_rxq_csum_data_valid(struct vtnet_rxq *rxq, struct mbuf *m, - uint16_t etype, int hoff, struct virtio_net_hdr *hdr __unused) +vtnet_rxq_csum(struct vtnet_rxq *rxq, struct mbuf *m, + struct virtio_net_hdr *hdr) { -#if 0 + const struct ether_header *eh; struct vtnet_softc *sc; -#endif - int protocol; + int hoff, protocol; + uint16_t etype; + bool isipv6; + + KASSERT(hdr->flags & + (VIRTIO_NET_HDR_F_NEEDS_CSUM | VIRTIO_NET_HDR_F_DATA_VALID), + ("%s: missing checksum offloading flag %x", __func__, hdr->flags)); + + eh = mtod(m, const struct ether_header *); + etype = ntohs(eh->ether_type); + if (etype == ETHERTYPE_VLAN) { + /* TODO BMV: Handle QinQ. */ + const struct ether_vlan_header *evh = + mtod(m, const struct ether_vlan_header *); + etype = ntohs(evh->evl_proto); + hoff = sizeof(struct ether_vlan_header); + } else + hoff = sizeof(struct ether_header); -#if 0 sc = rxq->vtnrx_sc; -#endif + /* Check whether ethernet type is IP or IPv6, and get protocol. */ switch (etype) { #if defined(INET) case ETHERTYPE_IP: - if (__predict_false(m->m_len < hoff + sizeof(struct ip))) - protocol = IPPROTO_DONE; - else { + if (__predict_false(m->m_len < hoff + sizeof(struct ip))) { + sc->vtnet_stats.rx_csum_inaccessible_ipproto++; + return (1); + } else { struct ip *ip = (struct ip *)(m->m_data + hoff); protocol = ip->ip_p; } + isipv6 = false; break; #endif #if defined(INET6) case ETHERTYPE_IPV6: if (__predict_false(m->m_len < hoff + sizeof(struct ip6_hdr)) - || ip6_lasthdr(m, hoff, IPPROTO_IPV6, &protocol) < 0) - protocol = IPPROTO_DONE; + || ip6_lasthdr(m, hoff, IPPROTO_IPV6, &protocol) < 0) { + sc->vtnet_stats.rx_csum_inaccessible_ipproto++; + return (1); + } + isipv6 = true; break; #endif default: - protocol = IPPROTO_DONE; - break; + sc->vtnet_stats.rx_csum_bad_ethtype++; + return (1); } + /* Check whether protocol is TCP or UDP. */ switch (protocol) { case IPPROTO_TCP: case IPPROTO_UDP: - m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; - m->m_pkthdr.csum_data = 0xFFFF; break; default: /* * FreeBSD does not support checksum offloading of this - * protocol. Let the stack re-verify the checksum later - * if the protocol is supported. + * protocol here. */ -#if 0 - if_printf(sc->vtnet_ifp, - "%s: checksum offload of unsupported protocol " - "etype=%#x protocol=%d csum_start=%d csum_offset=%d\n", - __func__, etype, protocol, hdr->csum_start, - hdr->csum_offset); -#endif - break; + sc->vtnet_stats.rx_csum_bad_ipproto++; + return (1); } - return (0); -} - -static int -vtnet_rxq_csum(struct vtnet_rxq *rxq, struct mbuf *m, - struct virtio_net_hdr *hdr) -{ - const struct ether_header *eh; - int hoff; - uint16_t etype; - - eh = mtod(m, const struct ether_header *); - etype = ntohs(eh->ether_type); - if (etype == ETHERTYPE_VLAN) { - /* TODO BMV: Handle QinQ. */ - const struct ether_vlan_header *evh = - mtod(m, const struct ether_vlan_header *); - etype = ntohs(evh->evl_proto); - hoff = sizeof(struct ether_vlan_header); - } else - hoff = sizeof(struct ether_header); - if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) - return (vtnet_rxq_csum_needs_csum(rxq, m, etype, hoff, hdr)); + return (vtnet_rxq_csum_needs_csum(rxq, m, isipv6, protocol, + hdr)); else /* VIRTIO_NET_HDR_F_DATA_VALID */ - return (vtnet_rxq_csum_data_valid(rxq, m, etype, hoff, hdr)); + vtnet_rxq_csum_data_valid(rxq, m, protocol); + + return (0); } +#endif static void vtnet_rxq_discard_merged_bufs(struct vtnet_rxq *rxq, int nbufs) @@ -2040,10 +2044,15 @@ vtnet_rxq_input(struct vtnet_rxq *rxq, struct mbuf *m, if (hdr->flags & (VIRTIO_NET_HDR_F_NEEDS_CSUM | VIRTIO_NET_HDR_F_DATA_VALID)) { +#if defined(INET) || defined(INET6) if (vtnet_rxq_csum(rxq, m, hdr) == 0) rxq->vtnrx_stats.vrxs_csum++; else rxq->vtnrx_stats.vrxs_csum_failed++; +#else + sc->vtnet_stats.rx_csum_bad_ethtype++; + rxq->vtnrx_stats.vrxs_csum_failed++; +#endif } if (hdr->gso_size != 0) { @@ -2497,6 +2506,10 @@ vtnet_txq_offload(struct vtnet_txq *txq, struct mbuf *m, hdr->csum_start = vtnet_gtoh16(sc, csum_start); hdr->csum_offset = vtnet_gtoh16(sc, m->m_pkthdr.csum_data); txq->vtntx_stats.vtxs_csum++; + } else if ((flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) && + (proto == IPPROTO_TCP || proto == IPPROTO_UDP) && + (m->m_pkthdr.csum_data == 0xFFFF)) { + hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID; } if (flags & (CSUM_IP_TSO | CSUM_IP6_TSO)) { @@ -2610,7 +2623,8 @@ vtnet_txq_encap(struct vtnet_txq *txq, struct mbuf **m_head, int flags) m->m_flags &= ~M_VLANTAG; } - if (m->m_pkthdr.csum_flags & VTNET_CSUM_ALL_OFFLOAD) { + if (m->m_pkthdr.csum_flags & + (VTNET_CSUM_ALL_OFFLOAD | CSUM_DATA_VALID)) { m = vtnet_txq_offload(txq, m, hdr); if ((*m_head = m) == NULL) { error = ENOBUFS; @@ -3032,16 +3046,14 @@ vtnet_get_counter(if_t ifp, ift_counter cnt) return (rxaccum.vrxs_iqdrops); case IFCOUNTER_IERRORS: return (rxaccum.vrxs_ierrors); + case IFCOUNTER_IBYTES: + return (rxaccum.vrxs_ibytes); case IFCOUNTER_OPACKETS: return (txaccum.vtxs_opackets); case IFCOUNTER_OBYTES: - if (!VTNET_ALTQ_ENABLED) - return (txaccum.vtxs_obytes); - /* FALLTHROUGH */ + return (txaccum.vtxs_obytes); case IFCOUNTER_OMCASTS: - if (!VTNET_ALTQ_ENABLED) - return (txaccum.vtxs_omcasts); - /* FALLTHROUGH */ + return (txaccum.vtxs_omcasts); default: return (if_get_counter_default(ifp, cnt)); } @@ -4322,9 +4334,9 @@ vtnet_setup_stat_sysctl(struct sysctl_ctx_list *ctx, SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_bad_offset", CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_bad_offset, "Received checksum offloaded buffer with incorrect offset"); - SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_bad_proto", - CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_bad_proto, - "Received checksum offloaded buffer with incorrect protocol"); + SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_inaccessible_ipproto", + CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_inaccessible_ipproto, + "Received checksum offloaded buffer with inaccessible IP protocol"); SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_csum_failed", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_STATS, sc, 0, vtnet_sysctl_rx_csum_failed, "QU", diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h index 0144b0f3232d..cab7ced639a7 100644 --- a/sys/dev/virtio/network/if_vtnetvar.h +++ b/sys/dev/virtio/network/if_vtnetvar.h @@ -46,7 +46,7 @@ struct vtnet_statistics { uint64_t rx_csum_bad_ethtype; uint64_t rx_csum_bad_ipproto; uint64_t rx_csum_bad_offset; - uint64_t rx_csum_bad_proto; + uint64_t rx_csum_inaccessible_ipproto; uint64_t tx_csum_unknown_ethtype; uint64_t tx_csum_proto_mismatch; uint64_t tx_tso_not_tcp; diff --git a/sys/dev/vmgenc/vmgenc_acpi.c b/sys/dev/vmgenc/vmgenc_acpi.c index 2ad8929dfd34..18519a8e4f22 100644 --- a/sys/dev/vmgenc/vmgenc_acpi.c +++ b/sys/dev/vmgenc/vmgenc_acpi.c @@ -56,6 +56,7 @@ #include <contrib/dev/acpica/include/acpi.h> #include <dev/acpica/acpivar.h> +#include <dev/random/randomdev.h> #include <dev/random/random_harvestq.h> #include <dev/vmgenc/vmgenc_acpi.h> @@ -210,6 +211,11 @@ acpi_GetPackedUINT64(device_t dev, ACPI_HANDLE handle, char *path, } +static const struct random_source random_vmgenid = { + .rs_ident = "VM Generation ID", + .rs_source = RANDOM_PURE_VMGENID, +}; + static int vmgenc_attach(device_t dev) { @@ -234,7 +240,7 @@ vmgenc_attach(device_t dev) memcpy(sc->vmg_cache_guid, __DEVOLATILE(void *, sc->vmg_pguid), sizeof(sc->vmg_cache_guid)); - random_harvest_register_source(RANDOM_PURE_VMGENID); + random_source_register(&random_vmgenid); vmgenc_harvest_all(sc->vmg_cache_guid, sizeof(sc->vmg_cache_guid)); AcpiInstallNotifyHandler(h, ACPI_DEVICE_NOTIFY, vmgenc_notify, dev); diff --git a/sys/dev/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c index 9f2b009d02ec..460a508a60dc 100644 --- a/sys/dev/vmm/vmm_dev.c +++ b/sys/dev/vmm/vmm_dev.c @@ -901,6 +901,7 @@ vmmdev_lookup_and_destroy(const char *name, struct ucred *cred) sc->cdev = NULL; sx_xunlock(&vmmdev_mtx); + vm_suspend(sc->vm, VM_SUSPEND_DESTROY); destroy_dev(cdev); vmmdev_destroy(sc); |