Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Jan 2009 22:22:30 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r187348 - head/sys/dev/pci
Message-ID:  <200901162222.n0GMMUs1020195@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Jan 16 22:22:30 2009
New Revision: 187348
URL: http://svn.freebsd.org/changeset/base/187348

Log:
  Disable decoding of BARs by devices before we trash the value in the BAR
  by writing all 1's to it to determine its length.  This fixes issues with
  MCFG on at least some machines where a trashed BAR claimed subsequent
  attempts at PCI config transactions because the addresses in the MCFG
  window fell in the decoding range of the BAR.
  
  In general it is a bad idea to leave the BARs enabled while we are
  frobbing with them in this manner.
  
  Sleuthing by:  tegge
  MFC after:     1 week

Modified:
  head/sys/dev/pci/pci.c

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c	Fri Jan 16 22:16:54 2009	(r187347)
+++ head/sys/dev/pci/pci.c	Fri Jan 16 22:22:30 2009	(r187348)
@@ -2291,9 +2291,27 @@ pci_add_map(device_t pcib, device_t bus,
 	struct resource *res;
 
 	map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
+
+	/*
+	 * Disable decoding via the command register before
+	 * determining the BARs length since we will be placing them
+	 * in a weird state.
+	 */
+	cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2);
+	PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND,
+	    cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2);
+
+	/*
+	 * Determine the BAR's length by writing all 1's.  The bottom
+	 * log_2(size) bits of the BAR will stick as 0 when we read
+	 * the value back.
+	 */
 	PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4);
 	testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
+
+	/* Restore the BAR and command register. */
 	PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4);
+	PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2);
 
 	if (PCI_BAR_MEM(map))
 		type = SYS_RES_MEMORY;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901162222.n0GMMUs1020195>