Commit f96ed261 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

Pull libata updates from Tejun Heo:
 - Write same support added
 - Minor ahci MSIX irq handling updates
 - Non-critical SCSI command translation fixes
 - Controller specific changes

* 'for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
  ahci: qoriq: Revert "ahci: qoriq: Disable NCQ on ls2080a SoC"
  libata: remove <asm-generic/libata-portmap.h>
  libata: remove unused definitions from <asm/libata-portmap.h>
  pata_at91: Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR
  ata: Replace BUG() with BUG_ON().
  ata: sata_mv: Replacing dma_pool_alloc and memset with a single call dma_pool_zalloc.
  libata: Some drives failing on SCT Write Same
  ahci: use pci_alloc_irq_vectors
  libata: SCT Write Same handle ATA_DFLAG_PIO
  libata: SCT Write Same / DSM Trim
  libata: Add support for SCT Write Same
  libata: Safely overwrite attached page in WRITE SAME xlat
  ahci: also use a per-port lock for the multi-MSIX case
  ARM: dts: STiH407-family: Add ports-implemented property in sata nodes
  ahci: st: Add ports-implemented property in support
  ahci: qoriq: enable snoopable sata read and write
  ahci: qoriq: adjust sata parameter
  libata-scsi: fix MODE SELECT translation for Control mode page
  libata-scsi: use u8 array to store mode page copy
parents b56061b0 1ce788d2
......@@ -502,10 +502,11 @@ usb2: usb3@3100000 {
};
sata: sata@3200000 {
compatible = "fsl,ls1043a-ahci", "fsl,ls1021a-ahci";
compatible = "fsl,ls1043a-ahci";
reg = <0x0 0x3200000 0x0 0x10000>;
interrupts = <0 69 0x4>;
clocks = <&clockgen 4 0>;
dma-coherent;
};
msi1: msi-controller1@1571000 {
......
......@@ -683,6 +683,7 @@ sata0: sata@3200000 {
reg = <0x0 0x3200000 0x0 0x10000>;
interrupts = <0 133 0x4>; /* Level high type */
clocks = <&clockgen 4 3>;
dma-coherent;
};
sata1: sata@3210000 {
......@@ -691,6 +692,7 @@ sata1: sata@3210000 {
reg = <0x0 0x3210000 0x0 0x10000>;
interrupts = <0 136 0x4>; /* Level high type */
clocks = <&clockgen 4 3>;
dma-coherent;
};
usb0: usb3@3100000 {
......
#ifndef __ASM_IA64_LIBATA_PORTMAP_H
#define __ASM_IA64_LIBATA_PORTMAP_H
#define ATA_PRIMARY_CMD 0x1F0
#define ATA_PRIMARY_CTL 0x3F6
#define ATA_PRIMARY_IRQ(dev) isa_irq_to_vector(14)
#define ATA_SECONDARY_CMD 0x170
#define ATA_SECONDARY_CTL 0x376
#define ATA_SECONDARY_IRQ(dev) isa_irq_to_vector(15)
#endif
#ifndef __ASM_POWERPC_LIBATA_PORTMAP_H
#define __ASM_POWERPC_LIBATA_PORTMAP_H
#define ATA_PRIMARY_CMD 0x1F0
#define ATA_PRIMARY_CTL 0x3F6
#define ATA_PRIMARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 0)
#define ATA_SECONDARY_CMD 0x170
#define ATA_SECONDARY_CTL 0x376
#define ATA_SECONDARY_IRQ(dev) pci_get_legacy_ide_irq(dev, 1)
#endif
......@@ -1400,142 +1400,56 @@ static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
}
#endif
/*
* ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
* to single msi.
*/
static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv, unsigned long flags)
static int ahci_get_irq_vector(struct ata_host *host, int port)
{
int nvec, i, rc;
/* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
return -ENODEV;
nvec = pci_msix_vec_count(pdev);
if (nvec < 0)
return nvec;
/*
* Proper MSI-X implementations will have a vector per-port.
* Barring that, we prefer single-MSI over single-MSIX. If this
* check fails (not enough MSI-X vectors for all ports) we will
* be called again with the flag clear iff ahci_init_msi()
* fails.
*/
if (flags & AHCI_HFLAG_MULTI_MSIX) {
if (nvec < n_ports)
return -ENODEV;
nvec = n_ports;
} else if (nvec) {
nvec = 1;
} else {
/*
* Emit dev_err() since this was the non-legacy irq
* method of last resort.
*/
rc = -ENODEV;
goto fail;
}
for (i = 0; i < nvec; i++)
hpriv->msix[i].entry = i;
rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
if (rc < 0)
goto fail;
if (nvec > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSIX;
hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */
return nvec;
fail:
dev_err(&pdev->dev,
"failed to enable MSI-X with error %d, # of vectors: %d\n",
rc, nvec);
return rc;
return pci_irq_vector(to_pci_dev(host->dev), port);
}
static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
int rc, nvec;
int nvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
return -ENODEV;
nvec = pci_msi_vec_count(pdev);
if (nvec < 0)
return nvec;
/*
* If number of MSIs is less than number of ports then Sharing Last
* Message mode could be enforced. In this case assume that advantage
* of multipe MSIs is negated and use single MSI mode instead.
*/
if (nvec < n_ports)
goto single_msi;
rc = pci_enable_msi_exact(pdev, nvec);
if (rc == -ENOSPC)
goto single_msi;
if (rc < 0)
return rc;
nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX,
PCI_IRQ_MSIX | PCI_IRQ_MSI);
if (nvec > 0) {
if (!(readl(hpriv->mmio + HOST_CTL) & HOST_MRSM)) {
hpriv->get_irq_vector = ahci_get_irq_vector;
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
return nvec;
}
/* fallback to single MSI mode if the controller enforced MRSM mode */
if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
pci_disable_msi(pdev);
/*
* Fallback to single MSI mode if the controller enforced MRSM
* mode.
*/
printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
goto single_msi;
pci_free_irq_vectors(pdev);
}
if (nvec > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
goto out;
single_msi:
nvec = 1;
rc = pci_enable_msi(pdev);
if (rc < 0)
return rc;
out:
hpriv->irq = pdev->irq;
return nvec;
}
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{
int nvec;
/*
* Try to enable per-port MSI-X. If the host is not capable
* fall back to single MSI before finally attempting single
* MSI-X.
* -ENOSPC indicated we don't have enough vectors. Don't bother trying
* a single vectors for any other error:
*/
nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX);
if (nvec >= 0)
if (nvec < 0 && nvec != -ENOSPC)
return nvec;
nvec = ahci_init_msi(pdev, n_ports, hpriv);
if (nvec >= 0)
return nvec;
/* try single-msix */
nvec = ahci_init_msix(pdev, n_ports, hpriv, 0);
if (nvec >= 0)
/*
* If the host is not capable of supporting per-port vectors, fall
* back to single MSI before finally attempting single MSI-X.
*/
nvec = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
if (nvec == 1)
return nvec;
/* legacy intx interrupts */
pci_intx(pdev, 1);
hpriv->irq = pdev->irq;
return 0;
return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
}
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
......@@ -1698,11 +1612,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!host)
return -ENOMEM;
host->private_data = hpriv;
hpriv->msix = devm_kzalloc(&pdev->dev,
sizeof(struct msix_entry) * n_ports, GFP_KERNEL);
if (!hpriv->msix)
return -ENOMEM;
ahci_init_interrupts(pdev, n_ports, hpriv);
if (ahci_init_msi(pdev, n_ports, hpriv) < 0) {
/* legacy intx interrupts */
pci_intx(pdev, 1);
}
hpriv->irq = pdev->irq;
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN;
......
......@@ -242,12 +242,10 @@ enum {
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
#ifdef CONFIG_PCI_MSI
AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */
AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */
AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */
#else
/* compile out MSI infrastructure */
AHCI_HFLAG_MULTI_MSI = 0,
AHCI_HFLAG_MULTI_MSIX = 0,
#endif
AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
......@@ -351,7 +349,6 @@ struct ahci_host_priv {
* the PHY position in this array.
*/
struct phy **phys;
struct msix_entry *msix; /* Optional MSI-X support */
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
......@@ -362,22 +359,11 @@ struct ahci_host_priv {
*/
void (*start_engine)(struct ata_port *ap);
irqreturn_t (*irq_handler)(int irq, void *dev_instance);
};
#ifdef CONFIG_PCI_MSI
static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
{
if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX)
return hpriv->msix[port].vector;
else
return hpriv->irq + port;
}
#else
static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
{
return hpriv->irq;
}
#endif
/* only required for per-port MSI(-X) support */
int (*get_irq_vector)(struct ata_host *host,
int port);
};
extern int ahci_ignore_sss;
......
......@@ -30,24 +30,23 @@
#define PORT_PHY3 0xB0
#define PORT_PHY4 0xB4
#define PORT_PHY5 0xB8
#define PORT_AXICC 0xBC
#define PORT_TRANS 0xC8
/* port register default value */
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
#define AHCI_PORT_TRANS_CFG 0x08000029
#define AHCI_PORT_AXICC_CFG 0x3fffffff
/* for ls1021a */
#define LS1021A_PORT_PHY2 0x28183414
#define LS1021A_PORT_PHY3 0x0e080e06
#define LS1021A_PORT_PHY4 0x064a080b
#define LS1021A_PORT_PHY5 0x2aa86470
#define LS1021A_AXICC_ADDR 0xC0
#define SATA_ECC_DISABLE 0x00020000
/* for ls1043a */
#define LS1043A_PORT_PHY2 0x28184d1f
#define LS1043A_PORT_PHY3 0x0e081509
enum ahci_qoriq_type {
AHCI_LS1021A,
AHCI_LS1043A,
......@@ -137,7 +136,7 @@ static struct ata_port_operations ahci_qoriq_ops = {
.hardreset = ahci_qoriq_hardreset,
};
static struct ata_port_info ahci_qoriq_port_info = {
static const struct ata_port_info ahci_qoriq_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
......@@ -162,18 +161,19 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR);
break;
case AHCI_LS1043A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(LS1043A_PORT_PHY2, reg_base + PORT_PHY2);
writel(LS1043A_PORT_PHY3, reg_base + PORT_PHY3);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
case AHCI_LS2080A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
}
......@@ -221,12 +221,6 @@ static int ahci_qoriq_probe(struct platform_device *pdev)
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)
......
......@@ -147,6 +147,7 @@ static struct scsi_host_template ahci_platform_sht = {
static int st_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct st_ahci_drv_data *drv_data;
struct ahci_host_priv *hpriv;
int err;
......@@ -170,6 +171,9 @@ static int st_ahci_probe(struct platform_device *pdev)
st_ahci_configure_oob(hpriv->mmio);
of_property_read_u32(dev->of_node,
"ports-implemented", &hpriv->force_port_map);
err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
&ahci_platform_sht);
if (err) {
......
......@@ -2520,7 +2520,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host,
*/
for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data;
int irq = ahci_irq_vector(hpriv, i);
int irq = hpriv->get_irq_vector(host, i);
/* Do not receive interrupts sent by dummy ports */
if (!pp) {
......@@ -2556,10 +2556,15 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
int irq = hpriv->irq;
int rc;
if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
if (hpriv->irq_handler)
dev_warn(host->dev,
"both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n");
if (!hpriv->get_irq_vector) {
dev_err(host->dev,
"AHCI_HFLAG_MULTI_MSI requires ->get_irq_vector!\n");
return -EIO;
}
rc = ahci_host_activate_multi_irqs(host, sht);
} else {
......
This diff is collapsed.
......@@ -347,10 +347,8 @@ static int at91sam9_smc_fields_init(struct device *dev)
field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC);
fields.mode = devm_regmap_field_alloc(dev, smc, field);
if (IS_ERR(fields.mode))
return PTR_ERR(fields.mode);
return 0;
return PTR_ERR_OR_ZERO(fields.mode);
}
static int pata_at91_probe(struct platform_device *pdev)
......
......@@ -152,8 +152,7 @@ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev)
div = 8;
T = (int)((1000000000000LL * div) / octeon_get_io_clock_rate());
if (ata_timing_compute(dev, dev->pio_mode, &timing, T, T))
BUG();
BUG_ON(ata_timing_compute(dev, dev->pio_mode, &timing, T, T));
t1 = timing.setup;
if (t1)
......
......@@ -1727,15 +1727,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)
......
#ifndef __ASM_GENERIC_LIBATA_PORTMAP_H
#define __ASM_GENERIC_LIBATA_PORTMAP_H
#define ATA_PRIMARY_IRQ(dev) 14
#define ATA_SECONDARY_IRQ(dev) 15
#endif
......@@ -105,6 +105,7 @@ enum {
ATA_ID_CFA_KEY_MGMT = 162,
ATA_ID_CFA_MODES = 163,
ATA_ID_DATA_SET_MGMT = 169,
ATA_ID_SCT_CMD_XPORT = 206,
ATA_ID_ROT_SPEED = 217,
ATA_ID_PIO4 = (1 << 1),
......@@ -788,6 +789,48 @@ static inline bool ata_id_sense_reporting_enabled(const u16 *id)
return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
}
/**
*
* Word: 206 - SCT Command Transport
* 15:12 - Vendor Specific
* 11:6 - Reserved
* 5 - SCT Command Transport Data Tables supported
* 4 - SCT Command Transport Features Control supported
* 3 - SCT Command Transport Error Recovery Control supported
* 2 - SCT Command Transport Write Same supported
* 1 - SCT Command Transport Long Sector Access supported
* 0 - SCT Command Transport supported
*/
static inline bool ata_id_sct_data_tables(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 5) ? true : false;
}
static inline bool ata_id_sct_features_ctrl(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 4) ? true : false;
}
static inline bool ata_id_sct_error_recovery_ctrl(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 3) ? true : false;
}
static inline bool ata_id_sct_write_same(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 2) ? true : false;
}
static inline bool ata_id_sct_long_sector_access(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 1) ? true : false;
}
static inline bool ata_id_sct_supported(const u16 *id)
{
return id[ATA_ID_SCT_CMD_XPORT] & (1 << 0) ? true : false;
}
/**
* ata_id_major_version - get ATA level of drive
* @id: Identify data
......@@ -1071,32 +1114,6 @@ static inline void ata_id_to_hd_driveid(u16 *id)
#endif
}
/*
* Write LBA Range Entries to the buffer that will cover the extent from
* sector to sector + count. This is used for TRIM and for ADD LBA(S)
* TO NV CACHE PINNED SET.
*/
static inline unsigned ata_set_lba_range_entries(void *_buffer,
unsigned num, u64 sector, unsigned long count)
{
__le64 *buffer = _buffer;
unsigned i = 0, used_bytes;
while (i < num) {
u64 entry = sector |
((u64)(count > 0xffff ? 0xffff : count) << 48);
buffer[i++] = __cpu_to_le64(entry);
if (count <= 0xffff)
break;
count -= 0xffff;
sector += 0xffff;
}
used_bytes = ALIGN(i * 8, 512);
memset(buffer + i, 0, used_bytes - i * 8);
return used_bytes;
}
static inline bool ata_ok(u8 status)
{
return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
......
......@@ -46,7 +46,8 @@
#ifdef CONFIG_ATA_NONSTANDARD
#include <asm/libata-portmap.h>
#else
#include <asm-generic/libata-portmap.h>
#define ATA_PRIMARY_IRQ(dev) 14
#define ATA_SECONDARY_IRQ(dev) 15
#endif
/*
......
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