Index: sys/dev/sdmmc/sdmmc_io.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.22
diff -p -u -r1.22 sdmmc_io.c
--- sys/dev/sdmmc/sdmmc_io.c	6 Dec 2025 16:03:39 -0000	1.22
+++ sys/dev/sdmmc/sdmmc_io.c	8 Dec 2025 16:04:08 -0000
@@ -49,6 +49,7 @@ struct sdmmc_intr_handler {
 	int (*ih_fun)(void *);
 	void *ih_arg;
 	TAILQ_ENTRY(sdmmc_intr_handler) entry;
+	struct evcnt ih_ev;
 };
 
 static int	sdmmc_io_rw_direct(struct sdmmc_softc *,
@@ -122,7 +123,11 @@ sdmmc_io_enable(struct sdmmc_softc *sc)
 		goto out;
 	}
 
+	DPRINTF(("%s: host_ocr 0x%08x\n", SDMMCDEVNAME(sc), host_ocr));
+	DPRINTF(("%s: card_ocr 0x%08x\n", SDMMCDEVNAME(sc), card_ocr));
+
 	/* Send the new OCR value until all cards are ready. */
+        host_ocr &= card_ocr; /* only allow the common voltages */
 	error = sdmmc_io_send_op_cond(sc, host_ocr, NULL);
 	if (error) {
 		aprint_error_dev(sc->sc_dev, "couldn't send I/O OCR\n");
@@ -192,6 +197,8 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
 	int error = 0;
 	uint8_t reg;
 
+device_printf(sc->sc_dev, "sdmmc_io_init\n");
+
 	SDMMC_LOCK(sc);
 
 	sf->blklen = sdmmc_chip_host_maxblklen(sc->sc_sct, sc->sc_sch);
@@ -218,6 +225,7 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
 
 		sdmmc_check_cis_quirks(sf);
 
+		sdmmc_print_cis(sf);
 #ifdef SDMMC_DEBUG
 		if (sdmmcdebug)
 			sdmmc_print_cis(sf);
@@ -243,11 +251,15 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
 
 		aprint_normal_dev(sc->sc_dev, "%u-bit width,", sf->width);
 		if ((sc->sc_busclk / 1000) != 0)
-			aprint_normal(" %u.%03u MHz\n",
+			aprint_normal(" %u.%03u MHz",
 			    sc->sc_busclk / 1000, sc->sc_busclk % 1000);
 		else
-			aprint_normal(" %u KHz\n", sc->sc_busclk % 1000);
-
+			aprint_normal(" %u KHz", sc->sc_busclk % 1000);
+		if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+			aprint_normal(", DMA\n");
+		} else {
+			aprint_normal(", PIO\n");
+		}
 
 	} else {
 		reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000);
@@ -348,10 +360,13 @@ sdmmc_io_rw_direct(struct sdmmc_softc *s
 
 	/* Don't lock */
 
+	sc->sc_ev_io.ev_count++;
+	sc->sc_ev_io_register[0].ev_count++;
+
 	/* Make sure the card is selected. */
 	error = sdmmc_select_card(sc, sf);
 	if (error)
-		return error;
+		goto done;
 
 	arg |= ((sf == NULL ? 0 : sf->number) & SD_ARG_CMD52_FUNC_MASK) <<
 	    SD_ARG_CMD52_FUNC_SHIFT;
@@ -378,6 +393,10 @@ sdmmc_io_rw_direct(struct sdmmc_softc *s
 		    ISSET(arg, SD_ARG_CMD52_WRITE) ? "write" : "read");
 	}
 
+done:
+	if (error)
+		sc->sc_ev_io_error.ev_count++;
+
 	return error;
 }
 
@@ -393,15 +412,32 @@ sdmmc_io_rw_extended(struct sdmmc_softc 
     int reg, u_char *datap, int len, int arg)
 {
 	struct sdmmc_command cmd;
-	int error;
+	int error, datalen;
+	u_int counter;
 
 	/* Don't lock */
 
+	datalen = len;
+        if (ISSET(arg, SD_ARG_CMD53_BLOCK_MODE))
+		datalen *= sf->blklen;
+
+	counter = __builtin_ctz(datalen);
+	if (counter < 3) {
+		sc->sc_ev_io.ev_count++;
+		sc->sc_ev_io_register[counter].ev_count++;
+	} else if (counter >= SDMMC_SECTOR_SIZE_SB && counter < SDMMC_SECTOR_SIZE_SB + SDMMC_XFER_SIZES) {
+		sc->sc_ev_xfer.ev_count++;
+		sc->sc_ev_xfer_aligned[counter - SDMMC_SECTOR_SIZE_SB].ev_count++;
+	} else {
+		sc->sc_ev_xfer.ev_count++;
+		sc->sc_ev_xfer_unaligned.ev_count++;
+	}
+
 #if 0
 	/* Make sure the card is selected. */
 	error = sdmmc_select_card(sc, sf);
 	if (error)
-		return error;
+		goto done;
 #endif
 
 	arg |= (((sf == NULL) ? 0 : sf->number) & SD_ARG_CMD53_FUNC_MASK) <<
@@ -414,28 +450,65 @@ sdmmc_io_rw_extended(struct sdmmc_softc 
 	memset(&cmd, 0, sizeof cmd);
 	cmd.c_opcode = SD_IO_RW_EXTENDED;
 	cmd.c_arg = arg;
-	cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R5;
+	cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R5 | SCF_NO_STOP;
 	cmd.c_data = datap;
-	if (ISSET(arg, SD_ARG_CMD53_BLOCK_MODE)) {
-		cmd.c_datalen = len * sf->blklen;
-		cmd.c_blklen = sf->blklen;
-	} else {
-		cmd.c_datalen = len;
-		cmd.c_blklen = MIN(len, sf->blklen);
-	}
+	cmd.c_datalen = datalen;
+	cmd.c_blklen = MIN(datalen, sf->blklen);
 
 	if (!ISSET(arg, SD_ARG_CMD53_WRITE))
 		cmd.c_flags |= SCF_CMD_READ;
 
-	error = sdmmc_mmc_command(sc, &cmd);
+	if (ISSET(sc->sc_caps, SMC_CAPS_DMA) && datalen > 64) {
+		int lflags, preops, postops;
+
+		if (cmd.c_flags & SCF_CMD_READ) {
+			lflags = BUS_DMA_READ;
+			preops = BUS_DMASYNC_PREREAD;
+			postops = BUS_DMASYNC_POSTREAD;
+		} else {
+			lflags = BUS_DMA_WRITE;
+			preops = BUS_DMASYNC_PREWRITE;
+			postops = BUS_DMASYNC_POSTWRITE;
+		}
+
+		error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap,
+		    datap, datalen, NULL, lflags);
+		if (error == 0) {
+			bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap,
+			    0, datalen, preops);
+			cmd.c_dmamap = sc->sc_dmap;
+			error = sdmmc_mmc_command(sc, &cmd);
+			if (error == 0) {
+				bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap,
+				    0, datalen, postops);
+			}
+			bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+		} else {
+			device_printf(sc->sc_dev,"dmamap load error = %d\n",
+			    error);
+			error = sdmmc_mmc_command(sc, &cmd);
+		}
+	} else {
+		error = sdmmc_mmc_command(sc, &cmd);
+	}
 
 	if (error) {
 		device_printf(sc->sc_dev,
 		    "extended I/O error %d, r=%d p=%p l=%d %s\n",
-		    error, reg, datap, len,
+		    error, reg, datap, datalen,
 		    ISSET(arg, SD_ARG_CMD53_WRITE) ? "write" : "read");
 	}
 
+#if 0
+done:
+#endif
+	if (error) {
+		if (counter < 3)
+			sc->sc_ev_io_error.ev_count++;
+		else
+			sc->sc_ev_xfer_error.ev_count++;
+	}
+
 	return error;
 }
 
@@ -510,19 +583,20 @@ int
 sdmmc_io_read_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
     int datalen)
 {
-	int blocks, error = 0;
+	int blocks, bytes, error = 0;
 
 	/* Don't lock */
 
 	while (datalen >= sf->blklen) {
 		blocks = imin(datalen / sf->blklen,
 		              SD_ARG_CMD53_LENGTH_MAX);
+		bytes = blocks * sf->blklen;
 		error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
 		    blocks, SD_ARG_CMD53_READ | SD_ARG_CMD53_BLOCK_MODE);
 		if (error)
 			goto error;
-		data += blocks * sf->blklen;
-		datalen -= blocks * sf->blklen;
+		data += bytes;
+		datalen -= bytes;
 	}
 
 	if (datalen)
@@ -536,19 +610,20 @@ int
 sdmmc_io_write_multi_1(struct sdmmc_function *sf, int reg, u_char *data,
     int datalen)
 {
-	int blocks, error = 0;
+	int blocks, bytes, error = 0;
 
 	/* Don't lock */
 
 	while (datalen >= sf->blklen) {
 		blocks = imin(datalen / sf->blklen,
 		             SD_ARG_CMD53_LENGTH_MAX);
+		bytes = blocks * sf->blklen;
 		error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
 		    blocks, SD_ARG_CMD53_WRITE | SD_ARG_CMD53_BLOCK_MODE);
 		if (error)
 			goto error;
-		data += blocks * sf->blklen;
-		datalen -= blocks * sf->blklen;
+		data += bytes;
+		datalen -= bytes;
 	}
 
 	if (datalen)
@@ -563,21 +638,22 @@ int
 sdmmc_io_read_region_1(struct sdmmc_function *sf, int reg, u_char *data,
     int datalen)
 {
-	int blocks, error = 0;
+	int blocks, bytes, error = 0;
 
 	/* Don't lock */
 
 	while (datalen >= sf->blklen) {
 		blocks = imin(datalen / sf->blklen,
 		              SD_ARG_CMD53_LENGTH_MAX);
+		bytes = blocks * sf->blklen;
 		error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
-		    blocks, SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT |
-		    SD_ARG_CMD53_BLOCK_MODE);
+		    blocks, SD_ARG_CMD53_READ |
+		    SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE);
 		if (error)
 			goto error;
-		reg += blocks * sf->blklen;
-		data += blocks * sf->blklen;
-		datalen -= blocks * sf->blklen;
+		reg += bytes;
+		data += bytes;
+		datalen -= bytes;
 	}
 
 	if (datalen)
@@ -591,21 +667,22 @@ int
 sdmmc_io_write_region_1(struct sdmmc_function *sf, int reg, u_char *data,
     int datalen)
 {
-	int blocks, error = 0;
+	int blocks, bytes, error = 0;
 
 	/* Don't lock */
 
 	while (datalen >= sf->blklen) {
 		blocks = imin(datalen / sf->blklen,
 		              SD_ARG_CMD53_LENGTH_MAX);
+		bytes = blocks * sf->blklen;
 		error = sdmmc_io_rw_extended(sf->sc, sf, reg, data,
-		    blocks, SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT |
-		    SD_ARG_CMD53_BLOCK_MODE);
+		    blocks, SD_ARG_CMD53_WRITE |
+		    SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE);
 		if (error)
 			goto error;
-		reg += blocks * sf->blklen;
-		data += blocks * sf->blklen;
-		datalen -= blocks * sf->blklen;
+		reg += bytes;
+		data += bytes;
+		datalen -= bytes;
 	}
 
 	if (datalen)
@@ -751,11 +828,14 @@ sdmmc_intr_establish(device_t dev, int (
 		free(ih, M_DEVBUF);
 		return NULL;
 	}
-	strlcpy(ih->ih_name, name, strlen(name));
+	strcpy(ih->ih_name, name);
 	ih->ih_softc = sc;
 	ih->ih_fun = fun;
 	ih->ih_arg = arg;
 
+	evcnt_attach_dynamic(&ih->ih_ev, EVCNT_TYPE_MISC,
+            &sc->sc_ev_card_intr, device_xname(dev), ih->ih_name);
+
 	mutex_enter(&sc->sc_mtx);
 	if (TAILQ_EMPTY(&sc->sc_intrq)) {
 		sdmmc_intr_enable(sc->sc_fn0);
@@ -787,6 +867,8 @@ sdmmc_intr_disestablish(void *cookie)
 	}
 	mutex_exit(&sc->sc_mtx);
 
+	evcnt_detach(&ih->ih_ev);
+
 	free(ih->ih_name, M_DEVBUF);
 	free(ih, M_DEVBUF);
 }
@@ -804,6 +886,7 @@ sdmmc_card_intr(device_t dev)
 	if (sc->sc_sct->card_enable_intr == NULL)
 		return;
 
+	sc->sc_ev_card_intr.ev_count++;
 	sdmmc_add_task(sc, &sc->sc_intr_task);
 }
 
@@ -815,8 +898,8 @@ sdmmc_intr_task(void *arg)
 
 	mutex_enter(&sc->sc_mtx);
 	TAILQ_FOREACH(ih, &sc->sc_intrq, entry) {
-		/* XXX examine return value and do evcount stuff*/
-		(void)(*ih->ih_fun)(ih->ih_arg);
+		if ((*ih->ih_fun)(ih->ih_arg))
+			ih->ih_ev.ev_count++;
 	}
 	mutex_exit(&sc->sc_mtx);
 
