aboutsummaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorAlexander Duyck2012-09-15 04:08:39 +0000
committerJeff Kirsher2012-11-15 05:20:01 -0800
commit07bd34db29e56be78297e973fd16e8f32ecd0a43 (patch)
tree486c1174e0612af0aff858b36ce048622b59410a /drivers/dma
parent702ed3c1a9dfe4dfe112f13542d0c9d689f5008b (diff)
ioat: Do not enable DCA if tag map is invalid
I have encountered several systems that have an invalid tag map. This invalid tag map results in only two tags being generated 0x1F which is usually applied to the first core in a Hyper-threaded pair and 0x00 which is applied to the second core in a Hyper-threaded pair. The net result of all this is that DCA causes significant cache thrash because the 0x1F tag will send traffic to the second socket, which the 0x00 tag will not DCA tag the frame resulting in no benefit. For now the best solution from the driver's perspective is to just disable DCA if the tag map is invalid. The correct solution for this would be to have the BIOS on affected systems updated so that the correct tags are generated for a given APIC ID. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Tested-by: Stephen Ko <stephen.s.ko@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/ioat/dca.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c
index abd9038e06b1..d6668071bd0d 100644
--- a/drivers/dma/ioat/dca.c
+++ b/drivers/dma/ioat/dca.c
@@ -604,6 +604,23 @@ static int ioat3_dca_count_dca_slots(void *iobase, u16 dca_offset)
return slots;
}
+static inline int dca3_tag_map_invalid(u8 *tag_map)
+{
+ /*
+ * If the tag map is not programmed by the BIOS the default is:
+ * 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x00
+ *
+ * This an invalid map and will result in only 2 possible tags
+ * 0x1F and 0x00. 0x00 is an invalid DCA tag so we know that
+ * this entire definition is invalid.
+ */
+ return ((tag_map[0] == DCA_TAG_MAP_VALID) &&
+ (tag_map[1] == DCA_TAG_MAP_VALID) &&
+ (tag_map[2] == DCA_TAG_MAP_VALID) &&
+ (tag_map[3] == DCA_TAG_MAP_VALID) &&
+ (tag_map[4] == DCA_TAG_MAP_VALID));
+}
+
struct dca_provider * __devinit
ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
{
@@ -674,6 +691,12 @@ ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
ioatdca->tag_map[i] = bit & DCA_TAG_MAP_MASK;
}
+ if (dca3_tag_map_invalid(ioatdca->tag_map)) {
+ dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n");
+ free_dca_provider(dca);
+ return NULL;
+ }
+
err = register_dca_provider(dca, &pdev->dev);
if (err) {
free_dca_provider(dca);