mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Merge branch 'for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo: "Most are ahci and other device specific additions. Dan cleaned up ahci IRQ handling to prepare for future MSIX changes. On the libata core side, Vinayak updated SG handling so that NCQ commands can be issued through SG_IO and Christoph cleaned up code a bit. There's one merge from for-4.3-fixes to include a pata_macio commit that didn't get pushed out" * 'for-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: ahci: add new Intel device IDs ahci: Add Marvell 88se91a2 device id ahci: cleanup ahci_host_activate_multi_irqs ahci: ahci_host_activate: kill IRQF_SHARED devicetree: bindings: Fixed a few typos ahci: qoriq: Disable NCQ on ls2080a SoC ahci: qoriq: Rename LS2085A SoC support code to LS2080A libata: enable LBA flag in taskfile for ata_scsi_pass_thru() libata: add support for NCQ commands for SG interface ahci: qoriq: Fix a compiling warning pata_it821x: use "const char *" for string literals libata: only call ->done once all per-tag ressources are released libata: cleanup ata_scsi_qc_complete ata: ahci: find eSATA ports and flag them as removable libata: samsung_cf: fix handling platform_get_irq result ata: pata_macio: Fix module autoload for OF platform driver ata: pata_pxa: dmaengine conversion ahci: added a new driver for supporting Freescale AHCI sata devicetree:bindings: add devicetree bindings for Freescale AHCI Revert "ahci: added support for Freescale AHCI sata"
This commit is contained in:
commit
11eaaadb3e
21
Documentation/devicetree/bindings/ata/ahci-fsl-qoriq.txt
Normal file
21
Documentation/devicetree/bindings/ata/ahci-fsl-qoriq.txt
Normal file
@ -0,0 +1,21 @@
|
||||
Binding for Freescale QorIQ AHCI SATA Controller
|
||||
|
||||
Required properties:
|
||||
- reg: Physical base address and size of the controller's register area.
|
||||
- compatible: Compatibility string. Must be 'fsl,<chip>-ahci', where
|
||||
chip could be ls1021a, ls2080a, ls1043a etc.
|
||||
- clocks: Input clock specifier. Refer to common clock bindings.
|
||||
- interrupts: Interrupt specifier. Refer to interrupt binding.
|
||||
|
||||
Optional properties:
|
||||
- dma-coherent: Enable AHCI coherent DMA operation.
|
||||
- reg-names: register area names when there are more than 1 register area.
|
||||
|
||||
Examples:
|
||||
sata@3200000 {
|
||||
compatible = "fsl,ls1021a-ahci";
|
||||
reg = <0x0 0x3200000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&platform_clk 1>;
|
||||
dma-coherent;
|
||||
};
|
@ -16,8 +16,6 @@ Required properties:
|
||||
- "snps,dwc-ahci"
|
||||
- "snps,exynos5440-ahci"
|
||||
- "snps,spear-ahci"
|
||||
- "fsl,qoriq-ahci" : for qoriq series socs which include ls1021, ls2085, etc.
|
||||
- "fsl,<chip>-ahci" : chip could be ls1021, ls2085 etc.
|
||||
- "generic-ahci"
|
||||
- interrupts : <interrupt mapping for SATA IRQ>
|
||||
- reg : <registers mapping>
|
||||
|
@ -175,6 +175,15 @@ config AHCI_XGENE
|
||||
help
|
||||
This option enables support for APM X-Gene SoC SATA host controller.
|
||||
|
||||
config AHCI_QORIQ
|
||||
tristate "Freescale QorIQ AHCI SATA support"
|
||||
depends on OF
|
||||
help
|
||||
This option enables support for the Freescale QorIQ AHCI SoC's
|
||||
onboard AHCI SATA.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SATA_FSL
|
||||
tristate "Freescale 3.0Gbps SATA support"
|
||||
depends on FSL_SOC
|
||||
|
@ -19,6 +19,7 @@ obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
|
||||
obj-$(CONFIG_AHCI_QORIQ) += ahci_qoriq.o libahci.o libahci_platform.o
|
||||
|
||||
# SFF w/ custom DMA
|
||||
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
|
||||
|
@ -314,6 +314,16 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
|
||||
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
|
||||
{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
|
||||
@ -489,6 +499,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||||
.driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0),
|
||||
.driver_data = board_ahci_yes_fbs },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a2), /* 88se91a2 */
|
||||
.driver_data = board_ahci_yes_fbs },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
|
||||
.driver_data = board_ahci_yes_fbs },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
|
||||
|
@ -181,6 +181,8 @@ enum {
|
||||
PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
|
||||
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
|
||||
PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */
|
||||
PORT_CMD_ESP = (1 << 21), /* External Sata Port */
|
||||
PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */
|
||||
PORT_CMD_PMP = (1 << 17), /* PMP attached */
|
||||
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
|
||||
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
|
||||
|
@ -76,7 +76,6 @@ static const struct of_device_id ahci_of_match[] = {
|
||||
{ .compatible = "ibm,476gtr-ahci", },
|
||||
{ .compatible = "snps,dwc-ahci", },
|
||||
{ .compatible = "hisilicon,hisi-ahci", },
|
||||
{ .compatible = "fsl,qoriq-ahci", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ahci_of_match);
|
||||
|
279
drivers/ata/ahci_qoriq.c
Normal file
279
drivers/ata/ahci_qoriq.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Freescale QorIQ AHCI SATA platform driver
|
||||
*
|
||||
* Copyright 2015 Freescale, Inc.
|
||||
* Tang Yuantian <Yuantian.Tang@freescale.com>
|
||||
*
|
||||
* 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; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/ahci_platform.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/libata.h>
|
||||
#include "ahci.h"
|
||||
|
||||
#define DRV_NAME "ahci-qoriq"
|
||||
|
||||
/* port register definition */
|
||||
#define PORT_PHY1 0xA8
|
||||
#define PORT_PHY2 0xAC
|
||||
#define PORT_PHY3 0xB0
|
||||
#define PORT_PHY4 0xB4
|
||||
#define PORT_PHY5 0xB8
|
||||
#define PORT_TRANS 0xC8
|
||||
|
||||
/* port register default value */
|
||||
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
|
||||
#define AHCI_PORT_PHY_2_CFG 0x28183411
|
||||
#define AHCI_PORT_PHY_3_CFG 0x0e081004
|
||||
#define AHCI_PORT_PHY_4_CFG 0x00480811
|
||||
#define AHCI_PORT_PHY_5_CFG 0x192c96a4
|
||||
#define AHCI_PORT_TRANS_CFG 0x08000025
|
||||
|
||||
#define SATA_ECC_DISABLE 0x00020000
|
||||
|
||||
enum ahci_qoriq_type {
|
||||
AHCI_LS1021A,
|
||||
AHCI_LS1043A,
|
||||
AHCI_LS2080A,
|
||||
};
|
||||
|
||||
struct ahci_qoriq_priv {
|
||||
struct ccsr_ahci *reg_base;
|
||||
enum ahci_qoriq_type type;
|
||||
void __iomem *ecc_addr;
|
||||
};
|
||||
|
||||
static const struct of_device_id ahci_qoriq_of_match[] = {
|
||||
{ .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A},
|
||||
{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
|
||||
{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
|
||||
|
||||
static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
{
|
||||
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
|
||||
void __iomem *port_mmio = ahci_port_base(link->ap);
|
||||
u32 px_cmd, px_is, px_val;
|
||||
struct ata_port *ap = link->ap;
|
||||
struct ahci_port_priv *pp = ap->private_data;
|
||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data;
|
||||
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
|
||||
struct ata_taskfile tf;
|
||||
bool online;
|
||||
int rc;
|
||||
bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
ahci_stop_engine(ap);
|
||||
|
||||
/*
|
||||
* There is a errata on ls1021a Rev1.0 and Rev2.0 which is:
|
||||
* A-009042: The device detection initialization sequence
|
||||
* mistakenly resets some registers.
|
||||
*
|
||||
* Workaround for this is:
|
||||
* The software should read and store PxCMD and PxIS values
|
||||
* before issuing the device detection initialization sequence.
|
||||
* After the sequence is complete, software should restore the
|
||||
* PxCMD and PxIS with the stored values.
|
||||
*/
|
||||
if (ls1021a_workaround) {
|
||||
px_cmd = readl(port_mmio + PORT_CMD);
|
||||
px_is = readl(port_mmio + PORT_IRQ_STAT);
|
||||
}
|
||||
|
||||
/* clear D2H reception area to properly wait for D2H FIS */
|
||||
ata_tf_init(link->device, &tf);
|
||||
tf.command = ATA_BUSY;
|
||||
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
|
||||
|
||||
rc = sata_link_hardreset(link, timing, deadline, &online,
|
||||
ahci_check_ready);
|
||||
|
||||
/* restore the PxCMD and PxIS on ls1021 */
|
||||
if (ls1021a_workaround) {
|
||||
px_val = readl(port_mmio + PORT_CMD);
|
||||
if (px_val != px_cmd)
|
||||
writel(px_cmd, port_mmio + PORT_CMD);
|
||||
|
||||
px_val = readl(port_mmio + PORT_IRQ_STAT);
|
||||
if (px_val != px_is)
|
||||
writel(px_is, port_mmio + PORT_IRQ_STAT);
|
||||
}
|
||||
|
||||
hpriv->start_engine(ap);
|
||||
|
||||
if (online)
|
||||
*class = ahci_dev_classify(ap);
|
||||
|
||||
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct ata_port_operations ahci_qoriq_ops = {
|
||||
.inherits = &ahci_ops,
|
||||
.hardreset = ahci_qoriq_hardreset,
|
||||
};
|
||||
|
||||
static struct ata_port_info ahci_qoriq_port_info = {
|
||||
.flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_qoriq_ops,
|
||||
};
|
||||
|
||||
static struct scsi_host_template ahci_qoriq_sht = {
|
||||
AHCI_SHT(DRV_NAME),
|
||||
};
|
||||
|
||||
static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
struct ahci_qoriq_priv *qpriv = hpriv->plat_data;
|
||||
void __iomem *reg_base = hpriv->mmio;
|
||||
|
||||
switch (qpriv->type) {
|
||||
case AHCI_LS1021A:
|
||||
writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
|
||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||
writel(AHCI_PORT_PHY_2_CFG, reg_base + PORT_PHY2);
|
||||
writel(AHCI_PORT_PHY_3_CFG, reg_base + PORT_PHY3);
|
||||
writel(AHCI_PORT_PHY_4_CFG, reg_base + PORT_PHY4);
|
||||
writel(AHCI_PORT_PHY_5_CFG, reg_base + PORT_PHY5);
|
||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||
break;
|
||||
|
||||
case AHCI_LS1043A:
|
||||
case AHCI_LS2080A:
|
||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ahci_qoriq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct ahci_qoriq_priv *qoriq_priv;
|
||||
const struct of_device_id *of_id;
|
||||
struct resource *res;
|
||||
int rc;
|
||||
|
||||
hpriv = ahci_platform_get_resources(pdev);
|
||||
if (IS_ERR(hpriv))
|
||||
return PTR_ERR(hpriv);
|
||||
|
||||
of_id = of_match_node(ahci_qoriq_of_match, np);
|
||||
if (!of_id)
|
||||
return -ENODEV;
|
||||
|
||||
qoriq_priv = devm_kzalloc(dev, sizeof(*qoriq_priv), GFP_KERNEL);
|
||||
if (!qoriq_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
qoriq_priv->type = (enum ahci_qoriq_type)of_id->data;
|
||||
|
||||
if (qoriq_priv->type == AHCI_LS1021A) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"sata-ecc");
|
||||
qoriq_priv->ecc_addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(qoriq_priv->ecc_addr))
|
||||
return PTR_ERR(qoriq_priv->ecc_addr);
|
||||
}
|
||||
|
||||
rc = ahci_platform_enable_resources(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
hpriv->plat_data = qoriq_priv;
|
||||
rc = ahci_qoriq_phy_init(hpriv);
|
||||
if (rc)
|
||||
goto disable_resources;
|
||||
|
||||
/* Workaround for ls2080a */
|
||||
if (qoriq_priv->type == AHCI_LS2080A) {
|
||||
hpriv->flags |= AHCI_HFLAG_NO_NCQ;
|
||||
ahci_qoriq_port_info.flags &= ~ATA_FLAG_NCQ;
|
||||
}
|
||||
|
||||
rc = ahci_platform_init_host(pdev, hpriv, &ahci_qoriq_port_info,
|
||||
&ahci_qoriq_sht);
|
||||
if (rc)
|
||||
goto disable_resources;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_resources:
|
||||
ahci_platform_disable_resources(hpriv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ahci_qoriq_resume(struct device *dev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(dev);
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
int rc;
|
||||
|
||||
rc = ahci_platform_enable_resources(hpriv);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = ahci_qoriq_phy_init(hpriv);
|
||||
if (rc)
|
||||
goto disable_resources;
|
||||
|
||||
rc = ahci_platform_resume_host(dev);
|
||||
if (rc)
|
||||
goto disable_resources;
|
||||
|
||||
/* We resumed so update PM runtime state */
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_resources:
|
||||
ahci_platform_disable_resources(hpriv);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ahci_qoriq_pm_ops, ahci_platform_suspend,
|
||||
ahci_qoriq_resume);
|
||||
|
||||
static struct platform_driver ahci_qoriq_driver = {
|
||||
.probe = ahci_qoriq_probe,
|
||||
.remove = ata_platform_remove_one,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = ahci_qoriq_of_match,
|
||||
.pm = &ahci_qoriq_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ahci_qoriq_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Freescale QorIQ AHCI SATA platform driver");
|
||||
MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -1117,6 +1117,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
|
||||
int port_no, void __iomem *mmio,
|
||||
void __iomem *port_mmio)
|
||||
{
|
||||
struct ahci_host_priv *hpriv = ap->host->private_data;
|
||||
const char *emsg = NULL;
|
||||
int rc;
|
||||
u32 tmp;
|
||||
@ -1138,6 +1139,12 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
|
||||
writel(tmp, port_mmio + PORT_IRQ_STAT);
|
||||
|
||||
writel(1 << port_no, mmio + HOST_IRQ_STAT);
|
||||
|
||||
/* mark esata ports */
|
||||
tmp = readl(port_mmio + PORT_CMD);
|
||||
if ((tmp & PORT_CMD_HPCP) ||
|
||||
((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
|
||||
ap->pflags |= ATA_PFLAG_EXTERNAL;
|
||||
}
|
||||
|
||||
void ahci_init_controller(struct ata_host *host)
|
||||
@ -2486,28 +2493,13 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
|
||||
|
||||
rc = devm_request_threaded_irq(host->dev, irq + i,
|
||||
ahci_multi_irqs_intr,
|
||||
ahci_port_thread_fn, IRQF_SHARED,
|
||||
ahci_port_thread_fn, 0,
|
||||
pp->irq_desc, host->ports[i]);
|
||||
if (rc)
|
||||
goto out_free_irqs;
|
||||
}
|
||||
|
||||
for (i = 0; i < host->n_ports; i++)
|
||||
return rc;
|
||||
ata_port_desc(host->ports[i], "irq %d", irq + i);
|
||||
|
||||
rc = ata_host_register(host, sht);
|
||||
if (rc)
|
||||
goto out_free_all_irqs;
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_all_irqs:
|
||||
i = host->n_ports;
|
||||
out_free_irqs:
|
||||
for (i--; i >= 0; i--)
|
||||
devm_free_irq(host->dev, irq + i, host->ports[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
return ata_host_register(host, sht);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1757,6 +1757,15 @@ nothing_to_do:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void ata_qc_done(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
void (*done)(struct scsi_cmnd *) = qc->scsidone;
|
||||
|
||||
ata_qc_free(qc);
|
||||
done(cmd);
|
||||
}
|
||||
|
||||
static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
@ -1774,28 +1783,17 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
||||
* asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
|
||||
*/
|
||||
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
|
||||
((cdb[2] & 0x20) || need_sense)) {
|
||||
((cdb[2] & 0x20) || need_sense))
|
||||
ata_gen_passthru_sense(qc);
|
||||
} else {
|
||||
if (!need_sense) {
|
||||
cmd->result = SAM_STAT_GOOD;
|
||||
} else {
|
||||
/* TODO: decide which descriptor format to use
|
||||
* for 48b LBA devices and call that here
|
||||
* instead of the fixed desc, which is only
|
||||
* good for smaller LBA (and maybe CHS?)
|
||||
* devices.
|
||||
*/
|
||||
ata_gen_ata_sense(qc);
|
||||
}
|
||||
}
|
||||
else if (need_sense)
|
||||
ata_gen_ata_sense(qc);
|
||||
else
|
||||
cmd->result = SAM_STAT_GOOD;
|
||||
|
||||
if (need_sense && !ap->ops->error_handler)
|
||||
ata_dump_status(ap->print_id, &qc->result_tf);
|
||||
|
||||
qc->scsidone(cmd);
|
||||
|
||||
ata_qc_free(qc);
|
||||
ata_qc_done(qc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2015,8 +2013,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
|
||||
|
||||
VPRINTK("ENTER\n");
|
||||
|
||||
/* set scsi removable (RMB) bit per ata bit */
|
||||
if (ata_id_removable(args->id))
|
||||
/* set scsi removable (RMB) bit per ata bit, or if the
|
||||
* AHCI port says it's external (Hotplug-capable, eSATA).
|
||||
*/
|
||||
if (ata_id_removable(args->id) ||
|
||||
(args->dev->link->ap->pflags & ATA_PFLAG_EXTERNAL))
|
||||
hdr[1] |= (1 << 7);
|
||||
|
||||
if (args->dev->class == ATA_DEV_ZAC) {
|
||||
@ -2594,8 +2595,7 @@ static void atapi_sense_complete(struct ata_queued_cmd *qc)
|
||||
ata_gen_passthru_sense(qc);
|
||||
}
|
||||
|
||||
qc->scsidone(qc->scsicmd);
|
||||
ata_qc_free(qc);
|
||||
ata_qc_done(qc);
|
||||
}
|
||||
|
||||
/* is it pointless to prefer PIO for "safety reasons"? */
|
||||
@ -2690,8 +2690,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
||||
qc->dev->sdev->locked = 0;
|
||||
|
||||
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
|
||||
qc->scsidone(cmd);
|
||||
ata_qc_free(qc);
|
||||
ata_qc_done(qc);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2735,8 +2734,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
||||
cmd->result = SAM_STAT_GOOD;
|
||||
}
|
||||
|
||||
qc->scsidone(cmd);
|
||||
ata_qc_free(qc);
|
||||
ata_qc_done(qc);
|
||||
}
|
||||
/**
|
||||
* atapi_xlat - Initialize PACKET taskfile
|
||||
@ -2914,12 +2912,14 @@ ata_scsi_map_proto(u8 byte1)
|
||||
case 5: /* PIO Data-out */
|
||||
return ATA_PROT_PIO;
|
||||
|
||||
case 12: /* FPDMA */
|
||||
return ATA_PROT_NCQ;
|
||||
|
||||
case 0: /* Hard Reset */
|
||||
case 1: /* SRST */
|
||||
case 8: /* Device Diagnostic */
|
||||
case 9: /* Device Reset */
|
||||
case 7: /* DMA Queued */
|
||||
case 12: /* FPDMA */
|
||||
case 15: /* Return Response Info */
|
||||
default: /* Reserved */
|
||||
break;
|
||||
@ -2947,6 +2947,9 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
||||
if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
|
||||
goto invalid_fld;
|
||||
|
||||
/* enable LBA */
|
||||
tf->flags |= ATA_TFLAG_LBA;
|
||||
|
||||
/*
|
||||
* 12 and 16 byte CDBs use different offsets to
|
||||
* provide the various register values.
|
||||
@ -2992,6 +2995,10 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
||||
tf->command = cdb[9];
|
||||
}
|
||||
|
||||
/* For NCQ commands with FPDMA protocol, copy the tag value */
|
||||
if (tf->protocol == ATA_PROT_NCQ)
|
||||
tf->nsect = qc->tag << 3;
|
||||
|
||||
/* enforce correct master/slave bit */
|
||||
tf->device = dev->devno ?
|
||||
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
|
||||
|
@ -604,9 +604,9 @@ static void it821x_display_disk(int n, u8 *buf)
|
||||
{
|
||||
unsigned char id[41];
|
||||
int mode = 0;
|
||||
char *mtype = "";
|
||||
const char *mtype = "";
|
||||
char mbuf[8];
|
||||
char *cbl = "(40 wire cable)";
|
||||
const char *cbl = "(40 wire cable)";
|
||||
|
||||
static const char *types[5] = {
|
||||
"RAID0", "RAID1", "RAID 0+1", "JBOD", "DISK"
|
||||
@ -903,7 +903,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
};
|
||||
|
||||
const struct ata_port_info *ppi[] = { NULL, NULL };
|
||||
static char *mode[2] = { "pass through", "smart" };
|
||||
static const char *mode[2] = { "pass through", "smart" };
|
||||
int rc;
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
|
@ -1344,6 +1344,7 @@ static struct of_device_id pata_macio_match[] =
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pata_macio_match);
|
||||
|
||||
static struct macio_driver pata_macio_driver =
|
||||
{
|
||||
|
@ -24,79 +24,36 @@
|
||||
#include <linux/ata.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma/pxa-dma.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include <mach/pxa2xx-regs.h>
|
||||
#include <linux/platform_data/ata-pxa.h>
|
||||
#include <mach/dma.h>
|
||||
|
||||
#define DRV_NAME "pata_pxa"
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
struct pata_pxa_data {
|
||||
uint32_t dma_channel;
|
||||
struct pxa_dma_desc *dma_desc;
|
||||
dma_addr_t dma_desc_addr;
|
||||
uint32_t dma_desc_id;
|
||||
|
||||
/* DMA IO physical address */
|
||||
uint32_t dma_io_addr;
|
||||
/* PXA DREQ<0:2> pin selector */
|
||||
uint32_t dma_dreq;
|
||||
/* DMA DCSR register value */
|
||||
uint32_t dma_dcsr;
|
||||
|
||||
struct dma_chan *dma_chan;
|
||||
dma_cookie_t dma_cookie;
|
||||
struct completion dma_done;
|
||||
};
|
||||
|
||||
/*
|
||||
* Setup the DMA descriptors. The size is transfer capped at 4k per descriptor,
|
||||
* if the transfer is longer, it is split into multiple chained descriptors.
|
||||
* DMA interrupt handler.
|
||||
*/
|
||||
static void pxa_load_dmac(struct scatterlist *sg, struct ata_queued_cmd *qc)
|
||||
static void pxa_ata_dma_irq(void *d)
|
||||
{
|
||||
struct pata_pxa_data *pd = qc->ap->private_data;
|
||||
struct pata_pxa_data *pd = d;
|
||||
enum dma_status status;
|
||||
|
||||
uint32_t cpu_len, seg_len;
|
||||
dma_addr_t cpu_addr;
|
||||
|
||||
cpu_addr = sg_dma_address(sg);
|
||||
cpu_len = sg_dma_len(sg);
|
||||
|
||||
do {
|
||||
seg_len = (cpu_len > 0x1000) ? 0x1000 : cpu_len;
|
||||
|
||||
pd->dma_desc[pd->dma_desc_id].ddadr = pd->dma_desc_addr +
|
||||
((pd->dma_desc_id + 1) * sizeof(struct pxa_dma_desc));
|
||||
|
||||
pd->dma_desc[pd->dma_desc_id].dcmd = DCMD_BURST32 |
|
||||
DCMD_WIDTH2 | (DCMD_LENGTH & seg_len);
|
||||
|
||||
if (qc->tf.flags & ATA_TFLAG_WRITE) {
|
||||
pd->dma_desc[pd->dma_desc_id].dsadr = cpu_addr;
|
||||
pd->dma_desc[pd->dma_desc_id].dtadr = pd->dma_io_addr;
|
||||
pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCSRCADDR |
|
||||
DCMD_FLOWTRG;
|
||||
} else {
|
||||
pd->dma_desc[pd->dma_desc_id].dsadr = pd->dma_io_addr;
|
||||
pd->dma_desc[pd->dma_desc_id].dtadr = cpu_addr;
|
||||
pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCTRGADDR |
|
||||
DCMD_FLOWSRC;
|
||||
}
|
||||
|
||||
cpu_len -= seg_len;
|
||||
cpu_addr += seg_len;
|
||||
pd->dma_desc_id++;
|
||||
|
||||
} while (cpu_len);
|
||||
|
||||
/* Should not happen */
|
||||
if (seg_len & 0x1f)
|
||||
DALGN |= (1 << pd->dma_dreq);
|
||||
status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, NULL);
|
||||
if (status == DMA_ERROR || status == DMA_COMPLETE)
|
||||
complete(&pd->dma_done);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -105,28 +62,22 @@ static void pxa_load_dmac(struct scatterlist *sg, struct ata_queued_cmd *qc)
|
||||
static void pxa_qc_prep(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct pata_pxa_data *pd = qc->ap->private_data;
|
||||
int si = 0;
|
||||
struct scatterlist *sg;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
enum dma_transfer_direction dir;
|
||||
|
||||
if (!(qc->flags & ATA_QCFLAG_DMAMAP))
|
||||
return;
|
||||
|
||||
pd->dma_desc_id = 0;
|
||||
|
||||
DCSR(pd->dma_channel) = 0;
|
||||
DALGN &= ~(1 << pd->dma_dreq);
|
||||
|
||||
for_each_sg(qc->sg, sg, qc->n_elem, si)
|
||||
pxa_load_dmac(sg, qc);
|
||||
|
||||
pd->dma_desc[pd->dma_desc_id - 1].ddadr = DDADR_STOP;
|
||||
|
||||
/* Fire IRQ only at the end of last block */
|
||||
pd->dma_desc[pd->dma_desc_id - 1].dcmd |= DCMD_ENDIRQEN;
|
||||
|
||||
DDADR(pd->dma_channel) = pd->dma_desc_addr;
|
||||
DRCMR(pd->dma_dreq) = DRCMR_MAPVLD | pd->dma_channel;
|
||||
|
||||
dir = (qc->dma_dir == DMA_TO_DEVICE ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
|
||||
tx = dmaengine_prep_slave_sg(pd->dma_chan, qc->sg, qc->n_elem, dir,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!tx) {
|
||||
ata_dev_err(qc->dev, "prep_slave_sg() failed\n");
|
||||
return;
|
||||
}
|
||||
tx->callback = pxa_ata_dma_irq;
|
||||
tx->callback_param = pd;
|
||||
pd->dma_cookie = dmaengine_submit(tx);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -145,7 +96,7 @@ static void pxa_bmdma_start(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct pata_pxa_data *pd = qc->ap->private_data;
|
||||
init_completion(&pd->dma_done);
|
||||
DCSR(pd->dma_channel) = DCSR_RUN;
|
||||
dma_async_issue_pending(pd->dma_chan);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -154,12 +105,14 @@ static void pxa_bmdma_start(struct ata_queued_cmd *qc)
|
||||
static void pxa_bmdma_stop(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct pata_pxa_data *pd = qc->ap->private_data;
|
||||
enum dma_status status;
|
||||
|
||||
if ((DCSR(pd->dma_channel) & DCSR_RUN) &&
|
||||
wait_for_completion_timeout(&pd->dma_done, HZ))
|
||||
dev_err(qc->ap->dev, "Timeout waiting for DMA completion!");
|
||||
status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, NULL);
|
||||
if (status != DMA_ERROR && status != DMA_COMPLETE &&
|
||||
wait_for_completion_timeout(&pd->dma_done, HZ))
|
||||
ata_dev_err(qc->dev, "Timeout waiting for DMA completion!");
|
||||
|
||||
DCSR(pd->dma_channel) = 0;
|
||||
dmaengine_terminate_all(pd->dma_chan);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -170,8 +123,11 @@ static unsigned char pxa_bmdma_status(struct ata_port *ap)
|
||||
{
|
||||
struct pata_pxa_data *pd = ap->private_data;
|
||||
unsigned char ret = ATA_DMA_INTR;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
|
||||
if (pd->dma_dcsr & DCSR_BUSERR)
|
||||
status = dmaengine_tx_status(pd->dma_chan, pd->dma_cookie, &state);
|
||||
if (status != DMA_COMPLETE)
|
||||
ret |= ATA_DMA_ERR;
|
||||
|
||||
return ret;
|
||||
@ -213,21 +169,6 @@ static struct ata_port_operations pxa_ata_port_ops = {
|
||||
.qc_prep = pxa_qc_prep,
|
||||
};
|
||||
|
||||
/*
|
||||
* DMA interrupt handler.
|
||||
*/
|
||||
static void pxa_ata_dma_irq(int dma, void *port)
|
||||
{
|
||||
struct ata_port *ap = port;
|
||||
struct pata_pxa_data *pd = ap->private_data;
|
||||
|
||||
pd->dma_dcsr = DCSR(dma);
|
||||
DCSR(dma) = pd->dma_dcsr;
|
||||
|
||||
if (pd->dma_dcsr & DCSR_STOPSTATE)
|
||||
complete(&pd->dma_done);
|
||||
}
|
||||
|
||||
static int pxa_ata_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ata_host *host;
|
||||
@ -238,6 +179,9 @@ static int pxa_ata_probe(struct platform_device *pdev)
|
||||
struct resource *dma_res;
|
||||
struct resource *irq_res;
|
||||
struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct dma_slave_config config;
|
||||
dma_cap_mask_t mask;
|
||||
struct pxad_param param;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -333,29 +277,32 @@ static int pxa_ata_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ap->private_data = data;
|
||||
data->dma_dreq = pdata->dma_dreq;
|
||||
data->dma_io_addr = dma_res->start;
|
||||
|
||||
/*
|
||||
* Allocate space for the DMA descriptors
|
||||
*/
|
||||
data->dma_desc = dmam_alloc_coherent(&pdev->dev, PAGE_SIZE,
|
||||
&data->dma_desc_addr, GFP_KERNEL);
|
||||
if (!data->dma_desc)
|
||||
return -EINVAL;
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
param.prio = PXAD_PRIO_LOWEST;
|
||||
param.drcmr = pdata->dma_dreq;
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
config.src_addr = dma_res->start;
|
||||
config.dst_addr = dma_res->start;
|
||||
config.src_maxburst = 32;
|
||||
config.dst_maxburst = 32;
|
||||
|
||||
/*
|
||||
* Request the DMA channel
|
||||
*/
|
||||
data->dma_channel = pxa_request_dma(DRV_NAME, DMA_PRIO_LOW,
|
||||
pxa_ata_dma_irq, ap);
|
||||
if (data->dma_channel < 0)
|
||||
data->dma_chan =
|
||||
dma_request_slave_channel_compat(mask, pxad_filter_fn,
|
||||
¶m, &pdev->dev, "data");
|
||||
if (!data->dma_chan)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Stop and clear the DMA channel
|
||||
*/
|
||||
DCSR(data->dma_channel) = 0;
|
||||
ret = dmaengine_slave_config(data->dma_chan, &config);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "dma configuration failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate the ATA host
|
||||
@ -363,7 +310,7 @@ static int pxa_ata_probe(struct platform_device *pdev)
|
||||
ret = ata_host_activate(host, irq_res->start, ata_sff_interrupt,
|
||||
pdata->irq_flags, &pxa_ata_sht);
|
||||
if (ret)
|
||||
pxa_free_dma(data->dma_channel);
|
||||
dma_release_channel(data->dma_chan);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -373,7 +320,7 @@ static int pxa_ata_remove(struct platform_device *pdev)
|
||||
struct ata_host *host = platform_get_drvdata(pdev);
|
||||
struct pata_pxa_data *data = host->ports[0]->private_data;
|
||||
|
||||
pxa_free_dma(data->dma_channel);
|
||||
dma_release_channel(data->dma_chan);
|
||||
|
||||
ata_host_detach(host);
|
||||
|
||||
|
@ -70,7 +70,7 @@ struct s3c_ide_info {
|
||||
struct clk *clk;
|
||||
void __iomem *ide_addr;
|
||||
void __iomem *sfr_addr;
|
||||
unsigned int irq;
|
||||
int irq;
|
||||
enum s3c_cpu_type cpu_type;
|
||||
unsigned int fifo_status_reg;
|
||||
};
|
||||
|
@ -254,6 +254,7 @@ enum {
|
||||
|
||||
ATA_PFLAG_PIO32 = (1 << 20), /* 32bit PIO */
|
||||
ATA_PFLAG_PIO32CHANGE = (1 << 21), /* 32bit PIO can be turned on/off */
|
||||
ATA_PFLAG_EXTERNAL = (1 << 22), /* eSATA/external port */
|
||||
|
||||
/* struct ata_queued_cmd flags */
|
||||
ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
|
||||
|
Loading…
Reference in New Issue
Block a user