lewisburg map/pcs register handling

Message ID CAF2xp_HuE+aV3ZhrC0E9CQopYgTQ4AHcK15v248AVgxXn8A0pA@mail.gmail.com
State Not Applicable
Delegated to: David Miller
Headers show
Series
  • lewisburg map/pcs register handling
Related show

Commit Message

Peter Chang Nov. 14, 2017, 11:55 p.m.
mostly, intel made the registers wider so that the offsets aren't
right. it only matters if you don't populate all the ports and aren't
using the first port.

\p

Patch

From 62ccc6118960204769809a1ea9d162cf2c1c95e1 Mon Sep 17 00:00:00 2001
From: peter chang <dpf@google.com>
Date: Tue, 14 Nov 2017 13:43:15 -0800
Subject: [PATCH] ahci: lewisburg MAP / PCS register handling

registers are now 32-bits and the existing offsets mean that the
wrong registers are being updated.

Change-Id: I992b31bc9e789f9dfbeb29afeb0b7777e325ea71
---
 drivers/ata/ahci.c    | 34 +++++++++++++++++++++++++++-------
 drivers/ata/ahci.h    |  4 ++++
 drivers/ata/libahci.c | 19 +++++++++++++++++++
 3 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9f78bb03bb76..16b0fac9f0ae 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -71,6 +71,7 @@  enum board_ids {
 
 	/* board IDs for specific chipsets in alphabetical order */
 	board_ahci_avn,
+	board_ahci_lbg,
 	board_ahci_mcp65,
 	board_ahci_mcp77,
 	board_ahci_mcp89,
@@ -174,6 +175,14 @@  static const struct ata_port_info ahci_port_info[] = {
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_avn_ops,
 	},
+	[board_ahci_lbg] = {
+		AHCI_HFLAGS	(AHCI_HFLAG_32BIT_MAP_PCS |
+				 AHCI_HFLAG_PCI_PORT_MAP),
+		.flags		= AHCI_FLAG_COMMON,
+		.pio_mask	= ATA_PIO4,
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &ahci_ops,
+	},
 	[board_ahci_mcp65] = {
 		AHCI_HFLAGS	(AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
 				 AHCI_HFLAG_YES_NCQ),
@@ -374,14 +383,14 @@  static const struct pci_device_id ahci_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
 	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
-	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
+	{ PCI_VDEVICE(INTEL, 0x2823), board_ahci_lbg }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/
-	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
+	{ PCI_VDEVICE(INTEL, 0xa182), board_ahci_lbg }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
-	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
+	{ PCI_VDEVICE(INTEL, 0xa202), board_ahci_lbg }, /* Lewisburg AHCI*/
 	{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
 	{ PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
@@ -630,12 +639,23 @@  static int ahci_pci_reset_controller(struct ata_host *host)
 	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
 		struct ahci_host_priv *hpriv = host->private_data;
 		u16 tmp16;
+		u32 tmp32;
 
 		/* configure PCS */
-		pci_read_config_word(pdev, 0x92, &tmp16);
-		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
-			tmp16 |= hpriv->port_map;
-			pci_write_config_word(pdev, 0x92, tmp16);
+		if (hpriv->flags & AHCI_HFLAG_32BIT_MAP_PCS)
+			pci_read_config_dword(pdev, 0x94, &tmp32);
+		else {
+			pci_read_config_word(pdev, 0x92, &tmp16);
+			tmp32 = tmp16;
+		}
+		if ((tmp32 & hpriv->port_map) != hpriv->port_map) {
+			tmp32 |= hpriv->port_map;
+			if (hpriv->flags & AHCI_HFLAG_32BIT_MAP_PCS)
+				pci_write_config_dword(pdev, 0x94, tmp32);
+			else {
+				tmp16 = tmp32;
+				pci_write_config_word(pdev, 0x92, tmp16);
+			}
 		}
 	}
 
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 8b61123d2c3c..a649107027de 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -251,6 +251,10 @@  enum {
 	AHCI_HFLAG_YES_ALPM		= (1 << 23), /* force ALPM cap on */
 	AHCI_HFLAG_NO_WRITE_TO_RO	= (1 << 24), /* don't write to read
 							only registers */
+        AHCI_HFLAG_32BIT_MAP_PCS	= (1 << 25), /* MAP/PCS register
+                                                        32-bits wide */
+        AHCI_HFLAG_PCI_PORT_MAP		= (1 << 26), /* port map in pci
+                                                        config space */
 
 	/* ap->flags bits */
 
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 3e286d86ab42..e65481d8e362 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -40,6 +40,7 @@ 
 #include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/device.h>
+#include <linux/pci.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
 #include <linux/libata.h>
@@ -523,6 +524,24 @@  void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 		port_map &= hpriv->mask_port_map;
 	}
 
+	if (hpriv->flags & AHCI_HFLAG_PCI_PORT_MAP) {
+		struct pci_dev *pdev = to_pci_dev(dev);
+		u16 disabled;
+
+		if (hpriv->flags & AHCI_HFLAG_32BIT_MAP_PCS) {
+			u32 tmp;
+
+			pci_read_config_dword(pdev, 0x90, &tmp);
+			disabled = (tmp >> 16) & 0xffff;
+		} else {
+			pci_read_config_word(pdev, 0x90, &disabled);
+			disabled = (disabled >> 8) & 0xff;
+		}
+
+		dev_info(dev, "port_map:%x disabled:%x\n", port_map, disabled);
+		port_map &= ~disabled;
+	}
+
 	/* cross check port_map and cap.n_ports */
 	if (port_map) {
 		int map_ports = 0;
-- 
2.15.0.448.gf294e3d99a-goog