* [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets
@ 2006-11-02 3:17 Tejun Heo
2006-11-02 3:20 ` [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s Tejun Heo
2006-11-07 9:46 ` [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Jeff Garzik
0 siblings, 2 replies; 8+ messages in thread
From: Tejun Heo @ 2006-11-02 3:17 UTC (permalink / raw)
To: Jeff Garzik, robbat2; +Cc: linux-ide
Instead of writing 0xf blindly, preserve the content of write-once
PORTS_IMPL register over host resets.
This patch is taken from Jeff Garzik's AHCI init update patch.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
Protection against 0 PI is added as suggested in the following
message.
http://article.gmane.org/gmane.linux.ide/13365
drivers/ata/ahci.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
Index: work/drivers/ata/ahci.c
===================================================================
--- work.orig/drivers/ata/ahci.c
+++ work/drivers/ata/ahci.c
@@ -389,6 +389,11 @@ static struct pci_driver ahci_pci_driver
};
+static inline int ahci_nr_ports(u32 cap)
+{
+ return (cap & 0x1f) + 1;
+}
+
static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
{
return base + 0x100 + (port * 0x80);
@@ -598,11 +603,12 @@ static int ahci_deinit_port(void __iomem
static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
{
- u32 cap_save, tmp;
+ u32 cap_save, impl_save, tmp;
cap_save = readl(mmio + HOST_CAP);
cap_save &= ( (1<<28) | (1<<17) );
cap_save |= (1 << 27);
+ impl_save = readl(mmio + HOST_PORTS_IMPL);
/* global controller reset */
tmp = readl(mmio + HOST_CTL);
@@ -623,10 +629,21 @@ static int ahci_reset_controller(void __
return -EIO;
}
+ /* turn on AHCI mode */
writel(HOST_AHCI_EN, mmio + HOST_CTL);
(void) readl(mmio + HOST_CTL); /* flush */
+
+ /* These write-once registers are normally cleared on reset.
+ * Restore BIOS values... which we HOPE were present before
+ * reset.
+ */
+ if (!impl_save) {
+ impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
+ }
writel(cap_save, mmio + HOST_CAP);
- writel(0xf, mmio + HOST_PORTS_IMPL);
+ writel(impl_save, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
@@ -1431,7 +1448,7 @@ static int ahci_host_init(struct ata_pro
hpriv->cap = readl(mmio + HOST_CAP);
hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
- probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
+ probe_ent->n_ports = ahci_nr_ports(hpriv->cap);
VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
hpriv->cap, hpriv->port_map, probe_ent->n_ports);
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-02 3:17 [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Tejun Heo
@ 2006-11-02 3:20 ` Tejun Heo
2006-11-06 1:05 ` Robin H. Johnson
2006-11-07 9:46 ` [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Jeff Garzik
1 sibling, 1 reply; 8+ messages in thread
From: Tejun Heo @ 2006-11-02 3:20 UTC (permalink / raw)
To: Jeff Garzik, robbat2; +Cc: linux-ide
Some ICH8s use non-linear port mapping. ahci driver didn't use to
honor PORTS_IMPL and this made ports after hole nonfunctional. This
patch makes ahci mark those ports as dummy and properly initialize all
the implemented ports after the dummies.
As it's unknown whether other AHCIs implement PORTS_IMPL register
properly, new board id board_ahci_pi is added and selectively applied
to ICH8s. All other AHCIs continue to use linear mapping regardless
of PORTS_IMPL value.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Robin H. Johnson <robbat2@gentoo.org>
---
Updated to mark unimplemented ports as dummies. Tested on ICH7
(consecutive mapping) and ICH8 (inconsecutive mapping). Error paths
are tested too.
Thanks.
drivers/ata/ahci.c | 71 +++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 55 insertions(+), 16 deletions(-)
Index: work/drivers/ata/ahci.c
===================================================================
--- work.orig/drivers/ata/ahci.c
+++ work/drivers/ata/ahci.c
@@ -53,6 +53,7 @@
enum {
AHCI_PCI_BAR = 5,
+ AHCI_MAX_PORTS = 32,
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_USE_CLUSTERING = 0,
@@ -77,7 +78,8 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_vt8251 = 1,
+ board_ahci_pi = 1,
+ board_ahci_vt8251 = 2,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -166,6 +168,7 @@ enum {
AHCI_FLAG_MSI = (1 << 0),
/* ap->flags bits */
+ AHCI_FLAG_HONOR_PI = (1 << 23), /* honor PORTS_IMPL */
AHCI_FLAG_NO_NCQ = (1 << 24),
};
@@ -315,6 +318,16 @@ static const struct ata_port_info ahci_p
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
+ /* board_ahci_pi */
+ {
+ .sht = &ahci_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
/* board_ahci_vt8251 */
{
.sht = &ahci_sht,
@@ -340,11 +353,11 @@ static const struct pci_device_id ahci_p
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
/* JMicron */
{ PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
@@ -659,7 +672,8 @@ static int ahci_reset_controller(void __
}
static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
- int n_ports, u32 cap)
+ int n_ports, unsigned int port_flags,
+ struct ahci_host_priv *hpriv)
{
int i, rc;
u32 tmp;
@@ -668,13 +682,12 @@ static void ahci_init_controller(void __
void __iomem *port_mmio = ahci_port_base(mmio, i);
const char *emsg = NULL;
-#if 0 /* BIOSen initialize this incorrectly */
- if (!(hpriv->port_map & (1 << i)))
+ if ((port_flags & AHCI_FLAG_HONOR_PI) &&
+ !(hpriv->port_map & (1 << i)))
continue;
-#endif
/* make sure port is not active */
- rc = ahci_deinit_port(port_mmio, cap, &emsg);
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
if (rc)
dev_printk(KERN_WARNING, &pdev->dev,
"%s (%d)\n", emsg, rc);
@@ -1327,7 +1340,8 @@ static int ahci_pci_device_resume(struct
if (rc)
return rc;
- ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
+ ahci_init_controller(mmio, pdev, host->n_ports,
+ host->ports[0]->flags, hpriv);
}
ata_host_resume(host);
@@ -1439,7 +1453,7 @@ static int ahci_host_init(struct ata_pro
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
void __iomem *mmio = probe_ent->mmio_base;
- unsigned int i, using_dac;
+ unsigned int i, cap_n_ports, using_dac;
int rc;
rc = ahci_reset_controller(mmio, pdev);
@@ -1448,10 +1462,34 @@ static int ahci_host_init(struct ata_pro
hpriv->cap = readl(mmio + HOST_CAP);
hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
- probe_ent->n_ports = ahci_nr_ports(hpriv->cap);
+ cap_n_ports = ahci_nr_ports(hpriv->cap);
VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
- hpriv->cap, hpriv->port_map, probe_ent->n_ports);
+ hpriv->cap, hpriv->port_map, n_ports);
+
+ if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
+ unsigned int n_ports = cap_n_ports;
+ u32 port_map = hpriv->port_map;
+ int max_port = 0;
+
+ for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+ if (port_map & (1 << i)) {
+ n_ports--;
+ port_map &= ~(1 << i);
+ max_port = i;
+ } else
+ probe_ent->dummy_port_mask |= 1 << i;
+ }
+
+ if (n_ports || port_map)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "nr_ports (%u) and implemented port map "
+ "(0x%x) don't match\n",
+ cap_n_ports, hpriv->port_map);
+
+ probe_ent->n_ports = max_port + 1;
+ } else
+ probe_ent->n_ports = cap_n_ports;
using_dac = hpriv->cap & HOST_CAP_64;
if (using_dac &&
@@ -1483,7 +1521,8 @@ static int ahci_host_init(struct ata_pro
for (i = 0; i < probe_ent->n_ports; i++)
ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
- ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
+ ahci_init_controller(mmio, pdev, probe_ent->n_ports,
+ probe_ent->port_flags, hpriv);
pci_set_master(pdev);
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-02 3:20 ` [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s Tejun Heo
@ 2006-11-06 1:05 ` Robin H. Johnson
2006-11-07 9:54 ` Tejun Heo
2006-11-09 6:08 ` Tejun Heo
0 siblings, 2 replies; 8+ messages in thread
From: Robin H. Johnson @ 2006-11-06 1:05 UTC (permalink / raw)
To: Tejun Heo; +Cc: Jeff Garzik, robbat2, linux-ide
[-- Attachment #1: Type: text/plain, Size: 1095 bytes --]
On Thu, Nov 02, 2006 at 12:20:59PM +0900, Tejun Heo wrote:
> @@ -1439,7 +1453,7 @@ static int ahci_host_init(struct ata_pro
> struct ahci_host_priv *hpriv = probe_ent->private_data;
> struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
> void __iomem *mmio = probe_ent->mmio_base;
> - unsigned int i, using_dac;
> + unsigned int i, cap_n_ports, using_dac;
> int rc;
>
> rc = ahci_reset_controller(mmio, pdev);
> @@ -1448,10 +1462,34 @@ static int ahci_host_init(struct ata_pro
>
> hpriv->cap = readl(mmio + HOST_CAP);
> hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
> - probe_ent->n_ports = ahci_nr_ports(hpriv->cap);
> + cap_n_ports = ahci_nr_ports(hpriv->cap);
>
> VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
> - hpriv->cap, hpriv->port_map, probe_ent->n_ports);
> + hpriv->cap, hpriv->port_map, n_ports);
n_ports is undefined here. Should be cap_n_ports instead.
Other than that, the two patches work perfectly.
--
Robin Hugh Johnson
E-Mail : robbat2@gentoo.org
GnuPG FP : 11AC BA4F 4778 E3F6 E4ED F38E B27B 944E 3488 4E85
[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets
2006-11-02 3:17 [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Tejun Heo
2006-11-02 3:20 ` [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s Tejun Heo
@ 2006-11-07 9:46 ` Jeff Garzik
1 sibling, 0 replies; 8+ messages in thread
From: Jeff Garzik @ 2006-11-07 9:46 UTC (permalink / raw)
To: Tejun Heo; +Cc: robbat2, linux-ide
Tejun Heo wrote:
> Instead of writing 0xf blindly, preserve the content of write-once
> PORTS_IMPL register over host resets.
>
> This patch is taken from Jeff Garzik's AHCI init update patch.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
applied
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-06 1:05 ` Robin H. Johnson
@ 2006-11-07 9:54 ` Tejun Heo
2006-11-09 6:08 ` Tejun Heo
1 sibling, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-11-07 9:54 UTC (permalink / raw)
To: Robin H. Johnson; +Cc: Jeff Garzik, linux-ide
Robin H. Johnson wrote:
> On Thu, Nov 02, 2006 at 12:20:59PM +0900, Tejun Heo wrote:
>> @@ -1439,7 +1453,7 @@ static int ahci_host_init(struct ata_pro
>> struct ahci_host_priv *hpriv = probe_ent->private_data;
>> struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
>> void __iomem *mmio = probe_ent->mmio_base;
>> - unsigned int i, using_dac;
>> + unsigned int i, cap_n_ports, using_dac;
>> int rc;
>>
>> rc = ahci_reset_controller(mmio, pdev);
>> @@ -1448,10 +1462,34 @@ static int ahci_host_init(struct ata_pro
>>
>> hpriv->cap = readl(mmio + HOST_CAP);
>> hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
>> - probe_ent->n_ports = ahci_nr_ports(hpriv->cap);
>> + cap_n_ports = ahci_nr_ports(hpriv->cap);
>>
>> VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
>> - hpriv->cap, hpriv->port_map, probe_ent->n_ports);
>> + hpriv->cap, hpriv->port_map, n_ports);
> n_ports is undefined here. Should be cap_n_ports instead.
>
> Other than that, the two patches work perfectly.
Thanks. Forgot to drop that part again. I'll post updated patch in a
few hours.
--
tejun
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-06 1:05 ` Robin H. Johnson
2006-11-07 9:54 ` Tejun Heo
@ 2006-11-09 6:08 ` Tejun Heo
2006-11-11 2:37 ` Tejun Heo
2006-11-14 18:45 ` Jeff Garzik
1 sibling, 2 replies; 8+ messages in thread
From: Tejun Heo @ 2006-11-09 6:08 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Robin H. Johnson, linux-ide
Some ICH8s use non-linear port mapping. ahci driver didn't use to
honor PORTS_IMPL and this made ports after hole nonfunctional. This
patch makes ahci mark those ports as dummy and properly initialize all
the implemented ports after the dummies.
As it's unknown whether other AHCIs implement PORTS_IMPL register
properly, new board id board_ahci_pi is added and selectively applied
to ICH8s. All other AHCIs continue to use linear mapping regardless
of PORTS_IMPL value.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Robin H. Johnson <robbat2@gentoo.org>
---
Two changes.
* AHCI_FLAG_HONOR_PI was changed to 1<<25. 1<<23 is not for LLD
specific flags.
* VPRINTK() fixed as Robin H. Johnson pointed out.
Please apply. Thanks.
drivers/ata/ahci.c | 71 ++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index f24d197..b05e22f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -53,6 +53,7 @@
enum {
AHCI_PCI_BAR = 5,
+ AHCI_MAX_PORTS = 32,
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
AHCI_USE_CLUSTERING = 0,
@@ -77,7 +78,8 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_vt8251 = 1,
+ board_ahci_pi = 1,
+ board_ahci_vt8251 = 2,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -167,6 +169,7 @@ enum {
/* ap->flags bits */
AHCI_FLAG_NO_NCQ = (1 << 24),
+ AHCI_FLAG_HONOR_PI = (1 << 25), /* honor PORTS_IMPL */
};
struct ahci_cmd_hdr {
@@ -315,6 +318,16 @@ static const struct ata_port_info ahci_p
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
+ /* board_ahci_pi */
+ {
+ .sht = &ahci_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
/* board_ahci_vt8251 */
{
.sht = &ahci_sht,
@@ -340,11 +353,11 @@ static const struct pci_device_id ahci_p
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
/* JMicron */
{ PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
@@ -667,7 +680,8 @@ static int ahci_reset_controller(void __
}
static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
- int n_ports, u32 cap)
+ int n_ports, unsigned int port_flags,
+ struct ahci_host_priv *hpriv)
{
int i, rc;
u32 tmp;
@@ -676,13 +690,12 @@ static void ahci_init_controller(void __
void __iomem *port_mmio = ahci_port_base(mmio, i);
const char *emsg = NULL;
-#if 0 /* BIOSen initialize this incorrectly */
- if (!(hpriv->port_map & (1 << i)))
+ if ((port_flags & AHCI_FLAG_HONOR_PI) &&
+ !(hpriv->port_map & (1 << i)))
continue;
-#endif
/* make sure port is not active */
- rc = ahci_deinit_port(port_mmio, cap, &emsg);
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
if (rc)
dev_printk(KERN_WARNING, &pdev->dev,
"%s (%d)\n", emsg, rc);
@@ -1335,7 +1348,8 @@ static int ahci_pci_device_resume(struct
if (rc)
return rc;
- ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
+ ahci_init_controller(mmio, pdev, host->n_ports,
+ host->ports[0]->flags, hpriv);
}
ata_host_resume(host);
@@ -1447,7 +1461,7 @@ static int ahci_host_init(struct ata_pro
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
void __iomem *mmio = probe_ent->mmio_base;
- unsigned int i, using_dac;
+ unsigned int i, cap_n_ports, using_dac;
int rc;
rc = ahci_reset_controller(mmio, pdev);
@@ -1456,10 +1470,34 @@ static int ahci_host_init(struct ata_pro
hpriv->cap = readl(mmio + HOST_CAP);
hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
- probe_ent->n_ports = ahci_nr_ports(hpriv->cap);
+ cap_n_ports = ahci_nr_ports(hpriv->cap);
VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
- hpriv->cap, hpriv->port_map, probe_ent->n_ports);
+ hpriv->cap, hpriv->port_map, cap_n_ports);
+
+ if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
+ unsigned int n_ports = cap_n_ports;
+ u32 port_map = hpriv->port_map;
+ int max_port = 0;
+
+ for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+ if (port_map & (1 << i)) {
+ n_ports--;
+ port_map &= ~(1 << i);
+ max_port = i;
+ } else
+ probe_ent->dummy_port_mask |= 1 << i;
+ }
+
+ if (n_ports || port_map)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "nr_ports (%u) and implemented port map "
+ "(0x%x) don't match\n",
+ cap_n_ports, hpriv->port_map);
+
+ probe_ent->n_ports = max_port + 1;
+ } else
+ probe_ent->n_ports = cap_n_ports;
using_dac = hpriv->cap & HOST_CAP_64;
if (using_dac &&
@@ -1491,7 +1529,8 @@ static int ahci_host_init(struct ata_pro
for (i = 0; i < probe_ent->n_ports; i++)
ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
- ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
+ ahci_init_controller(mmio, pdev, probe_ent->n_ports,
+ probe_ent->port_flags, hpriv);
pci_set_master(pdev);
--
1.4.3.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-09 6:08 ` Tejun Heo
@ 2006-11-11 2:37 ` Tejun Heo
2006-11-14 18:45 ` Jeff Garzik
1 sibling, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-11-11 2:37 UTC (permalink / raw)
To: Tejun Heo; +Cc: Jeff Garzik, Robin H. Johnson, linux-ide
Tejun Heo wrote:
> Some ICH8s use non-linear port mapping. ahci driver didn't use to
> honor PORTS_IMPL and this made ports after hole nonfunctional. This
> patch makes ahci mark those ports as dummy and properly initialize all
> the implemented ports after the dummies.
>
> As it's unknown whether other AHCIs implement PORTS_IMPL register
> properly, new board id board_ahci_pi is added and selectively applied
> to ICH8s. All other AHCIs continue to use linear mapping regardless
> of PORTS_IMPL value.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> Cc: Robin H. Johnson <robbat2@gentoo.org>
> ---
>
> Two changes.
>
> * AHCI_FLAG_HONOR_PI was changed to 1<<25. 1<<23 is not for LLD
> specific flags.
>
> * VPRINTK() fixed as Robin H. Johnson pointed out.
Jeff, I think this should go into #upstream-fixes too. It's not as dumb
as adding a PCI ID but it's adding support for a highly popular hardware
and "wait for 2.6.20 for ICH8 support" just sucks.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s
2006-11-09 6:08 ` Tejun Heo
2006-11-11 2:37 ` Tejun Heo
@ 2006-11-14 18:45 ` Jeff Garzik
1 sibling, 0 replies; 8+ messages in thread
From: Jeff Garzik @ 2006-11-14 18:45 UTC (permalink / raw)
To: Tejun Heo; +Cc: Robin H. Johnson, linux-ide
Tejun Heo wrote:
> Some ICH8s use non-linear port mapping. ahci driver didn't use to
> honor PORTS_IMPL and this made ports after hole nonfunctional. This
> patch makes ahci mark those ports as dummy and properly initialize all
> the implemented ports after the dummies.
>
> As it's unknown whether other AHCIs implement PORTS_IMPL register
> properly, new board id board_ahci_pi is added and selectively applied
> to ICH8s. All other AHCIs continue to use linear mapping regardless
> of PORTS_IMPL value.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> Cc: Robin H. Johnson <robbat2@gentoo.org>
> ---
>
> Two changes.
>
> * AHCI_FLAG_HONOR_PI was changed to 1<<25. 1<<23 is not for LLD
> specific flags.
>
> * VPRINTK() fixed as Robin H. Johnson pointed out.
applied
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2006-11-14 18:46 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-02 3:17 [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Tejun Heo
2006-11-02 3:20 ` [PATCH 2/2 #upstream] ahci: honor PORTS_IMPL on ICH8s Tejun Heo
2006-11-06 1:05 ` Robin H. Johnson
2006-11-07 9:54 ` Tejun Heo
2006-11-09 6:08 ` Tejun Heo
2006-11-11 2:37 ` Tejun Heo
2006-11-14 18:45 ` Jeff Garzik
2006-11-07 9:46 ` [PATCH 1/2 #upstream] ahci: preserve PORTS_IMPL over host resets Jeff Garzik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).