[Skiboot] [PATCH v2 07/23] phb4: Mask out write-1-to-clear registers in RC cfg

Michael Neuling mikey at neuling.org
Sun Jun 25 05:17:12 AEST 2017


From: Russell Currey <ruscur at russell.cc>

The root complex config space only supports 4-byte accesses. Thus, when
the client requests a smaller size write, we do a read-modify-write to
the register.

However, some register have bits defined as "write 1 to clear".

If we do a RMW cycles on such a register and such bits are 1 in the
part that the client doesn't intend to modify, we will accidentally
write back those 1's and clear the corresponding bit.

This avoids it by masking out those magic bits from the "old" value
read from the register.

Signed-off-by: Russell Currey <ruscur at russell.cc>
Signed-off-by: Michael Neuling <mikey at neuling.org>
---
 hw/phb4.c | 44 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 39 insertions(+), 5 deletions(-)

diff --git a/hw/phb4.c b/hw/phb4.c
index 3ee618e3a8..7e8ba3b07c 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -264,20 +264,54 @@ static int64_t phb4_rc_write(struct phb4 *p, uint32_t offset, uint8_t sz,
 			     uint32_t val)
 {
 	uint32_t reg = offset & ~3;
-	uint32_t old, mask, shift;
+	uint32_t old, mask, shift, oldold;
 	int64_t rc;
 
 	if (reg > PHB_RC_CONFIG_SIZE)
 		return OPAL_SUCCESS;
 
-	/* If size isn't 4-bytes, do a RMW cycle
-	 *
-	 * XXX TODO: Filter out registers that do write-1-to-clear !!!
-	 */
+	/* If size isn't 4-bytes, do a RMW cycle */
 	if (sz < 4) {
 		rc = phb4_rc_read(p, reg, 4, &old);
 		if (rc != OPAL_SUCCESS)
 			return rc;
+
+		/*
+		 * Since we have to Read-Modify-Write here, we need to filter
+		 * out registers that have write-1-to-clear bits to prevent
+		 * clearing stuff we shouldn't be.  So for any register this
+		 * applies to, mask out those bits.
+		 */
+		oldold = old;
+		switch(reg) {
+		case 0x1C: /* Secondary status */
+			old &= 0x00ffffff; /* mask out 24-31 */
+			break;
+		case 0x50: /* EC - Device status */
+			old &= 0xfff0ffff; /* mask out 16-19 */
+			break;
+		case 0x58: /* EC - Link status */
+			old &= 0x3fffffff; /* mask out 30-31 */
+			break;
+		case 0x78: /* EC - Link status 2 */
+			old &= 0xf000ffff; /* mask out 16-27 */
+			break;
+		/* These registers *only* have write-1-to-clear bits */
+		case 0x104: /* AER - Uncorr. error status */
+		case 0x110: /* AER - Corr. error status */
+		case 0x130: /* AER - Root error status */
+		case 0x180: /* P16 - status */
+		case 0x184: /* P16 - LDPM status */
+		case 0x188: /* P16 - FRDPM status */
+		case 0x18C: /* P16 - SRDPM status */
+			old &= 0x00000000;
+			break;
+		}
+
+		if (old != oldold)
+			PHBDBG(p, "Rewrote %x to %x for reg %x for W1C\n",
+			       oldold, old, reg);
+
 		if (sz == 1) {
 			shift = (offset & 3) << 3;
 			mask = 0xff << shift;
-- 
2.11.0



More information about the Skiboot mailing list