Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 30 Apr 2026 09:18:12 +0000
From:      Corvi=?utf-8?Q?n K=C3=B6h?=ne <corvink@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 226b37dc3ad5 - main - dev/ichsmb: disable block buffer if supported
Message-ID:  <69f31e54.416a2.7d72e12f@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by corvink:

URL: https://cgit.FreeBSD.org/src/commit/?id=226b37dc3ad5641c18f8542c18baea3ea641c5af

commit 226b37dc3ad5641c18f8542c18baea3ea641c5af
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2026-03-30 09:33:20 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2026-04-30 09:15:18 +0000

    dev/ichsmb: disable block buffer if supported
    
    In order to improve the efficiency of block read/write calls, Intel has
    introduced a block buffer. Instead of generating an interrupt after
    receiving/sending a single byte, the data is buffered in the block buffer. It
    allows the SMBus controller to generate a single interrupt for the whole
    transfer. At the moment, we don't support that and don't expect the SMBus
    controller to behave in that way. Unfortunately, BIOS code can also access the
    SMBus controller and may enable the block buffer. Poorly written BIOS code may
    also keep the block buffer enabled breaking our driver. Therefore, we should
    check if the device supports a block buffer and disable it for every request
    because we don't know if some BIOS code has reconfigured the SMBus controller
    in between.
    
    Reviewed by:            emaste
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Pull Request:           https://github.com/freebsd/freebsd-src/pull/2161
---
 sys/dev/ichsmb/ichsmb.c     | 18 +++++++++++++++
 sys/dev/ichsmb/ichsmb_pci.c | 54 +++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ichsmb/ichsmb_reg.h |  3 +++
 sys/dev/ichsmb/ichsmb_var.h |  3 +++
 4 files changed, 78 insertions(+)

diff --git a/sys/dev/ichsmb/ichsmb.c b/sys/dev/ichsmb/ichsmb.c
index e40a8a8a3886..0df757d9cc0e 100644
--- a/sys/dev/ichsmb/ichsmb.c
+++ b/sys/dev/ichsmb/ichsmb.c
@@ -395,6 +395,15 @@ ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
 	sc->block_write = true;
 
 	mtx_lock(&sc->mutex);
+	/*
+	 * We don't expect the block buffer to be enabled. However, BIOS code
+	 * might enable it and doesn't restore it at any time, so we should
+	 * ensure it's disabled before sending an SMBus command.
+	 */
+	if (sc->features & ICHSMB_FEATURE_BLOCK_BUFFER) {
+		bus_write_1(sc->io_res, ICH_AUX_CNT,
+		    bus_read_1(sc->io_res, ICH_AUX_CNT) & ~ICH_AUX_CNT_E32B);
+	}
 	sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
 	bus_write_1(sc->io_res, ICH_XMIT_SLVA,
 	    slave | ICH_XMIT_SLVA_WRITE);
@@ -424,6 +433,15 @@ ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
 	sc->block_write = false;
 
 	mtx_lock(&sc->mutex);
+	/*
+	 * We don't expect the block buffer to be enabled. However, BIOS code
+	 * might enable it and doesn't restore it at any time, so we should
+	 * ensure it's disabled before sending an SMBus command.
+	 */
+	if (sc->features & ICHSMB_FEATURE_BLOCK_BUFFER) {
+		bus_write_1(sc->io_res, ICH_AUX_CNT,
+		    bus_read_1(sc->io_res, ICH_AUX_CNT) & ~ICH_AUX_CNT_E32B);
+	}
 	sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
 	bus_write_1(sc->io_res, ICH_XMIT_SLVA,
 	    slave | ICH_XMIT_SLVA_READ);
diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c
index 7d6d94dbb4a4..af3e0f004b88 100644
--- a/sys/dev/ichsmb/ichsmb_pci.c
+++ b/sys/dev/ichsmb/ichsmb_pci.c
@@ -129,106 +129,153 @@ static const struct pci_device_table ichsmb_devices[] = {
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801CA),
 	  PCI_DESCR("Intel 82801CA (ICH3) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801DC),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801DC (ICH4) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801EB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801EB (ICH5) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801FB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801FB (ICH6) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801GB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801GB (ICH7) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801H),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801H (ICH8) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801I),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801I (ICH9) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801GB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801GB (ICH7) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801H),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801H (ICH8) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801I),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801I (ICH9) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_EP80579),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel EP80579 SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801JI),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801JI (ICH10) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_82801JD),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 82801JD (ICH10) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_PCH),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel PCH SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_6300ESB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 6300ESB (ICH) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_631xESB),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel 631xESB/6321ESB (ESB2) SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_DH89XXCC),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel DH89xxCC SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_PATSBURG),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Patsburg SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_CPT),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Cougar Point SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_PPT),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Panther Point SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_AVOTON),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Avoton SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_LPT),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Lynx Point SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_LPTLP),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Lynx Point-LP SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_WCPT),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Wildcat Point SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_WCPTLP),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Wildcat Point-LP SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_BAYTRAIL),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Baytrail SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_BRASWELL),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Braswell SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_COLETOCRK),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Coleto Creek SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_WELLSBURG),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Wellsburg SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_SRPT),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Sunrise Point-H SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_SRPTLP),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Sunrise Point-LP SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_DENVERTON),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Denverton SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_BROXTON),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Broxton SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_LEWISBURG),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Lewisburg SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_LEWISBURG2),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Lewisburg SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_KABYLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Kaby Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_CANNONLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Cannon Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_COMETLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Comet Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_COMETLAKE2),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Comet Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_TIGERLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Tiger Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_TIGERLAKE2),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  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),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Gemini Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_CEDARFORK),
 	  PCI_DESCR("Intel Cedar Fork SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_ICELAKE),
 	  PCI_DESCR("Intel Ice Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Alder Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE2),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Alder Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE3),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Alder Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_RAPTORLAKE),
 	  PCI_DESCR("Intel Raptor Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Meteor Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE2),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Meteor Lake SMBus controller") },
 	{ PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE3),
+	  .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER,
 	  PCI_DESCR("Intel Meteor Lake SMBus controller") },
 };
 
@@ -288,6 +335,7 @@ ichsmb_pci_probe(device_t dev)
 static int
 ichsmb_pci_attach(device_t dev)
 {
+	const struct pci_device_table *tbl;
 	const sc_p sc = device_get_softc(dev);
 	int error;
 
@@ -296,6 +344,12 @@ ichsmb_pci_attach(device_t dev)
 	sc->ich_cmd = -1;
 	sc->dev = dev;
 
+	tbl = PCI_MATCH(dev, ichsmb_devices);
+	if (tbl == NULL)
+		return (ENXIO);
+
+	sc->features = (uint32_t)tbl->driver_data;
+
 	/* Allocate an I/O range */
 	sc->io_rid = ICH_SMB_BASE;
 	sc->io_res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT,
diff --git a/sys/dev/ichsmb/ichsmb_reg.h b/sys/dev/ichsmb/ichsmb_reg.h
index 78e398a556ef..be3b9e4a899d 100644
--- a/sys/dev/ichsmb/ichsmb_reg.h
+++ b/sys/dev/ichsmb/ichsmb_reg.h
@@ -84,6 +84,9 @@
 #define ICH_D0				0x05	/* host data 0 */
 #define ICH_D1				0x06	/* host data 1 */
 #define ICH_BLOCK_DB			0x07	/* block data byte */
+#define ICH_AUX_CNT			0x0d	/* auxiliary control */
+#define   ICH_AUX_CNT_E32B		0x02	/*   enable 32 byte buffer */
+#define   ICH_AUX_CNT_AAC		0x01	/*   automatically append crc */
 
 #endif /* _DEV_ICHSMB_ICHSMB_REG_H_ */
 
diff --git a/sys/dev/ichsmb/ichsmb_var.h b/sys/dev/ichsmb/ichsmb_var.h
index 8aeaf403781b..f16a40be9777 100644
--- a/sys/dev/ichsmb/ichsmb_var.h
+++ b/sys/dev/ichsmb/ichsmb_var.h
@@ -41,6 +41,8 @@
 
 #include "smbus_if.h"
 
+#define ICHSMB_FEATURE_BLOCK_BUFFER 0x01	/* supports 32 byte block buffer */
+
 /* Per-device private info */
 struct ichsmb_softc {
 
@@ -52,6 +54,7 @@ struct ichsmb_softc {
 	struct resource		*irq_res;       /* interrupt resource */
 	int			irq_rid;        /* interrupt bus id */
 	void			*irq_handle;    /* handle for interrupt code */
+	uint32_t		features;	/* supported device features */
 
 	/* Device state */
 	int			ich_cmd;	/* ich command, or -1 */


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f31e54.416a2.7d72e12f>