sync with OpenBSD -current

This commit is contained in:
purplerain 2024-06-06 00:05:03 +00:00
parent 2d7157972b
commit 6040ea8924
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
17 changed files with 989 additions and 255 deletions

View file

@ -1,4 +1,4 @@
/* $OpenBSD: hibernate_machdep.c,v 1.50 2023/04/24 09:04:03 dv Exp $ */
/* $OpenBSD: hibernate_machdep.c,v 1.51 2024/06/05 04:58:05 mglocker Exp $ */
/*
* Copyright (c) 2012 Mike Larkin <mlarkin@openbsd.org>
@ -51,6 +51,7 @@
#include "sd.h"
#include "nvme.h"
#include "sdmmc.h"
#include "ufshci.h"
/* Hibernate support */
void hibernate_enter_resume_4k_pte(vaddr_t, paddr_t);
@ -97,6 +98,8 @@ get_hibernate_io_function(dev_t dev)
vaddr_t addr, size_t size, int op, void *page);
extern int sdmmc_scsi_hibernate_io(dev_t dev, daddr_t blkno,
vaddr_t addr, size_t size, int op, void *page);
extern int ufshci_hibernate_io(dev_t dev, daddr_t blkno,
vaddr_t addr, size_t size, int op, void *page);
struct device *dv = disk_lookup(&sd_cd, DISKUNIT(dev));
struct {
const char *driver;
@ -113,6 +116,9 @@ get_hibernate_io_function(dev_t dev)
#endif
#if NSDMMC > 0
{ "sdmmc", sdmmc_scsi_hibernate_io },
#endif
#if NUFSHCI > 0
{ "ufshci", ufshci_hibernate_io },
#endif
};

View file

@ -1,4 +1,4 @@
# $OpenBSD: Makefile.amd64,v 1.135 2024/06/04 15:14:45 deraadt Exp $
# $OpenBSD: Makefile.amd64,v 1.136 2024/06/05 20:19:26 deraadt Exp $
# For instructions on building kernels consult the config(8) and options(4)
# manual pages.
@ -73,7 +73,7 @@ CMACHFLAGS+= -mno-retpoline -fcf-protection=none
.endif
.else
CMACHFLAGS+= -mretpoline-external-thunk -fcf-protection=branch
CMACHFLAGS+= -fret-clean
#CMACHFLAGS+= -fret-clean
.endif
.if ${COMPILER_VERSION:Mclang}
NO_INTEGR_AS= -no-integrated-as

View file

@ -1,4 +1,4 @@
/* $OpenBSD: dwqe.c,v 1.21 2024/05/06 09:54:38 stsp Exp $ */
/* $OpenBSD: dwqe.c,v 1.22 2024/06/05 10:19:55 stsp Exp $ */
/*
* Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se>
@ -21,6 +21,7 @@
*/
#include "bpfilter.h"
#include "vlan.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -99,6 +100,53 @@ dwqe_have_tx_csum_offload(struct dwqe_softc *sc)
return (sc->sc_hw_feature[0] & GMAC_MAC_HW_FEATURE0_TXCOESEL);
}
int
dwqe_have_tx_vlan_offload(struct dwqe_softc *sc)
{
#if NVLAN > 0
return (sc->sc_hw_feature[0] & GMAC_MAC_HW_FEATURE0_SAVLANINS);
#else
return 0;
#endif
}
void
dwqe_set_vlan_rx_mode(struct dwqe_softc *sc)
{
#if NVLAN > 0
uint32_t reg;
/* Enable outer VLAN tag stripping on Rx. */
reg = dwqe_read(sc, GMAC_VLAN_TAG_CTRL);
reg |= GMAC_VLAN_TAG_CTRL_EVLRXS | GMAC_VLAN_TAG_CTRL_STRIP_ALWAYS;
dwqe_write(sc, GMAC_VLAN_TAG_CTRL, reg);
#endif
}
void
dwqe_set_vlan_tx_mode(struct dwqe_softc *sc)
{
#if NVLAN > 0
uint32_t reg;
reg = dwqe_read(sc, GMAC_VLAN_TAG_INCL);
/* Enable insertion of outer VLAN tag. */
reg |= GMAC_VLAN_TAG_INCL_INSERT;
/*
* Generate C-VLAN tags (type 0x8100, 802.1Q). Setting this
* bit would result in S-VLAN tags (type 0x88A8, 802.1ad).
*/
reg &= ~GMAC_VLAN_TAG_INCL_CSVL;
/* Use VLAN tags provided in Tx context descriptors. */
reg |= GMAC_VLAN_TAG_INCL_VLTI;
dwqe_write(sc, GMAC_VLAN_TAG_INCL, reg);
#endif
}
int
dwqe_attach(struct dwqe_softc *sc)
{
@ -127,6 +175,8 @@ dwqe_attach(struct dwqe_softc *sc)
bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
ifp->if_capabilities = IFCAP_VLAN_MTU;
if (dwqe_have_tx_vlan_offload(sc))
ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
if (dwqe_have_tx_csum_offload(sc)) {
ifp->if_capabilities |= (IFCAP_CSUM_IPv4 |
IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4 |
@ -218,6 +268,14 @@ dwqe_attach(struct dwqe_softc *sc)
if (!sc->sc_fixed_link)
dwqe_mii_attach(sc);
/*
* All devices support VLAN tag stripping on Rx but inserting
* VLAN tags during Tx is an optional feature.
*/
dwqe_set_vlan_rx_mode(sc);
if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)
dwqe_set_vlan_tx_mode(sc);
if_attach(ifp);
ether_ifattach(ifp);
@ -329,7 +387,8 @@ dwqe_start(struct ifqueue *ifq)
used = 0;
for (;;) {
if (used + DWQE_NTXSEGS + 1 > left) {
/* VLAN tags require an extra Tx context descriptor. */
if (used + DWQE_NTXSEGS + 2 > left) {
ifq_set_oactive(ifq);
break;
}
@ -714,6 +773,21 @@ dwqe_rx_csum(struct dwqe_softc *sc, struct mbuf *m, struct dwqe_desc *rxd)
m->m_pkthdr.csum_flags |= csum_flags;
}
void
dwqe_vlan_strip(struct dwqe_softc *sc, struct mbuf *m, struct dwqe_desc *rxd)
{
#if NVLAN > 0
uint16_t tag;
if ((rxd->sd_tdes3 & RDES3_RDES0_VALID) &&
(rxd->sd_tdes3 & RDES3_LD)) {
tag = rxd->sd_tdes0 & RDES0_OVT;
m->m_pkthdr.ether_vtag = le16toh(tag);
m->m_flags |= M_VLANTAG;
}
#endif
}
void
dwqe_rx_proc(struct dwqe_softc *sc)
{
@ -763,6 +837,7 @@ dwqe_rx_proc(struct dwqe_softc *sc)
m->m_pkthdr.len = m->m_len = len;
dwqe_rx_csum(sc, m, rxd);
dwqe_vlan_strip(sc, m, rxd);
ml_enqueue(&ml, m);
}
@ -1107,12 +1182,34 @@ dwqe_tx_csum(struct dwqe_softc *sc, struct mbuf *m, struct dwqe_desc *txd)
txd->sd_tdes3 |= TDES3_CSUM_IPHDR_PAYLOAD_PSEUDOHDR;
}
uint16_t
dwqe_set_tx_context_desc(struct dwqe_softc *sc, struct mbuf *m, int idx)
{
uint16_t tag = 0;
#if NVLAN > 0
struct dwqe_desc *ctxt_txd;
if ((m->m_flags & M_VLANTAG) == 0)
return 0;
tag = m->m_pkthdr.ether_vtag;
if (tag) {
ctxt_txd = &sc->sc_txdesc[idx];
ctxt_txd->sd_tdes3 |= (htole16(tag) & TDES3_VLAN_TAG);
ctxt_txd->sd_tdes3 |= TDES3_VLAN_TAG_VALID;
ctxt_txd->sd_tdes3 |= (TDES3_CTXT | TDES3_OWN);
}
#endif
return tag;
}
int
dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used)
{
struct dwqe_desc *txd, *txd_start;
bus_dmamap_t map;
int cur, frag, i;
uint16_t vlan_tag = 0;
cur = frag = *idx;
map = sc->sc_txbuf[cur].tb_map;
@ -1128,6 +1225,17 @@ dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used)
bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
BUS_DMASYNC_PREWRITE);
if (dwqe_have_tx_vlan_offload(sc)) {
vlan_tag = dwqe_set_tx_context_desc(sc, m, frag);
if (vlan_tag) {
(*used)++;
if (frag == (DWQE_NTXDESC - 1))
frag = 0;
else
frag++;
}
}
txd = txd_start = &sc->sc_txdesc[frag];
for (i = 0; i < map->dm_nsegs; i++) {
/* TODO: check for 32-bit vs 64-bit support */
@ -1140,6 +1248,8 @@ dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used)
if (i == 0) {
txd->sd_tdes3 |= TDES3_FS;
dwqe_tx_csum(sc, m, txd);
if (vlan_tag)
txd->sd_tdes2 |= TDES2_VLAN_TAG_INSERT;
}
if (i == (map->dm_nsegs - 1)) {
txd->sd_tdes2 |= TDES2_IC;

View file

@ -1,4 +1,4 @@
/* $OpenBSD: dwqereg.h,v 1.9 2024/05/06 09:54:38 stsp Exp $ */
/* $OpenBSD: dwqereg.h,v 1.10 2024/06/05 10:19:55 stsp Exp $ */
/*
* Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se>
@ -44,6 +44,19 @@
#define GMAC_INT_MASK_LPIIM (1 << 10)
#define GMAC_INT_MASK_PIM (1 << 3)
#define GMAC_INT_MASK_RIM (1 << 0)
#define GMAC_VLAN_TAG_CTRL 0x0050
#define GMAC_VLAN_TAG_CTRL_EVLRXS (1 << 24)
#define GMAC_VLAN_TAG_CTRL_STRIP_ALWAYS ((1 << 21) | (1 << 22))
#define GMAC_VLAN_TAG_DATA 0x0054
#define GMAC_VLAN_TAG_INCL 0x0060
#define GMAC_VLAN_TAG_INCL_VLTI (1 << 20)
#define GMAC_VLAN_TAG_INCL_CSVL (1 << 19)
#define GMAC_VLAN_TAG_INCL_DELETE 0x10000
#define GMAC_VLAN_TAG_INCL_INSERT 0x20000
#define GMAC_VLAN_TAG_INCL_REPLACE 0x30000
#define GMAC_VLAN_TAG_INCL_VLT 0x0ffff
#define GMAC_VLAN_TAG_INCL_RDWR (1U << 30)
#define GMAC_VLAN_TAG_INCL_BUSY (1U << 31)
#define GMAC_QX_TX_FLOW_CTRL(x) (0x0070 + (x) * 4)
#define GMAC_QX_TX_FLOW_CTRL_PT_SHIFT 16
#define GMAC_QX_TX_FLOW_CTRL_TFE (1 << 0)
@ -64,6 +77,7 @@
#define GMAC_MAC_HW_FEATURE(x) (0x011c + (x) * 0x4)
#define GMAC_MAC_HW_FEATURE0_TXCOESEL (1 << 14)
#define GMAC_MAC_HW_FEATURE0_RXCOESEL (1 << 16)
#define GMAC_MAC_HW_FEATURE0_SAVLANINS (1 << 27)
#define GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(x) (((x) >> 6) & 0x1f)
#define GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(x) (((x) >> 0) & 0x1f)
#define GMAC_MAC_MDIO_ADDR 0x0200
@ -230,6 +244,12 @@ struct dwqe_desc {
uint32_t sd_tdes3;
};
/* Tx context descriptor bits (host to device); precedes regular descriptor */
#define TDES3_CTXT (1 << 30)
#define TDES3_VLAN_TAG_VALID (1 << 16)
#define TDES3_VLAN_TAG 0xffff
/* Bit 31 is the OWN bit, as in regular Tx descriptor. */
/* Tx bits (read format; host to device) */
#define TDES2_HDR_LEN 0x000003ff /* if TSO is enabled */
#define TDES2_BUF1_LEN 0x00003fff /* if TSO is disabled */
@ -250,6 +270,11 @@ struct dwqe_desc {
#define TDES3_CSUM_IPHDR_PAYLOAD (0x2 << 16)
#define TDES3_CSUM_IPHDR_PAYLOAD_PSEUDOHDR (0x3 << 16)
#define TDES3_TSO_EN (1 << 18)
#define TDES3_CPC ((1 << 26) | (1 << 27)) /* if TSO is disabled */
#define TDES3_CPC_CRC_AND_PAD (0x0 << 26)
#define TDES3_CPC_CRC_NO_PAD (0x1 << 26)
#define TDES3_CPC_DISABLE (0x2 << 26)
#define TDES3_CPC_CRC_REPLACE (0x3 << 26)
#define TDES3_LS (1 << 28)
#define TDES3_FS (1 << 29)
#define TDES3_OWN (1U << 31)
@ -268,6 +293,8 @@ struct dwqe_desc {
#define RDES3_OWN (1U << 31)
/* Rx bits (writeback format; device to host) */
#define RDES0_IVT 0xffff0000
#define RDES0_OVT 0x0000ffff
#define RDES1_IP_PAYLOAD_TYPE 0x7
#define RDES1_IP_PAYLOAD_UNKNOWN 0x0
#define RDES1_IP_PAYLOAD_UDP 0x1

View file

@ -1,4 +1,4 @@
/* $OpenBSD: ufshci.c,v 1.33 2024/05/27 10:27:58 mglocker Exp $ */
/* $OpenBSD: ufshci.c,v 1.34 2024/06/05 04:58:05 mglocker Exp $ */
/*
* Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org>
@ -42,6 +42,13 @@
#include <dev/ic/ufshcivar.h>
#include <dev/ic/ufshcireg.h>
#ifdef HIBERNATE
#include <uvm/uvm_extern.h>
#include <sys/hibernate.h>
#include <sys/disklabel.h>
#include <sys/disk.h>
#endif
#ifdef UFSHCI_DEBUG
int ufshci_dbglvl = 1;
#define DPRINTF(l, x...) do { if ((l) <= ufshci_dbglvl) printf(x); } \
@ -59,7 +66,9 @@ int ufshci_is_poll(struct ufshci_softc *, uint32_t);
struct ufshci_dmamem *ufshci_dmamem_alloc(struct ufshci_softc *, size_t);
void ufshci_dmamem_free(struct ufshci_softc *,
struct ufshci_dmamem *);
int ufshci_alloc(struct ufshci_softc *);
int ufshci_init(struct ufshci_softc *);
int ufshci_disable(struct ufshci_softc *);
int ufshci_doorbell_read(struct ufshci_softc *);
void ufshci_doorbell_write(struct ufshci_softc *, int);
int ufshci_doorbell_poll(struct ufshci_softc *, int,
@ -104,6 +113,11 @@ void ufshci_scsi_io_done(struct ufshci_softc *,
void ufshci_scsi_done(struct ufshci_softc *,
struct ufshci_ccb *);
#if HIBERNATE
int ufshci_hibernate_io(dev_t, daddr_t, vaddr_t, size_t,
int, void *);
#endif
const struct scsi_adapter ufshci_switch = {
ufshci_scsi_cmd, NULL, NULL, NULL, NULL
};
@ -227,6 +241,8 @@ ufshci_attach(struct ufshci_softc *sc)
#if 0
sc->sc_flags |= UFSHCI_FLAGS_AGGR_INTR; /* Enable intr. aggregation */
#endif
/* Allocate the DMA buffers and initialize the controller. */
ufshci_alloc(sc);
ufshci_init(sc);
if (ufshci_ccb_alloc(sc, sc->sc_nutrs) != 0) {
@ -371,6 +387,39 @@ ufshci_dmamem_free(struct ufshci_softc *sc, struct ufshci_dmamem *udm)
free(udm, M_DEVBUF, sizeof(*udm));
}
int
ufshci_alloc(struct ufshci_softc *sc)
{
/* 7.1.1 Host Controller Initialization: 13) */
sc->sc_dmamem_utmrd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_utmrd) * sc->sc_nutmrs);
if (sc->sc_dmamem_utmrd == NULL) {
printf("%s: Can't allocate DMA memory for UTMRD\n",
sc->sc_dev.dv_xname);
return -1;
}
/* 7.1.1 Host Controller Initialization: 15) */
sc->sc_dmamem_utrd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_utrd) * sc->sc_nutrs);
if (sc->sc_dmamem_utrd == NULL) {
printf("%s: Can't allocate DMA memory for UTRD\n",
sc->sc_dev.dv_xname);
return -1;
}
/* Allocate UCDs. */
sc->sc_dmamem_ucd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_ucd) * sc->sc_nutrs);
if (sc->sc_dmamem_ucd == NULL) {
printf("%s: Can't allocate DMA memory for UCD\n",
sc->sc_dev.dv_xname);
return -1;
}
return 0;
}
int
ufshci_init(struct ufshci_softc *sc)
{
@ -430,44 +479,18 @@ ufshci_init(struct ufshci_softc *sc)
* TODO: More UIC commands to issue?
*/
/* 7.1.1 Host Controller Initialization: 13) */
sc->sc_dmamem_utmrd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_utmrd) * sc->sc_nutmrs);
if (sc->sc_dmamem_utmrd == NULL) {
printf("%s: Can't allocate DMA memory for UTMRD\n",
sc->sc_dev.dv_xname);
return -1;
}
/* 7.1.1 Host Controller Initialization: 14) */
dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utmrd);
DPRINTF(2, "%s: utmrd dva=%llu\n", __func__, dva);
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBA, (uint32_t)dva);
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLBAU, (uint32_t)(dva >> 32));
/* 7.1.1 Host Controller Initialization: 15) */
sc->sc_dmamem_utrd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_utrd) * sc->sc_nutrs);
if (sc->sc_dmamem_utrd == NULL) {
printf("%s: Can't allocate DMA memory for UTRD\n",
sc->sc_dev.dv_xname);
return -1;
}
/* 7.1.1 Host Controller Initialization: 16) */
dva = UFSHCI_DMA_DVA(sc->sc_dmamem_utrd);
DPRINTF(2, "%s: utrd dva=%llu\n", __func__, dva);
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBA, (uint32_t)dva);
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLBAU, (uint32_t)(dva >> 32));
/* Allocate UCDs. */
sc->sc_dmamem_ucd = ufshci_dmamem_alloc(sc,
sizeof(struct ufshci_ucd) * sc->sc_nutrs);
if (sc->sc_dmamem_ucd == NULL) {
printf("%s: Can't allocate DMA memory for UCD\n",
sc->sc_dev.dv_xname);
return -1;
}
/* 7.1.1 Host Controller Initialization: 17) */
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLRSR, UFSHCI_REG_UTMRLRSR_START);
@ -482,6 +505,19 @@ ufshci_init(struct ufshci_softc *sc)
return 0;
}
int
ufshci_disable(struct ufshci_softc *sc)
{
/* Stop run queues. */
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTMRLRSR, UFSHCI_REG_UTMRLRSR_STOP);
UFSHCI_WRITE_4(sc, UFSHCI_REG_UTRLRSR, UFSHCI_REG_UTRLRSR_STOP);
/* Disable interrupts. */
UFSHCI_WRITE_4(sc, UFSHCI_REG_IE, 0);
return 0;
}
int
ufshci_doorbell_read(struct ufshci_softc *sc)
{
@ -1353,11 +1389,11 @@ ufshci_activate(struct ufshci_softc *sc, int act)
case DVACT_POWERDOWN:
DPRINTF(1, "%s: POWERDOWN\n", __func__);
rv = config_activate_children(&sc->sc_dev, act);
ufshci_powerdown(sc);
ufshci_disable(sc);
break;
case DVACT_RESUME:
DPRINTF(1, "%s: RESUME\n", __func__);
ufshci_resume(sc);
rv = ufshci_init(sc);
if (rv == 0)
rv = config_activate_children(&sc->sc_dev, act);
break;
@ -1369,56 +1405,6 @@ ufshci_activate(struct ufshci_softc *sc, int act)
return rv;
}
int
ufshci_powerdown(struct ufshci_softc *sc)
{
uint32_t reg;
/* Send "hibernate enter" command. */
UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD,
UFSHCI_REG_UICCMD_CMDOP_DME_HIBERNATE_ENTER);
if (ufshci_is_poll(sc, UFSHCI_REG_IS_UHES) != 0) {
printf("%s: hibernate enter cmd failed\n", __func__);
return 1;
}
/* Check if "hibernate enter" command was executed successfully. */
reg = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
DPRINTF(1, "%s: UPMCRS=0x%x\n", __func__, UFSHCI_REG_HCS_UPMCRS(reg));
if (UFSHCI_REG_HCS_UPMCRS(reg) > UFSHCI_REG_HCS_UPMCRS_PWR_REMTOTE) {
printf("%s: hibernate enter cmd returned UPMCRS error=0x%x\n",
__func__, UFSHCI_REG_HCS_UPMCRS(reg));
return 1;
}
return 0;
}
int
ufshci_resume(struct ufshci_softc *sc)
{
uint32_t reg;
/* Send "hibernate exit" command. */
UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD,
UFSHCI_REG_UICCMD_CMDOP_DME_HIBERNATE_EXIT);
if (ufshci_is_poll(sc, UFSHCI_REG_IS_UHXS) != 0) {
printf("%s: hibernate exit command failed\n", __func__);
return 1;
}
/* Check if "hibernate exit" command was executed successfully. */
reg = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
DPRINTF(1, "%s: UPMCRS=0x%x\n", __func__, UFSHCI_REG_HCS_UPMCRS(reg));
if (UFSHCI_REG_HCS_UPMCRS(reg) > UFSHCI_REG_HCS_UPMCRS_PWR_REMTOTE) {
printf("%s: hibernate exit cmd returned UPMCRS error=0x%x\n",
__func__, UFSHCI_REG_HCS_UPMCRS(reg));
return 1;
}
return 0;
}
/* SCSI */
int
@ -1928,3 +1914,155 @@ ufshci_scsi_done(struct ufshci_softc *sc, struct ufshci_ccb *ccb)
xs->resid = 0;
scsi_done(xs);
}
#if HIBERNATE
int
ufshci_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size,
int op, void *page)
{
struct ufshci_hibernate_page {
struct ufshci_utrd utrd;
struct ufshci_ucd ucd;
struct ufshci_softc *sc; /* Copy of softc */
daddr_t poffset; /* Start of SWAP partition */
size_t psize; /* Size of SWAP partition */
uint32_t secsize; /* Our sector size */
} *my = page;
paddr_t data_phys, page_phys;
uint64_t data_bus_phys, page_bus_phys;
uint64_t timeout_us;
int off, len, slot;
uint32_t blocks, reg;
uint64_t lba;
if (op == HIB_INIT) {
struct device *disk;
struct device *scsibus;
extern struct cfdriver sd_cd;
/* Find ufshci softc. */
disk = disk_lookup(&sd_cd, DISKUNIT(dev));
if (disk == NULL)
return ENOTTY;
scsibus = disk->dv_parent;
my->sc = (struct ufshci_softc *)disk->dv_parent->dv_parent;
/* Stop run queues and disable interrupts. */
ufshci_disable(my->sc);
/* Tell the controler the new hibernate UTRD address. */
pmap_extract(pmap_kernel(), (vaddr_t)page, &page_phys);
page_bus_phys = page_phys + ((void *)&my->utrd - page);
UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLBA,
(uint32_t)page_bus_phys);
UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLBAU,
(uint32_t)(page_bus_phys >> 32));
/* Start run queues. */
UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTMRLRSR,
UFSHCI_REG_UTMRLRSR_START);
UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLRSR,
UFSHCI_REG_UTRLRSR_START);
my->poffset = blkno;
my->psize = size;
my->secsize = UFSHCI_LBS;
return 0;
}
if (op != HIB_W)
return 0;
if (blkno + (size / DEV_BSIZE) > my->psize)
return E2BIG;
blocks = size / my->secsize;
lba = (blkno + my->poffset) / (my->secsize / DEV_BSIZE);
/*
* The following code is a ripped down version of ufshci_utr_cmd_io()
* adapted for hibernate.
*/
slot = 0; /* We only use the first slot for hibernate */
memset(&my->utrd, 0, sizeof(struct ufshci_utrd));
my->utrd.dw0 = UFSHCI_UTRD_DW0_CT_UFS;
my->utrd.dw0 |= UFSHCI_UTRD_DW0_DD_I2T;
my->utrd.dw0 |= UFSHCI_UTRD_DW0_I_REG;
my->utrd.dw2 = UFSHCI_UTRD_DW2_OCS_IOV;
memset(&my->ucd, 0, sizeof(struct ufshci_ucd));
my->ucd.cmd.hdr.tc = UPIU_TC_I2T_COMMAND;
my->ucd.cmd.hdr.flags = (1 << 5); /* Bit-5 = Write */
my->ucd.cmd.hdr.lun = 0;
my->ucd.cmd.hdr.task_tag = slot;
my->ucd.cmd.hdr.cmd_set_type = 0; /* SCSI command */
my->ucd.cmd.hdr.query = 0;
my->ucd.cmd.hdr.response = 0;
my->ucd.cmd.hdr.status = 0;
my->ucd.cmd.hdr.ehs_len = 0;
my->ucd.cmd.hdr.device_info = 0;
my->ucd.cmd.hdr.ds_len = 0;
my->ucd.cmd.expected_xfer_len = htobe32(UFSHCI_LBS * blocks);
my->ucd.cmd.cdb[0] = WRITE_10; /* 0x2a */
my->ucd.cmd.cdb[1] = (1 << 3); /* FUA: Force Unit Access */
my->ucd.cmd.cdb[2] = (lba >> 24) & 0xff;
my->ucd.cmd.cdb[3] = (lba >> 16) & 0xff;
my->ucd.cmd.cdb[4] = (lba >> 8) & 0xff;
my->ucd.cmd.cdb[5] = (lba >> 0) & 0xff;
my->ucd.cmd.cdb[7] = (blocks >> 8) & 0xff;
my->ucd.cmd.cdb[8] = (blocks >> 0) & 0xff;
pmap_extract(pmap_kernel(), (vaddr_t)page, &page_phys);
page_bus_phys = page_phys + ((void *)&my->ucd - page);
my->utrd.dw4 = (uint32_t)page_bus_phys;
my->utrd.dw5 = (uint32_t)(page_bus_phys >> 32);
off = sizeof(struct upiu_command) / 4; /* DWORD offset */
my->utrd.dw6 = UFSHCI_UTRD_DW6_RUO(off);
len = sizeof(struct upiu_response) / 4; /* DWORD length */
my->utrd.dw6 |= UFSHCI_UTRD_DW6_RUL(len);
off = (sizeof(struct upiu_command) + sizeof(struct upiu_response)) / 4;
my->utrd.dw7 = UFSHCI_UTRD_DW7_PRDTO(off);
my->utrd.dw7 |= UFSHCI_UTRD_DW7_PRDTL(1); /* dm_nsegs */
pmap_extract(pmap_kernel(), (vaddr_t)addr, &data_phys);
data_bus_phys = data_phys;
my->ucd.prdt[0].dw0 = (uint32_t)data_bus_phys;
my->ucd.prdt[0].dw1 = (uint32_t)(data_bus_phys >> 32);
my->ucd.prdt[0].dw2 = 0;
my->ucd.prdt[0].dw3 = size - 1; /* ds_len */
if (UFSHCI_READ_4(my->sc, UFSHCI_REG_UTRLRSR) != 1)
return EIO;
ufshci_doorbell_write(my->sc, slot);
/* ufshci_doorbell_poll() adaption for hibernate. */
for (timeout_us = 1000000 * 1000; timeout_us != 0;
timeout_us -= 1000) {
reg = UFSHCI_READ_4(my->sc, UFSHCI_REG_UTRLDBR);
if ((reg & (1U << slot)) == 0)
break;
delay(1000);
}
if (timeout_us == 0)
return EIO;
UFSHCI_WRITE_4(my->sc, UFSHCI_REG_UTRLCNR, (1U << slot));
/* Check if the command was succesfully executed. */
if (my->utrd.dw2 != UFSHCI_UTRD_DW2_OCS_SUCCESS)
return EIO;
return 0;
}
#endif /* HIBERNATE */

View file

@ -1,4 +1,4 @@
/* $OpenBSD: subr_hibernate.c,v 1.140 2024/06/04 20:31:35 krw Exp $ */
/* $OpenBSD: subr_hibernate.c,v 1.141 2024/06/05 11:04:17 krw Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@ -72,6 +72,7 @@ vaddr_t hibernate_rle_page;
/* Hibernate info as read from disk during resume */
union hibernate_info disk_hib;
struct bdevsw *bdsw;
/*
* Global copy of the pig start address. This needs to be a global as we
@ -1004,18 +1005,9 @@ hibernate_block_io(union hibernate_info *hib, daddr_t blkctr,
size_t xfer_size, vaddr_t dest, int iswrite)
{
struct buf *bp;
struct bdevsw *bdsw;
int error;
bp = geteblk(xfer_size);
bdsw = &bdevsw[major(hib->dev)];
error = (*bdsw->d_open)(hib->dev, FREAD, S_IFCHR, curproc);
if (error) {
printf("hibernate_block_io open failed\n");
return (1);
}
if (iswrite)
bcopy((caddr_t)dest, bp->b_data, xfer_size);
@ -1030,26 +1022,13 @@ hibernate_block_io(union hibernate_info *hib, daddr_t blkctr,
if (error) {
printf("hib block_io biowait error %d blk %lld size %zu\n",
error, (long long)blkctr, xfer_size);
error = (*bdsw->d_close)(hib->dev, 0, S_IFCHR,
curproc);
if (error)
printf("hibernate_block_io error close failed\n");
return (1);
}
error = (*bdsw->d_close)(hib->dev, FREAD, S_IFCHR, curproc);
if (error) {
printf("hibernate_block_io close failed\n");
return (1);
}
if (!iswrite)
} else if (!iswrite)
bcopy(bp->b_data, (caddr_t)dest, xfer_size);
bp->b_flags |= B_INVAL;
brelse(bp);
return (0);
return (error != 0);
}
/*
@ -1140,6 +1119,13 @@ hibernate_resume(void)
/* Read hibernate info from disk */
s = splbio();
bdsw = &bdevsw[major(hib->dev)];
if ((*bdsw->d_open)(hib->dev, FREAD, S_IFCHR, curproc)) {
printf("hibernate_resume device open failed\n");
splx(s);
return;
}
DPRINTF("reading hibernate signature block location: %lld\n",
hib->sig_offset);
@ -1147,16 +1133,14 @@ hibernate_resume(void)
hib->sig_offset,
hib->sec_size, (vaddr_t)&disk_hib, 0)) {
DPRINTF("error in hibernate read\n");
splx(s);
return;
goto fail;
}
/* Check magic number */
if (disk_hib.magic != HIBERNATE_MAGIC) {
DPRINTF("wrong magic number in hibernate signature: %x\n",
disk_hib.magic);
splx(s);
return;
goto fail;
}
/*
@ -1165,8 +1149,7 @@ hibernate_resume(void)
*/
if (hibernate_clear_signature(hib)) {
DPRINTF("error clearing hibernate signature block\n");
splx(s);
return;
goto fail;
}
/*
@ -1175,8 +1158,7 @@ hibernate_resume(void)
*/
if (hibernate_compare_signature(hib, &disk_hib)) {
DPRINTF("mismatched hibernate signature block\n");
splx(s);
return;
goto fail;
}
disk_hib.dev = hib->dev;
@ -1189,6 +1171,9 @@ hibernate_resume(void)
/* Read the image from disk into the image (pig) area */
if (hibernate_read_image(&disk_hib))
goto fail;
if ((*bdsw->d_close)(hib->dev, 0, S_IFCHR, curproc))
printf("hibernate_resume device close failed\n");
bdsw = NULL;
DPRINTF("hibernate: quiescing devices\n");
if (config_suspend_all(DVACT_QUIESCE) != 0)
@ -1235,8 +1220,11 @@ hibernate_resume(void)
hibernate_unpack_image(&disk_hib);
fail:
if (!bdsw)
printf("\nUnable to resume hibernated image\n");
else if ((*bdsw->d_close)(hib->dev, 0, S_IFCHR, curproc))
printf("hibernate_resume device close failed\n");
splx(s);
printf("\nUnable to resume hibernated image\n");
}
/*