sync with OpenBSD -current
This commit is contained in:
parent
2d7157972b
commit
6040ea8924
17 changed files with 989 additions and 255 deletions
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue