diff options
author | Mark Lord <liml@rtr.ca> | 2007-12-01 13:07:22 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-12-01 17:44:10 -0500 |
commit | 02a121da5a53d415b6596bc19cc6999d295d32a4 (patch) | |
tree | 4016dd755dcbb1339bc3d742b1e8bdf1cd14991c /drivers/ata | |
parent | 0f9fe9b7148f95f018ae2c97f7fa1a35364ea785 (diff) |
sata_mv: Fix broken Marvell 7042 support.
sata_mv: Fix broken Marvell 7042 support.
The Marvell 7042 chip is more or less the same as the 6042 internally,
but sports a PCIe bus. Despite having identical SATA cores, the 7042
does differ from its PCI bus counterparts in placment and layout of
certain bus related registers.
This patch fixes sata_mv to distinguish between the PCI bus registers
of earlier chips, and the PCIe bus registers of the 7042.
Specifically, move the offsets and bit patterns for the
PCI/PCIe interrupt cause/mask registers into the struct mv_host_priv,
as these values differ between the 6xxx and 7xxx series chips.
This fixes the driver to not access reserved PCI addresses,
and prevents the lockups reported in linux-2.6.24 with 7042 boards.
Also add a new PCI ID for the Highpoint 2300 7042-based board
that I'm using for testing this stuff here.
Tested with Marvell 6081 + 7042 chips, on x86 & x86_64.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/sata_mv.c | 62 |
1 files changed, 42 insertions, 20 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 97c3e116977e..8d864e5e97ed 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -164,10 +164,14 @@ enum { | |||
164 | MV_PCI_ERR_ATTRIBUTE = 0x1d48, | 164 | MV_PCI_ERR_ATTRIBUTE = 0x1d48, |
165 | MV_PCI_ERR_COMMAND = 0x1d50, | 165 | MV_PCI_ERR_COMMAND = 0x1d50, |
166 | 166 | ||
167 | PCI_IRQ_CAUSE_OFS = 0x1d58, | 167 | PCI_IRQ_CAUSE_OFS = 0x1d58, |
168 | PCI_IRQ_MASK_OFS = 0x1d5c, | 168 | PCI_IRQ_MASK_OFS = 0x1d5c, |
169 | PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */ | 169 | PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */ |
170 | 170 | ||
171 | PCIE_IRQ_CAUSE_OFS = 0x1900, | ||
172 | PCIE_IRQ_MASK_OFS = 0x1910, | ||
173 | PCIE_UNMASK_ALL_IRQS = 0x70a, /* assorted bits */ | ||
174 | |||
171 | HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, | 175 | HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, |
172 | HC_MAIN_IRQ_MASK_OFS = 0x1d64, | 176 | HC_MAIN_IRQ_MASK_OFS = 0x1d64, |
173 | PORT0_ERR = (1 << 0), /* shift by port # */ | 177 | PORT0_ERR = (1 << 0), /* shift by port # */ |
@@ -303,6 +307,7 @@ enum { | |||
303 | MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */ | 307 | MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */ |
304 | MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */ | 308 | MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */ |
305 | MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */ | 309 | MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */ |
310 | MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */ | ||
306 | 311 | ||
307 | /* Port private flags (pp_flags) */ | 312 | /* Port private flags (pp_flags) */ |
308 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ | 313 | MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ |
@@ -388,7 +393,15 @@ struct mv_port_signal { | |||
388 | u32 pre; | 393 | u32 pre; |
389 | }; | 394 | }; |
390 | 395 | ||
391 | struct mv_host_priv; | 396 | struct mv_host_priv { |
397 | u32 hp_flags; | ||
398 | struct mv_port_signal signal[8]; | ||
399 | const struct mv_hw_ops *ops; | ||
400 | u32 irq_cause_ofs; | ||
401 | u32 irq_mask_ofs; | ||
402 | u32 unmask_all_irqs; | ||
403 | }; | ||
404 | |||
392 | struct mv_hw_ops { | 405 | struct mv_hw_ops { |
393 | void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio, | 406 | void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio, |
394 | unsigned int port); | 407 | unsigned int port); |
@@ -401,12 +414,6 @@ struct mv_hw_ops { | |||
401 | void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); | 414 | void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); |
402 | }; | 415 | }; |
403 | 416 | ||
404 | struct mv_host_priv { | ||
405 | u32 hp_flags; | ||
406 | struct mv_port_signal signal[8]; | ||
407 | const struct mv_hw_ops *ops; | ||
408 | }; | ||
409 | |||
410 | static void mv_irq_clear(struct ata_port *ap); | 417 | static void mv_irq_clear(struct ata_port *ap); |
411 | static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); | 418 | static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); |
412 | static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); | 419 | static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); |
@@ -631,11 +638,13 @@ static const struct pci_device_id mv_pci_tbl[] = { | |||
631 | /* Adaptec 1430SA */ | 638 | /* Adaptec 1430SA */ |
632 | { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, | 639 | { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, |
633 | 640 | ||
634 | { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, | 641 | /* Marvell 7042 support */ |
635 | |||
636 | /* add Marvell 7042 support */ | ||
637 | { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, | 642 | { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, |
638 | 643 | ||
644 | /* Highpoint RocketRAID PCIe series */ | ||
645 | { PCI_VDEVICE(TTI, 0x2300), chip_7042 }, | ||
646 | { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, | ||
647 | |||
639 | { } /* terminate list */ | 648 | { } /* terminate list */ |
640 | }; | 649 | }; |
641 | 650 | ||
@@ -1648,13 +1657,14 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) | |||
1648 | 1657 | ||
1649 | static void mv_pci_error(struct ata_host *host, void __iomem *mmio) | 1658 | static void mv_pci_error(struct ata_host *host, void __iomem *mmio) |
1650 | { | 1659 | { |
1660 | struct mv_host_priv *hpriv = host->private_data; | ||
1651 | struct ata_port *ap; | 1661 | struct ata_port *ap; |
1652 | struct ata_queued_cmd *qc; | 1662 | struct ata_queued_cmd *qc; |
1653 | struct ata_eh_info *ehi; | 1663 | struct ata_eh_info *ehi; |
1654 | unsigned int i, err_mask, printed = 0; | 1664 | unsigned int i, err_mask, printed = 0; |
1655 | u32 err_cause; | 1665 | u32 err_cause; |
1656 | 1666 | ||
1657 | err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS); | 1667 | err_cause = readl(mmio + hpriv->irq_cause_ofs); |
1658 | 1668 | ||
1659 | dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", | 1669 | dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", |
1660 | err_cause); | 1670 | err_cause); |
@@ -1662,7 +1672,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) | |||
1662 | DPRINTK("All regs @ PCI error\n"); | 1672 | DPRINTK("All regs @ PCI error\n"); |
1663 | mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); | 1673 | mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); |
1664 | 1674 | ||
1665 | writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); | 1675 | writelfl(0, mmio + hpriv->irq_cause_ofs); |
1666 | 1676 | ||
1667 | for (i = 0; i < host->n_ports; i++) { | 1677 | for (i = 0; i < host->n_ports; i++) { |
1668 | ap = host->ports[i]; | 1678 | ap = host->ports[i]; |
@@ -1926,6 +1936,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, | |||
1926 | #define ZERO(reg) writel(0, mmio + (reg)) | 1936 | #define ZERO(reg) writel(0, mmio + (reg)) |
1927 | static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) | 1937 | static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) |
1928 | { | 1938 | { |
1939 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | ||
1940 | struct mv_host_priv *hpriv = host->private_data; | ||
1929 | u32 tmp; | 1941 | u32 tmp; |
1930 | 1942 | ||
1931 | tmp = readl(mmio + MV_PCI_MODE); | 1943 | tmp = readl(mmio + MV_PCI_MODE); |
@@ -1937,8 +1949,8 @@ static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) | |||
1937 | writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); | 1949 | writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); |
1938 | ZERO(HC_MAIN_IRQ_MASK_OFS); | 1950 | ZERO(HC_MAIN_IRQ_MASK_OFS); |
1939 | ZERO(MV_PCI_SERR_MASK); | 1951 | ZERO(MV_PCI_SERR_MASK); |
1940 | ZERO(PCI_IRQ_CAUSE_OFS); | 1952 | ZERO(hpriv->irq_cause_ofs); |
1941 | ZERO(PCI_IRQ_MASK_OFS); | 1953 | ZERO(hpriv->irq_mask_ofs); |
1942 | ZERO(MV_PCI_ERR_LOW_ADDRESS); | 1954 | ZERO(MV_PCI_ERR_LOW_ADDRESS); |
1943 | ZERO(MV_PCI_ERR_HIGH_ADDRESS); | 1955 | ZERO(MV_PCI_ERR_HIGH_ADDRESS); |
1944 | ZERO(MV_PCI_ERR_ATTRIBUTE); | 1956 | ZERO(MV_PCI_ERR_ATTRIBUTE); |
@@ -2490,6 +2502,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) | |||
2490 | break; | 2502 | break; |
2491 | 2503 | ||
2492 | case chip_7042: | 2504 | case chip_7042: |
2505 | hp_flags |= MV_HP_PCIE; | ||
2493 | case chip_6042: | 2506 | case chip_6042: |
2494 | hpriv->ops = &mv6xxx_ops; | 2507 | hpriv->ops = &mv6xxx_ops; |
2495 | hp_flags |= MV_HP_GEN_IIE; | 2508 | hp_flags |= MV_HP_GEN_IIE; |
@@ -2516,6 +2529,15 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) | |||
2516 | } | 2529 | } |
2517 | 2530 | ||
2518 | hpriv->hp_flags = hp_flags; | 2531 | hpriv->hp_flags = hp_flags; |
2532 | if (hp_flags & MV_HP_PCIE) { | ||
2533 | hpriv->irq_cause_ofs = PCIE_IRQ_CAUSE_OFS; | ||
2534 | hpriv->irq_mask_ofs = PCIE_IRQ_MASK_OFS; | ||
2535 | hpriv->unmask_all_irqs = PCIE_UNMASK_ALL_IRQS; | ||
2536 | } else { | ||
2537 | hpriv->irq_cause_ofs = PCI_IRQ_CAUSE_OFS; | ||
2538 | hpriv->irq_mask_ofs = PCI_IRQ_MASK_OFS; | ||
2539 | hpriv->unmask_all_irqs = PCI_UNMASK_ALL_IRQS; | ||
2540 | } | ||
2519 | 2541 | ||
2520 | return 0; | 2542 | return 0; |
2521 | } | 2543 | } |
@@ -2595,10 +2617,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) | |||
2595 | } | 2617 | } |
2596 | 2618 | ||
2597 | /* Clear any currently outstanding host interrupt conditions */ | 2619 | /* Clear any currently outstanding host interrupt conditions */ |
2598 | writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); | 2620 | writelfl(0, mmio + hpriv->irq_cause_ofs); |
2599 | 2621 | ||
2600 | /* and unmask interrupt generation for host regs */ | 2622 | /* and unmask interrupt generation for host regs */ |
2601 | writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); | 2623 | writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); |
2602 | 2624 | ||
2603 | if (IS_GEN_I(hpriv)) | 2625 | if (IS_GEN_I(hpriv)) |
2604 | writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); | 2626 | writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); |
@@ -2609,8 +2631,8 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) | |||
2609 | "PCI int cause/mask=0x%08x/0x%08x\n", | 2631 | "PCI int cause/mask=0x%08x/0x%08x\n", |
2610 | readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), | 2632 | readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), |
2611 | readl(mmio + HC_MAIN_IRQ_MASK_OFS), | 2633 | readl(mmio + HC_MAIN_IRQ_MASK_OFS), |
2612 | readl(mmio + PCI_IRQ_CAUSE_OFS), | 2634 | readl(mmio + hpriv->irq_cause_ofs), |
2613 | readl(mmio + PCI_IRQ_MASK_OFS)); | 2635 | readl(mmio + hpriv->irq_mask_ofs)); |
2614 | 2636 | ||
2615 | done: | 2637 | done: |
2616 | return rc; | 2638 | return rc; |