Commit 02a121da authored by Mark Lord's avatar Mark Lord Committed by Jeff Garzik

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: default avatarMark Lord <mlord@pobox.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 0f9fe9b7
...@@ -168,6 +168,10 @@ enum { ...@@ -168,6 +168,10 @@ enum {
PCI_IRQ_MASK_OFS = 0x1d5c, PCI_IRQ_MASK_OFS = 0x1d5c,
PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */ PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
PCIE_IRQ_CAUSE_OFS = 0x1900,
PCIE_IRQ_MASK_OFS = 0x1910,
PCIE_UNMASK_ALL_IRQS = 0x70a, /* assorted bits */
HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
HC_MAIN_IRQ_MASK_OFS = 0x1d64, HC_MAIN_IRQ_MASK_OFS = 0x1d64,
PORT0_ERR = (1 << 0), /* shift by port # */ PORT0_ERR = (1 << 0), /* shift by port # */
...@@ -303,6 +307,7 @@ enum { ...@@ -303,6 +307,7 @@ enum {
MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */ MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */ MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */ MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
/* Port private flags (pp_flags) */ /* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
...@@ -388,7 +393,15 @@ struct mv_port_signal { ...@@ -388,7 +393,15 @@ struct mv_port_signal {
u32 pre; u32 pre;
}; };
struct mv_host_priv; struct mv_host_priv {
u32 hp_flags;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
u32 irq_cause_ofs;
u32 irq_mask_ofs;
u32 unmask_all_irqs;
};
struct mv_hw_ops { struct mv_hw_ops {
void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio, void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port); unsigned int port);
...@@ -401,12 +414,6 @@ struct mv_hw_ops { ...@@ -401,12 +414,6 @@ struct mv_hw_ops {
void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio); void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
}; };
struct mv_host_priv {
u32 hp_flags;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
};
static void mv_irq_clear(struct ata_port *ap); static void mv_irq_clear(struct ata_port *ap);
static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); 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,11 +638,13 @@ static const struct pci_device_id mv_pci_tbl[] = {
/* Adaptec 1430SA */ /* Adaptec 1430SA */
{ PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 },
{ PCI_VDEVICE(TTI, 0x2310), chip_7042 }, /* Marvell 7042 support */
/* add Marvell 7042 support */
{ PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
/* Highpoint RocketRAID PCIe series */
{ PCI_VDEVICE(TTI, 0x2300), chip_7042 },
{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
{ } /* terminate list */ { } /* terminate list */
}; };
...@@ -1648,13 +1657,14 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) ...@@ -1648,13 +1657,14 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
static void mv_pci_error(struct ata_host *host, void __iomem *mmio) static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
{ {
struct mv_host_priv *hpriv = host->private_data;
struct ata_port *ap; struct ata_port *ap;
struct ata_queued_cmd *qc; struct ata_queued_cmd *qc;
struct ata_eh_info *ehi; struct ata_eh_info *ehi;
unsigned int i, err_mask, printed = 0; unsigned int i, err_mask, printed = 0;
u32 err_cause; u32 err_cause;
err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS); err_cause = readl(mmio + hpriv->irq_cause_ofs);
dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
err_cause); err_cause);
...@@ -1662,7 +1672,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) ...@@ -1662,7 +1672,7 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
DPRINTK("All regs @ PCI error\n"); DPRINTK("All regs @ PCI error\n");
mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); writelfl(0, mmio + hpriv->irq_cause_ofs);
for (i = 0; i < host->n_ports; i++) { for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i]; ap = host->ports[i];
...@@ -1926,6 +1936,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, ...@@ -1926,6 +1936,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
#define ZERO(reg) writel(0, mmio + (reg)) #define ZERO(reg) writel(0, mmio + (reg))
static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
{ {
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct mv_host_priv *hpriv = host->private_data;
u32 tmp; u32 tmp;
tmp = readl(mmio + MV_PCI_MODE); tmp = readl(mmio + MV_PCI_MODE);
...@@ -1937,8 +1949,8 @@ static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio) ...@@ -1937,8 +1949,8 @@ static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
ZERO(HC_MAIN_IRQ_MASK_OFS); ZERO(HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK); ZERO(MV_PCI_SERR_MASK);
ZERO(PCI_IRQ_CAUSE_OFS); ZERO(hpriv->irq_cause_ofs);
ZERO(PCI_IRQ_MASK_OFS); ZERO(hpriv->irq_mask_ofs);
ZERO(MV_PCI_ERR_LOW_ADDRESS); ZERO(MV_PCI_ERR_LOW_ADDRESS);
ZERO(MV_PCI_ERR_HIGH_ADDRESS); ZERO(MV_PCI_ERR_HIGH_ADDRESS);
ZERO(MV_PCI_ERR_ATTRIBUTE); ZERO(MV_PCI_ERR_ATTRIBUTE);
...@@ -2490,6 +2502,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) ...@@ -2490,6 +2502,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break; break;
case chip_7042: case chip_7042:
hp_flags |= MV_HP_PCIE;
case chip_6042: case chip_6042:
hpriv->ops = &mv6xxx_ops; hpriv->ops = &mv6xxx_ops;
hp_flags |= MV_HP_GEN_IIE; hp_flags |= MV_HP_GEN_IIE;
...@@ -2516,6 +2529,15 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) ...@@ -2516,6 +2529,15 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
} }
hpriv->hp_flags = hp_flags; hpriv->hp_flags = hp_flags;
if (hp_flags & MV_HP_PCIE) {
hpriv->irq_cause_ofs = PCIE_IRQ_CAUSE_OFS;
hpriv->irq_mask_ofs = PCIE_IRQ_MASK_OFS;
hpriv->unmask_all_irqs = PCIE_UNMASK_ALL_IRQS;
} else {
hpriv->irq_cause_ofs = PCI_IRQ_CAUSE_OFS;
hpriv->irq_mask_ofs = PCI_IRQ_MASK_OFS;
hpriv->unmask_all_irqs = PCI_UNMASK_ALL_IRQS;
}
return 0; return 0;
} }
...@@ -2595,10 +2617,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) ...@@ -2595,10 +2617,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
} }
/* Clear any currently outstanding host interrupt conditions */ /* Clear any currently outstanding host interrupt conditions */
writelfl(0, mmio + PCI_IRQ_CAUSE_OFS); writelfl(0, mmio + hpriv->irq_cause_ofs);
/* and unmask interrupt generation for host regs */ /* and unmask interrupt generation for host regs */
writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
if (IS_GEN_I(hpriv)) if (IS_GEN_I(hpriv))
writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); 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,8 +2631,8 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
"PCI int cause/mask=0x%08x/0x%08x\n", "PCI int cause/mask=0x%08x/0x%08x\n",
readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
readl(mmio + HC_MAIN_IRQ_MASK_OFS), readl(mmio + HC_MAIN_IRQ_MASK_OFS),
readl(mmio + PCI_IRQ_CAUSE_OFS), readl(mmio + hpriv->irq_cause_ofs),
readl(mmio + PCI_IRQ_MASK_OFS)); readl(mmio + hpriv->irq_mask_ofs));
done: done:
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment