svn commit: r362574 - head/sys/dev/uart

Marcin Wojtas mw at FreeBSD.org
Wed Jun 24 12:15:28 UTC 2020


Author: mw
Date: Wed Jun 24 12:15:27 2020
New Revision: 362574
URL: https://svnweb.freebsd.org/changeset/base/362574

Log:
  Fix AccessWidth and BitWidth parsing in SPCR table
  
  The ACPI Specification defines a Generic Address Structure (GAS),
  which is used to describe UART controller register layout in the
  SPCR table. The driver responsible for parsing it (uart_cpu_acpi)
  wrongly associates the Access Size field to the uart_bas's regshft
  and the register BitWidth to the regiowidth - according to
  the definitions it should be opposite.
  
  This problem remained hidden most likely because the majority of platforms
  use 32-bit registers (BitWidth) which are accessed with the according
  size (Dword). However on Marvell Armada 8k / Cn913x platforms,
  the 32-bit registers should be accessed with Byte granulity, which
  unveiled the issue.
  
  This patch fixes above by proper values assignment and slightly improved
  parsing.
  
  Note that handling of the AccessWidth set to EFI_ACPI_6_0_UNDEFINED is
  needed to work around a buggy SPCR table on EC2 x86 "bare metal" instances.
  
  Reviewed by: manu, imp, cperciva, greg_unrelenting.technology
  Obtained from: Semihalf
  MFC after: 2 weeks
  Differential Revision: https://reviews.freebsd.org/D25373

Modified:
  head/sys/dev/uart/uart_cpu_acpi.c

Modified: head/sys/dev/uart/uart_cpu_acpi.c
==============================================================================
--- head/sys/dev/uart/uart_cpu_acpi.c	Wed Jun 24 07:25:54 2020	(r362573)
+++ head/sys/dev/uart/uart_cpu_acpi.c	Wed Jun 24 12:15:27 2020	(r362574)
@@ -120,11 +120,46 @@ uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *d
 		    (int)spcr->SerialPort.SpaceId);
 		goto out;
 	}
-	if (spcr->SerialPort.AccessWidth == 0)
+	switch (spcr->SerialPort.AccessWidth) {
+	case 0: /* EFI_ACPI_6_0_UNDEFINED */
+		/* FALLTHROUGH */
+	case 1: /* EFI_ACPI_6_0_BYTE */
+		di->bas.regiowidth = 1;
+		break;
+	case 2: /* EFI_ACPI_6_0_WORD */
+		di->bas.regiowidth = 2;
+		break;
+	case 3: /* EFI_ACPI_6_0_DWORD */
+		di->bas.regiowidth = 4;
+		break;
+	case 4: /* EFI_ACPI_6_0_QWORD */
+		di->bas.regiowidth = 8;
+		break;
+	default:
+		printf("UART unsupported access width: %d!\n",
+		    (int)spcr->SerialPort.AccessWidth);
+		goto out;
+	}
+	switch (spcr->SerialPort.BitWidth) {
+	case 0:
+		/* FALLTHROUGH */
+	case 8:
 		di->bas.regshft = 0;
-	else
-		di->bas.regshft = spcr->SerialPort.AccessWidth - 1;
-	di->bas.regiowidth = spcr->SerialPort.BitWidth / 8;
+		break;
+	case 16:
+		di->bas.regshft = 1;
+		break;
+	case 32:
+		di->bas.regshft = 2;
+		break;
+	case 64:
+		di->bas.regshft = 3;
+		break;
+	default:
+		printf("UART unsupported bit width: %d!\n",
+		    (int)spcr->SerialPort.BitWidth);
+		goto out;
+	}
 	switch (spcr->BaudRate) {
 	case 0:
 		/* Special value; means "keep current value unchanged". */


More information about the svn-src-head mailing list