acpi: Add support for DRHD size reporting

VT-d spec 4.0 supports size definition for DRHD BAR to support DRHD
sizes larger than 4KB. If the value in the field is N, the size of
the register set is 2^N 4 KB pages.

Some latest OS (e.g. Linux kernel 6.5) will have VTd driver trying
to use the beyond 4KB part of the DRHD BAR if they exist. They need
the DRHD size field to set up page mapping before access those
registers.

Re-add acpi_create_dmar_drhd with a size parameter to support the
needs.

TEST=Build and boot on intel/archercity CRB

Change-Id: I49dd5de2eca257a5f6240e36d05755cabca96d1c
Signed-off-by: Shuo Liu <shuo.liu@intel.com>
Signed-off-by: Gang Chen <gang.c.chen@intel.com>
Signed-off-by: Jincheng Li <jincheng.li@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/82429
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/acpi/acpi_dmar.c b/src/acpi/acpi_dmar.c
index 20a100d..67bca55 100644
--- a/src/acpi/acpi_dmar.c
+++ b/src/acpi/acpi_dmar.c
@@ -2,7 +2,9 @@
 
 #include <acpi/acpi.h>
 #include <arch/ioapic.h>
+#include <assert.h>
 #include <cpu/cpu.h>
+#include <lib.h>
 #include <version.h>
 
 void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
@@ -37,8 +39,23 @@
 }
 
 unsigned long acpi_create_dmar_drhd_4k(unsigned long current, u8 flags,
-	u16 segment, u64 bar)
+				       u16 segment, u64 bar)
 {
+	return acpi_create_dmar_drhd(current, flags, segment, bar, 4 * KiB);
+}
+
+unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
+	u16 segment, u64 bar, size_t size)
+{
+	/*
+	 * Refer to Intel® Virtualization Technology for Directed I/O
+	 * Architecture Specification Revision 4.1,
+	 * size is at least 1 page and max 2^15 pages, 4 KiB each, and the bar
+	 * should be aligned with size.
+	 */
+	assert(4 * KiB <= size && size <= (1 << 15) * 4 * KiB && IS_POWER_OF_2(size));
+	assert(IS_ALIGNED(bar, size));
+
 	dmar_entry_t *drhd = (dmar_entry_t *)current;
 	memset(drhd, 0, sizeof(*drhd));
 	drhd->type = DMAR_DRHD;
@@ -46,6 +63,7 @@
 	drhd->flags = flags;
 	drhd->segment = segment;
 	drhd->bar = bar;
+	drhd->size = log2_64(size) - 12;
 
 	return drhd->length;
 }
diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h
index 469d672..a36e65c 100644
--- a/src/include/acpi/acpi.h
+++ b/src/include/acpi/acpi.h
@@ -638,7 +638,7 @@
 	u16 type;
 	u16 length;
 	u8 flags;
-	u8 reserved;
+	u8 size;
 	u16 segment;
 	u64 bar;
 } __packed dmar_entry_t;
@@ -1851,6 +1851,8 @@
 		      unsigned long (*acpi_fill_dmar)(unsigned long));
 unsigned long acpi_create_dmar_drhd_4k(unsigned long current, u8 flags,
 				    u16 segment, u64 bar);
+unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
+				    u16 segment, u64 bar, size_t size);
 unsigned long acpi_create_dmar_rmrr(unsigned long current, u16 segment,
 				    u64 bar, u64 limit);
 unsigned long acpi_create_dmar_atsr(unsigned long current, u8 flags,