diff options
Diffstat (limited to 'drivers/ata/sata_mv.c')
| -rw-r--r-- | drivers/ata/sata_mv.c | 535 |
1 files changed, 281 insertions, 254 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 35c6b6d09c27..ffb396f61731 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sata_mv.c - Marvell SATA support * @@ -9,20 +10,6 @@ * Extensive overhaul and enhancement by Mark Lord <mlord@pobox.com>. * * Please ALWAYS copy linux-ide@vger.kernel.org on emails. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* @@ -60,6 +47,7 @@ #include <linux/dma-mapping.h> #include <linux/device.h> #include <linux/clk.h> +#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/ata_platform.h> #include <linux/mbus.h> @@ -304,6 +292,12 @@ enum { MV5_LTMODE = 0x30, MV5_PHY_CTL = 0x0C, SATA_IFCFG = 0x050, + LP_PHY_CTL = 0x058, + LP_PHY_CTL_PIN_PU_PLL = (1 << 0), + LP_PHY_CTL_PIN_PU_RX = (1 << 1), + LP_PHY_CTL_PIN_PU_TX = (1 << 2), + LP_PHY_CTL_GEN_TX_3G = (1 << 5), + LP_PHY_CTL_GEN_RX_3G = (1 << 9), MV_M2_PREAMP_MASK = 0x7e0, @@ -431,6 +425,7 @@ enum { MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */ + MV_HP_FIX_LP_PHY_CTL = (1 << 13), /* fix speed in LP_PHY_CTL ? */ /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ @@ -553,10 +548,21 @@ struct mv_host_priv { u32 irq_mask_offset; u32 unmask_all_irqs; -#if defined(CONFIG_HAVE_CLK) + /* + * Needed on some devices that require their clocks to be enabled. + * These are optional: if the platform device does not have any + * clocks, they won't be used. Also, if the underlying hardware + * does not support the common clock framework (CONFIG_HAVE_CLK=n), + * all the clock operations become no-ops (see clk.h). + */ struct clk *clk; struct clk **port_clks; -#endif + /* + * Some devices have a SATA PHY which can be enabled/disabled + * in order to save power. These are optional: if the platform + * devices does not have any phy, they won't be used. + */ + struct phy **port_phys; /* * These consistent DMA memory pools give us guaranteed * alignment for hardware-accessed data structures, @@ -573,7 +579,7 @@ struct mv_hw_ops { void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio); void (*read_preamp)(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); - int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio, + int (*reset_hc)(struct ata_host *host, void __iomem *mmio, unsigned int n_hc); void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio); void (*reset_bus)(struct ata_host *host, void __iomem *mmio); @@ -586,8 +592,8 @@ static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) static int mv_port_start(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap); static int mv_qc_defer(struct ata_queued_cmd *qc); -static void mv_qc_prep(struct ata_queued_cmd *qc); -static void mv_qc_prep_iie(struct ata_queued_cmd *qc); +static enum ata_completion_errors mv_qc_prep(struct ata_queued_cmd *qc); +static enum ata_completion_errors mv_qc_prep_iie(struct ata_queued_cmd *qc); static unsigned int mv_qc_issue(struct ata_queued_cmd *qc); static int mv_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); @@ -600,7 +606,7 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); -static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, +static int mv5_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc); static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio); @@ -610,14 +616,14 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); -static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, +static int mv6_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc); static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv_soc_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio); static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx, void __iomem *mmio); -static int mv_soc_reset_hc(struct mv_host_priv *hpriv, +static int mv_soc_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc); static void mv_soc_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); @@ -653,17 +659,21 @@ static u8 mv_sff_check_status(struct ata_port *ap); * PRDs for 64K boundaries in mv_fill_sg(). */ #ifdef CONFIG_PCI -static struct scsi_host_template mv5_sht = { +static const struct scsi_host_template mv5_sht = { ATA_BASE_SHT(DRV_NAME), .sg_tablesize = MV_MAX_SG_CT / 2, .dma_boundary = MV_DMA_BOUNDARY, }; #endif -static struct scsi_host_template mv6_sht = { - ATA_NCQ_SHT(DRV_NAME), +static const struct scsi_host_template mv6_sht = { + __ATA_BASE_SHT(DRV_NAME), .can_queue = MV_MAX_Q_DEPTH - 1, .sg_tablesize = MV_MAX_SG_CT / 2, .dma_boundary = MV_DMA_BOUNDARY, + .sdev_groups = ata_ncq_sdev_groups, + .change_queue_depth = ata_scsi_change_queue_depth, + .tag_alloc_policy_rr = true, + .sdev_configure = ata_scsi_sdev_configure }; static struct ata_port_operations mv5_ops = { @@ -677,7 +687,7 @@ static struct ata_port_operations mv5_ops = { .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, - .hardreset = mv_hardreset, + .reset.hardreset = mv_hardreset, .scr_read = mv5_scr_read, .scr_write = mv5_scr_write, @@ -699,10 +709,10 @@ static struct ata_port_operations mv6_ops = { .freeze = mv_eh_freeze, .thaw = mv_eh_thaw, - .hardreset = mv_hardreset, - .softreset = mv_softreset, - .pmp_hardreset = mv_pmp_hardreset, - .pmp_softreset = mv_softreset, + .reset.hardreset = mv_hardreset, + .reset.softreset = mv_softreset, + .pmp_reset.hardreset = mv_pmp_hardreset, + .pmp_reset.softreset = mv_softreset, .error_handler = mv_pmp_error_handler, .scr_read = mv_scr_read, @@ -777,37 +787,6 @@ static const struct ata_port_info mv_port_info[] = { }, }; -static const struct pci_device_id mv_pci_tbl[] = { - { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, - { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, - { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, - { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, - /* RocketRAID 1720/174x have different identifiers */ - { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, - { PCI_VDEVICE(TTI, 0x1740), chip_6042 }, - { PCI_VDEVICE(TTI, 0x1742), chip_6042 }, - - { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, - { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, - { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, - { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, - { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, - - { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, - - /* Adaptec 1430SA */ - { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, - - /* Marvell 7042 support */ - { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, - - /* Highpoint RocketRAID PCIe series */ - { PCI_VDEVICE(TTI, 0x2300), chip_7042 }, - { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, - - { } /* terminate list */ -}; - static const struct mv_hw_ops mv5xxx_ops = { .phy_errata = mv5_phy_errata, .enable_leds = mv5_enable_leds, @@ -967,7 +946,7 @@ static inline void mv_write_cached_reg(void __iomem *addr, u32 *old, u32 new) * Looks like a lot of fuss, but it avoids an unnecessary * +1 usec read-after-write delay for unaffected registers. */ - laddr = (long)addr & 0xffff; + laddr = (unsigned long)addr & 0xffff; if (laddr >= 0x300 && laddr <= 0x33c) { laddr &= 0x000f; if (laddr == 0x4 || laddr == 0xc) { @@ -1140,9 +1119,8 @@ static void mv_set_irq_coalescing(struct ata_host *host, spin_unlock_irqrestore(&host->lock, flags); } -/** +/* * mv_start_edma - Enable eDMA engine - * @base: port base address * @pp: port private data * * Verify the local cache of the eDMA state is accurate with a @@ -1239,81 +1217,74 @@ static int mv_stop_edma(struct ata_port *ap) return err; } -#ifdef ATA_DEBUG -static void mv_dump_mem(void __iomem *start, unsigned bytes) +static void mv_dump_mem(struct device *dev, void __iomem *start, unsigned bytes) { - int b, w; + int b, w, o; + unsigned char linebuf[38]; + for (b = 0; b < bytes; ) { - DPRINTK("%p: ", start + b); - for (w = 0; b < bytes && w < 4; w++) { - printk("%08x ", readl(start + b)); + for (w = 0, o = 0; b < bytes && w < 4; w++) { + o += scnprintf(linebuf + o, sizeof(linebuf) - o, + "%08x ", readl(start + b)); b += sizeof(u32); } - printk("\n"); + dev_dbg(dev, "%s: %p: %s\n", + __func__, start + b, linebuf); } } -#endif -#if defined(ATA_DEBUG) || defined(CONFIG_PCI) + static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes) { -#ifdef ATA_DEBUG - int b, w; - u32 dw; + int b, w, o; + u32 dw = 0; + unsigned char linebuf[38]; + for (b = 0; b < bytes; ) { - DPRINTK("%02x: ", b); - for (w = 0; b < bytes && w < 4; w++) { + for (w = 0, o = 0; b < bytes && w < 4; w++) { (void) pci_read_config_dword(pdev, b, &dw); - printk("%08x ", dw); + o += snprintf(linebuf + o, sizeof(linebuf) - o, + "%08x ", dw); b += sizeof(u32); } - printk("\n"); + dev_dbg(&pdev->dev, "%s: %02x: %s\n", + __func__, b, linebuf); } -#endif } -#endif -static void mv_dump_all_regs(void __iomem *mmio_base, int port, + +static void mv_dump_all_regs(void __iomem *mmio_base, struct pci_dev *pdev) { -#ifdef ATA_DEBUG - void __iomem *hc_base = mv_hc_base(mmio_base, - port >> MV_PORT_HC_SHIFT); + void __iomem *hc_base; void __iomem *port_base; int start_port, num_ports, p, start_hc, num_hcs, hc; - if (0 > port) { - start_hc = start_port = 0; - num_ports = 8; /* shld be benign for 4 port devs */ - num_hcs = 2; - } else { - start_hc = port >> MV_PORT_HC_SHIFT; - start_port = port; - num_ports = num_hcs = 1; - } - DPRINTK("All registers for port(s) %u-%u:\n", start_port, - num_ports > 1 ? num_ports - 1 : start_port); + start_hc = start_port = 0; + num_ports = 8; /* should be benign for 4 port devs */ + num_hcs = 2; + dev_dbg(&pdev->dev, + "%s: All registers for port(s) %u-%u:\n", __func__, + start_port, num_ports > 1 ? num_ports - 1 : start_port); - if (NULL != pdev) { - DPRINTK("PCI config space regs:\n"); - mv_dump_pci_cfg(pdev, 0x68); - } - DPRINTK("PCI regs:\n"); - mv_dump_mem(mmio_base+0xc00, 0x3c); - mv_dump_mem(mmio_base+0xd00, 0x34); - mv_dump_mem(mmio_base+0xf00, 0x4); - mv_dump_mem(mmio_base+0x1d00, 0x6c); + dev_dbg(&pdev->dev, "%s: PCI config space regs:\n", __func__); + mv_dump_pci_cfg(pdev, 0x68); + + dev_dbg(&pdev->dev, "%s: PCI regs:\n", __func__); + mv_dump_mem(&pdev->dev, mmio_base+0xc00, 0x3c); + mv_dump_mem(&pdev->dev, mmio_base+0xd00, 0x34); + mv_dump_mem(&pdev->dev, mmio_base+0xf00, 0x4); + mv_dump_mem(&pdev->dev, mmio_base+0x1d00, 0x6c); for (hc = start_hc; hc < start_hc + num_hcs; hc++) { hc_base = mv_hc_base(mmio_base, hc); - DPRINTK("HC regs (HC %i):\n", hc); - mv_dump_mem(hc_base, 0x1c); + dev_dbg(&pdev->dev, "%s: HC regs (HC %i):\n", __func__, hc); + mv_dump_mem(&pdev->dev, hc_base, 0x1c); } for (p = start_port; p < start_port + num_ports; p++) { port_base = mv_port_base(mmio_base, p); - DPRINTK("EDMA regs (port %i):\n", p); - mv_dump_mem(port_base, 0x54); - DPRINTK("SATA regs (port %i):\n", p); - mv_dump_mem(port_base+0x300, 0x60); + dev_dbg(&pdev->dev, "%s: EDMA regs (port %i):\n", __func__, p); + mv_dump_mem(&pdev->dev, port_base, 0x54); + dev_dbg(&pdev->dev, "%s: SATA regs (port %i):\n", __func__, p); + mv_dump_mem(&pdev->dev, port_base+0x300, 0x60); } -#endif } static unsigned int mv_scr_offset(unsigned int sc_reg_in) @@ -1353,6 +1324,7 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) if (ofs != 0xffffffffU) { void __iomem *addr = mv_ap_base(link->ap) + ofs; + struct mv_host_priv *hpriv = link->ap->host->private_data; if (sc_reg_in == SCR_CONTROL) { /* * Workaround for 88SX60x1 FEr SATA#26: @@ -1369,6 +1341,25 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) */ if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1) val |= 0xf000; + + if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) { + void __iomem *lp_phy_addr = + mv_ap_base(link->ap) + LP_PHY_CTL; + /* + * Set PHY speed according to SControl speed. + */ + u32 lp_phy_val = + LP_PHY_CTL_PIN_PU_PLL | + LP_PHY_CTL_PIN_PU_RX | + LP_PHY_CTL_PIN_PU_TX; + + if ((val & 0xf0) != 0x10) + lp_phy_val |= + LP_PHY_CTL_GEN_TX_3G | + LP_PHY_CTL_GEN_RX_3G; + + writelfl(lp_phy_val, lp_phy_addr); + } } writelfl(val, addr); return 0; @@ -1493,7 +1484,7 @@ static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq) writel(new, hpriv->base + GPIO_PORT_CTL); } -/** +/* * mv_bmdma_enable - set a magic bit on GEN_IIE to allow bmdma * @ap: Port being initialized * @@ -1688,15 +1679,13 @@ static int mv_port_start(struct ata_port *ap) return -ENOMEM; ap->private_data = pp; - pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma); + pp->crqb = dma_pool_zalloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma); if (!pp->crqb) return -ENOMEM; - memset(pp->crqb, 0, MV_CRQB_Q_SZ); - pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma); + pp->crpb = dma_pool_zalloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma); if (!pp->crpb) goto out_port_free_dma_mem; - memset(pp->crpb, 0, MV_CRPB_Q_SZ); /* 6041/6081 Rev. "C0" (and newer) are okay with async notify */ if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0) @@ -1765,7 +1754,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) struct mv_sg *mv_sg, *last_sg = NULL; unsigned int si; - mv_sg = pp->sg_tbl[qc->tag]; + mv_sg = pp->sg_tbl[qc->hw_tag]; for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); @@ -1866,9 +1855,9 @@ static void mv_bmdma_setup(struct ata_queued_cmd *qc) writel(0, port_mmio + BMDMA_CMD); /* load PRD table addr. */ - writel((pp->sg_tbl_dma[qc->tag] >> 16) >> 16, + writel((pp->sg_tbl_dma[qc->hw_tag] >> 16) >> 16, port_mmio + BMDMA_PRD_HIGH); - writelfl(pp->sg_tbl_dma[qc->tag], + writelfl(pp->sg_tbl_dma[qc->hw_tag], port_mmio + BMDMA_PRD_LOW); /* issue r/w command */ @@ -1894,8 +1883,8 @@ static void mv_bmdma_start(struct ata_queued_cmd *qc) } /** - * mv_bmdma_stop - Stop BMDMA transfer - * @qc: queued command to stop DMA on. + * mv_bmdma_stop_ap - Stop BMDMA transfer + * @ap: port to stop * * Clears the ATA_DMA_START flag in the bmdma control register * @@ -1986,7 +1975,7 @@ static void mv_rw_multi_errata_sata24(struct ata_queued_cmd *qc) break; case ATA_CMD_WRITE_MULTI_FUA_EXT: tf->flags &= ~ATA_TFLAG_FUA; /* ugh */ - /* fall through */ + fallthrough; case ATA_CMD_WRITE_MULTI_EXT: tf->command = ATA_CMD_PIO_WRITE_EXT; break; @@ -2007,7 +1996,7 @@ static void mv_rw_multi_errata_sata24(struct ata_queued_cmd *qc) * LOCKING: * Inherited from caller. */ -static void mv_qc_prep(struct ata_queued_cmd *qc) +static enum ata_completion_errors mv_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mv_port_priv *pp = ap->private_data; @@ -2019,32 +2008,32 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) switch (tf->protocol) { case ATA_PROT_DMA: if (tf->command == ATA_CMD_DSM) - return; - /* fall-thru */ + return AC_ERR_OK; + fallthrough; case ATA_PROT_NCQ: break; /* continue below */ case ATA_PROT_PIO: mv_rw_multi_errata_sata24(qc); - return; + return AC_ERR_OK; default: - return; + return AC_ERR_OK; } /* Fill in command request block */ if (!(tf->flags & ATA_TFLAG_WRITE)) flags |= CRQB_FLAG_READ; - WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); - flags |= qc->tag << CRQB_TAG_SHIFT; + WARN_ON(MV_MAX_Q_DEPTH <= qc->hw_tag); + flags |= qc->hw_tag << CRQB_TAG_SHIFT; flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT; /* get current queue index from software */ in_index = pp->req_idx; pp->crqb[in_index].sg_addr = - cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff); + cpu_to_le32(pp->sg_tbl_dma[qc->hw_tag] & 0xffffffff); pp->crqb[in_index].sg_addr_hi = - cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16); + cpu_to_le32((pp->sg_tbl_dma[qc->hw_tag] >> 16) >> 16); pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags); cw = &pp->crqb[in_index].ata_cmd[0]; @@ -2074,12 +2063,10 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none * of which are defined/used by Linux. If we get here, this * driver needs work. - * - * FIXME: modify libata to give qc_prep a return value and - * return error here. */ - BUG_ON(tf->command); - break; + ata_port_err(ap, "%s: unsupported command: %.2x\n", __func__, + tf->command); + return AC_ERR_INVALID; } mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0); mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0); @@ -2092,8 +2079,10 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */ if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; + return AC_ERR_OK; mv_fill_sg(qc); + + return AC_ERR_OK; } /** @@ -2108,7 +2097,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) * LOCKING: * Inherited from caller. */ -static void mv_qc_prep_iie(struct ata_queued_cmd *qc) +static enum ata_completion_errors mv_qc_prep_iie(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct mv_port_priv *pp = ap->private_data; @@ -2119,25 +2108,25 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) if ((tf->protocol != ATA_PROT_DMA) && (tf->protocol != ATA_PROT_NCQ)) - return; + return AC_ERR_OK; if (tf->command == ATA_CMD_DSM) - return; /* use bmdma for this */ + return AC_ERR_OK; /* use bmdma for this */ /* Fill in Gen IIE command request block */ if (!(tf->flags & ATA_TFLAG_WRITE)) flags |= CRQB_FLAG_READ; - WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); - flags |= qc->tag << CRQB_TAG_SHIFT; - flags |= qc->tag << CRQB_HOSTQ_SHIFT; + WARN_ON(MV_MAX_Q_DEPTH <= qc->hw_tag); + flags |= qc->hw_tag << CRQB_TAG_SHIFT; + flags |= qc->hw_tag << CRQB_HOSTQ_SHIFT; flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT; /* get current queue index from software */ in_index = pp->req_idx; crqb = (struct mv_crqb_iie *) &pp->crqb[in_index]; - crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff); - crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16); + crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->hw_tag] & 0xffffffff); + crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->hw_tag] >> 16) >> 16); crqb->flags = cpu_to_le32(flags); crqb->ata_cmd[0] = cpu_to_le32( @@ -2162,8 +2151,10 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) ); if (!(qc->flags & ATA_QCFLAG_DMAMAP)) - return; + return AC_ERR_OK; mv_fill_sg(qc); + + return AC_ERR_OK; } /** @@ -2195,6 +2186,7 @@ static u8 mv_sff_check_status(struct ata_port *ap) /** * mv_send_fis - Send a FIS, using the "Vendor-Unique FIS" register + * @ap: ATA port to send a FIS * @fis: fis to be sent * @nwords: number of 32-bit words in the fis */ @@ -2270,7 +2262,7 @@ static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATAPI_PROT_PIO: pp->pp_flags |= MV_PP_FLAG_FAKE_ATA_BUSY; - /* fall through */ + fallthrough; case ATAPI_PROT_NODATA: ap->hsm_task_state = HSM_ST_FIRST; break; @@ -2321,7 +2313,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) return AC_ERR_OTHER; break; /* use bmdma for this */ } - /* fall thru */ + fallthrough; case ATA_PROT_NCQ: mv_start_edma(ap, port_mmio, pp, qc->tf.protocol); pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK; @@ -2350,7 +2342,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) ": attempting PIO w/multiple DRQ: " "this may fail due to h/w errata\n"); } - /* drop through */ + fallthrough; case ATA_PROT_NODATA: case ATAPI_PROT_PIO: case ATAPI_PROT_NODATA: @@ -2441,20 +2433,18 @@ static unsigned int mv_get_err_pmp_map(struct ata_port *ap) static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map) { - struct ata_eh_info *ehi; unsigned int pmp; /* * Initialize EH info for PMPs which saw device errors */ - ehi = &ap->link.eh_info; for (pmp = 0; pmp_map != 0; pmp++) { unsigned int this_pmp = (1 << pmp); if (pmp_map & this_pmp) { struct ata_link *link = &ap->pmp_link[pmp]; + struct ata_eh_info *ehi = &link->eh_info; pmp_map &= ~this_pmp; - ehi = &link->eh_info; ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "dev err"); ehi->err_mask |= AC_ERR_DEV; @@ -2504,7 +2494,7 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) failed_links = hweight16(new_map); ata_port_info(ap, - "%s: pmp_map=%04x qc_map=%04x failed_links=%d nr_active_links=%d\n", + "%s: pmp_map=%04x qc_map=%04llx failed_links=%d nr_active_links=%d\n", __func__, pp->delayed_eh_pmp_map, ap->qc_active, failed_links, ap->nr_active_links); @@ -2805,7 +2795,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp } if (work_done) { - ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask); + ata_qc_complete_multiple(ap, ata_qc_get_active(ap) ^ done_mask); /* Update the software queue position index in hardware */ writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | @@ -2934,8 +2924,8 @@ static int mv_pci_error(struct ata_host *host, void __iomem *mmio) dev_err(host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n", err_cause); - DPRINTK("All regs @ PCI error\n"); - mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev)); + dev_dbg(host->dev, "%s: All regs @ PCI error\n", __func__); + mv_dump_all_regs(mmio, to_pci_dev(host->dev)); writelfl(0, mmio + hpriv->irq_cause_offset); @@ -3173,9 +3163,10 @@ static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio, } #undef ZERO -static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, +static int mv5_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc) { + struct mv_host_priv *hpriv = host->private_data; unsigned int hc, port; for (hc = 0; hc < n_hc; hc++) { @@ -3225,7 +3216,7 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) writel(tmp, mmio + GPIO_PORT_CTL); } -/** +/* * mv6_reset_hc - Perform the 6xxx global soft reset * @mmio: base address of the HBA * @@ -3234,7 +3225,7 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio) * LOCKING: * Inherited from caller. */ -static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, +static int mv6_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc) { void __iomem *reg = mmio + PCI_MAIN_CMD_STS; @@ -3254,7 +3245,7 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, break; } if (!(PCI_MASTER_EMPTY & t)) { - printk(KERN_ERR DRV_NAME ": PCI master won't flush\n"); + dev_err(host->dev, "PCI master won't flush\n"); rc = 1; goto done; } @@ -3268,7 +3259,7 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, } while (!(GLOB_SFT_RST & t) && (i-- > 0)); if (!(GLOB_SFT_RST & t)) { - printk(KERN_ERR DRV_NAME ": can't set global reset\n"); + dev_err(host->dev, "can't set global reset\n"); rc = 1; goto done; } @@ -3282,7 +3273,7 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, } while ((GLOB_SFT_RST & t) && (i-- > 0)); if (GLOB_SFT_RST & t) { - printk(KERN_ERR DRV_NAME ": can't clear global reset\n"); + dev_err(host->dev, "can't clear global reset\n"); rc = 1; } done: @@ -3451,9 +3442,10 @@ static void mv_soc_reset_one_hc(struct mv_host_priv *hpriv, #undef ZERO -static int mv_soc_reset_hc(struct mv_host_priv *hpriv, +static int mv_soc_reset_hc(struct ata_host *host, void __iomem *mmio, unsigned int n_hc) { + struct mv_host_priv *hpriv = host->private_data; unsigned int port; for (port = 0; port < hpriv->n_ports; port++) @@ -3506,7 +3498,7 @@ static void mv_soc_65n_phy_errata(struct mv_host_priv *hpriv, writel(reg, port_mmio + PHY_MODE9_GEN1); } -/** +/* * soc_is_65 - check if the soc is 65 nano device * * Detect the type of the SoC, this is done by reading the PHYCFG_OFS @@ -3561,7 +3553,7 @@ static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio, hpriv->ops->phy_errata(hpriv, mmio, port_no); if (IS_GEN_I(hpriv)) - mdelay(1); + usleep_range(500, 1000); } static void mv_pmp_select(struct ata_port *ap, int pmp) @@ -3610,7 +3602,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class, /* Workaround for errata FEr SATA#10 (part 2) */ do { - const unsigned long *timing = + const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context); rc = sata_link_hardreset(link, timing, deadline + extra, @@ -3695,11 +3687,6 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) /* unmask all non-transient EDMA error interrupts */ writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK); - - VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", - readl(port_mmio + EDMA_CFG), - readl(port_mmio + EDMA_ERR_IRQ_CAUSE), - readl(port_mmio + EDMA_ERR_IRQ_MASK)); } static unsigned int mv_in_pcix_mode(struct ata_host *host) @@ -3831,16 +3818,16 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) * * Warn the user, lest they think we're just buggy. */ - printk(KERN_WARNING DRV_NAME ": Highpoint RocketRAID" + dev_warn(&pdev->dev, "Highpoint RocketRAID" " BIOS CORRUPTS DATA on all attached drives," " regardless of if/how they are configured." " BEWARE!\n"); - printk(KERN_WARNING DRV_NAME ": For data safety, do not" + dev_warn(&pdev->dev, "For data safety, do not" " use sectors 8-9 on \"Legacy\" drives," " and avoid the final two gigabytes on" " all RocketRAID BIOS initialized drives.\n"); } - /* drop through */ + fallthrough; case chip_6042: hpriv->ops = &mv6xxx_ops; hp_flags |= MV_HP_GEN_IIE; @@ -3868,8 +3855,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) break; default: - dev_err(host->dev, "BUG: invalid board index %u\n", board_idx); - return 1; + dev_alert(host->dev, "BUG: invalid board index %u\n", board_idx); + return -EINVAL; } hpriv->hp_flags = hp_flags; @@ -3926,7 +3913,7 @@ static int mv_init_host(struct ata_host *host) if (hpriv->ops->read_preamp) hpriv->ops->read_preamp(hpriv, port, mmio); - rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc); + rc = hpriv->ops->reset_hc(host, mmio, n_hc); if (rc) goto done; @@ -3944,7 +3931,7 @@ static int mv_init_host(struct ata_host *host) for (hc = 0; hc < n_hc; hc++) { void __iomem *hc_mmio = mv_hc_base(mmio, hc); - VPRINTK("HC%i: HC config=0x%08x HC IRQ cause " + dev_dbg(host->dev, "HC%i: HC config=0x%08x HC IRQ cause " "(before clear)=0x%08x\n", hc, readl(hc_mmio + HC_CFG), readl(hc_mmio + HC_IRQ_CAUSE)); @@ -4032,16 +4019,14 @@ static int mv_platform_probe(struct platform_device *pdev) struct resource *res; int n_ports = 0, irq = 0; int rc; -#if defined(CONFIG_HAVE_CLK) int port; -#endif ata_print_version_once(&pdev->dev, DRV_VERSION); /* * Simple resource validation .. */ - if (unlikely(pdev->num_resources != 2)) { + if (unlikely(pdev->num_resources != 1)) { dev_err(&pdev->dev, "invalid number of resources\n"); return -EINVAL; } @@ -4055,41 +4040,65 @@ static int mv_platform_probe(struct platform_device *pdev) /* allocate host */ if (pdev->dev.of_node) { - of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports); + rc = of_property_read_u32(pdev->dev.of_node, "nr-ports", + &n_ports); + if (rc) { + dev_err(&pdev->dev, + "error parsing nr-ports property: %d\n", rc); + return rc; + } + + if (n_ports <= 0) { + dev_err(&pdev->dev, "nr-ports must be positive: %d\n", + n_ports); + return -EINVAL; + } + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); } else { - mv_platform_data = pdev->dev.platform_data; + mv_platform_data = dev_get_platdata(&pdev->dev); n_ports = mv_platform_data->n_ports; irq = platform_get_irq(pdev, 0); } + if (irq < 0) + return irq; + if (!irq) + return -EINVAL; host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!host || !hpriv) return -ENOMEM; -#if defined(CONFIG_HAVE_CLK) - hpriv->port_clks = devm_kzalloc(&pdev->dev, - sizeof(struct clk *) * n_ports, + hpriv->port_clks = devm_kcalloc(&pdev->dev, + n_ports, sizeof(struct clk *), GFP_KERNEL); if (!hpriv->port_clks) return -ENOMEM; -#endif + hpriv->port_phys = devm_kcalloc(&pdev->dev, + n_ports, sizeof(struct phy *), + GFP_KERNEL); + if (!hpriv->port_phys) + return -ENOMEM; host->private_data = hpriv; - hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; host->iomap = NULL; hpriv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!hpriv->base) + return -ENOMEM; + hpriv->base -= SATAHC0_REG_BASE; -#if defined(CONFIG_HAVE_CLK) hpriv->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(hpriv->clk)) + if (IS_ERR(hpriv->clk)) { dev_notice(&pdev->dev, "cannot get optional clkdev\n"); - else - clk_prepare_enable(hpriv->clk); + } else { + rc = clk_prepare_enable(hpriv->clk); + if (rc) + goto err; + } for (port = 0; port < n_ports; port++) { char port_number[16]; @@ -4097,8 +4106,25 @@ static int mv_platform_probe(struct platform_device *pdev) hpriv->port_clks[port] = clk_get(&pdev->dev, port_number); if (!IS_ERR(hpriv->port_clks[port])) clk_prepare_enable(hpriv->port_clks[port]); + + sprintf(port_number, "port%d", port); + hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev, + port_number); + if (IS_ERR(hpriv->port_phys[port])) { + rc = PTR_ERR(hpriv->port_phys[port]); + hpriv->port_phys[port] = NULL; + if (rc != -EPROBE_DEFER) + dev_warn(&pdev->dev, "error getting phy %d", rc); + + /* Cleanup only the initialized ports */ + hpriv->n_ports = port; + goto err; + } else + phy_power_on(hpriv->port_phys[port]); } -#endif + + /* All the ports have been initialized */ + hpriv->n_ports = n_ports; /* * (Re-)program MBUS remapping windows if we are asked to. @@ -4111,6 +4137,15 @@ static int mv_platform_probe(struct platform_device *pdev) if (rc) goto err; + /* + * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be + * updated in the LP_PHY_CTL register. + */ + if (pdev->dev.of_node && + of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-370-sata")) + hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL; + /* initialize adapter */ rc = mv_init_host(host); if (rc) @@ -4124,18 +4159,17 @@ static int mv_platform_probe(struct platform_device *pdev) return 0; err: -#if defined(CONFIG_HAVE_CLK) if (!IS_ERR(hpriv->clk)) { clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } - for (port = 0; port < n_ports; port++) { + for (port = 0; port < hpriv->n_ports; port++) { if (!IS_ERR(hpriv->port_clks[port])) { clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } + phy_power_off(hpriv->port_phys[port]); } -#endif return rc; } @@ -4148,16 +4182,13 @@ err: * A platform bus SATA device has been unplugged. Perform the needed * cleanup. Also called on module unload for any active devices. */ -static int mv_platform_remove(struct platform_device *pdev) +static void mv_platform_remove(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); -#if defined(CONFIG_HAVE_CLK) struct mv_host_priv *hpriv = host->private_data; int port; -#endif ata_host_detach(host); -#if defined(CONFIG_HAVE_CLK) if (!IS_ERR(hpriv->clk)) { clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); @@ -4167,19 +4198,18 @@ static int mv_platform_remove(struct platform_device *pdev) clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } + phy_power_off(hpriv->port_phys[port]); } -#endif - return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mv_platform_suspend(struct platform_device *pdev, pm_message_t state) { struct ata_host *host = platform_get_drvdata(pdev); + if (host) - return ata_host_suspend(host, state); - else - return 0; + ata_host_suspend(host, state); + return 0; } static int mv_platform_resume(struct platform_device *pdev) @@ -4201,7 +4231,7 @@ static int mv_platform_resume(struct platform_device *pdev) /* initialize adapter */ ret = mv_init_host(host); if (ret) { - printk(KERN_ERR DRV_NAME ": Error during HW init\n"); + dev_err(&pdev->dev, "Error during HW init\n"); return ret; } ata_host_resume(host); @@ -4215,9 +4245,10 @@ static int mv_platform_resume(struct platform_device *pdev) #endif #ifdef CONFIG_OF -static struct of_device_id mv_sata_dt_ids[] = { +static const struct of_device_id mv_sata_dt_ids[] = { + { .compatible = "marvell,armada-370-sata", }, { .compatible = "marvell,orion-sata", }, - {}, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mv_sata_dt_ids); #endif @@ -4229,7 +4260,6 @@ static struct platform_driver mv_platform_driver = { .resume = mv_platform_resume, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mv_sata_dt_ids), }, }; @@ -4238,54 +4268,53 @@ static struct platform_driver mv_platform_driver = { #ifdef CONFIG_PCI static int mv_pci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mv_pci_device_resume(struct pci_dev *pdev); #endif +static const struct pci_device_id mv_pci_tbl[] = { + { PCI_VDEVICE(MARVELL, 0x5040), chip_504x }, + { PCI_VDEVICE(MARVELL, 0x5041), chip_504x }, + { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 }, + { PCI_VDEVICE(MARVELL, 0x5081), chip_508x }, + /* RocketRAID 1720/174x have different identifiers */ + { PCI_VDEVICE(TTI, 0x1720), chip_6042 }, + { PCI_VDEVICE(TTI, 0x1740), chip_6042 }, + { PCI_VDEVICE(TTI, 0x1742), chip_6042 }, + + { PCI_VDEVICE(MARVELL, 0x6040), chip_604x }, + { PCI_VDEVICE(MARVELL, 0x6041), chip_604x }, + { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 }, + { PCI_VDEVICE(MARVELL, 0x6080), chip_608x }, + { PCI_VDEVICE(MARVELL, 0x6081), chip_608x }, + + { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x }, + + /* Adaptec 1430SA */ + { PCI_VDEVICE(ADAPTEC2, 0x0243), chip_7042 }, + + /* Marvell 7042 support */ + { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 }, + + /* Highpoint RocketRAID PCIe series */ + { PCI_VDEVICE(TTI, 0x2300), chip_7042 }, + { PCI_VDEVICE(TTI, 0x2310), chip_7042 }, + + { } /* terminate list */ +}; static struct pci_driver mv_pci_driver = { .name = DRV_NAME, .id_table = mv_pci_tbl, .probe = mv_pci_init_one, .remove = ata_pci_remove_one, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .suspend = ata_pci_device_suspend, .resume = mv_pci_device_resume, #endif }; - -/* move to PCI layer or libata core? */ -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_err(&pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} +MODULE_DEVICE_TABLE(pci, mv_pci_tbl); /** * mv_print_info - Dump key info to kernel log for perusal. @@ -4371,9 +4400,11 @@ static int mv_pci_init_one(struct pci_dev *pdev, host->iomap = pcim_iomap_table(pdev); hpriv->base = host->iomap[MV_PRIMARY_BAR]; - rc = pci_go_64(pdev); - if (rc) + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + dev_err(&pdev->dev, "DMA enable failed\n"); return rc; + } rc = mv_create_dma_pools(hpriv, &pdev->dev); if (rc) @@ -4406,7 +4437,7 @@ static int mv_pci_init_one(struct pci_dev *pdev, IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mv_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = pci_get_drvdata(pdev); @@ -4428,9 +4459,6 @@ static int mv_pci_device_resume(struct pci_dev *pdev) #endif #endif -static int mv_platform_probe(struct platform_device *pdev); -static int mv_platform_remove(struct platform_device *pdev); - static int __init mv_init(void) { int rc = -ENODEV; @@ -4458,8 +4486,7 @@ static void __exit mv_exit(void) MODULE_AUTHOR("Brett Russ"); MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, mv_pci_tbl); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:" DRV_NAME); |
