Commit 2ba14a01 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev

* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev: (67 commits)
  fix drivers/ata/sata_fsl.c double-decl
  [libata] Prefer SCSI_SENSE_BUFFERSIZE to sizeof()
  pata_legacy: Merge winbond support
  ata_generic: Cenatek support
  pata_winbond: error return
  pata_serverworks: Fix cable types and cosmetics
  pata_mpc52xx: remove un-needed assignment
  libata: fix off-by-one in error categorization
  ahci: factor out AHCI enabling and enable AHCI before reading CAP
  ata_piix: implement SIDPR SCR access
  ata_piix: convert to prepare - activate initialization
  libata: factor out ata_pci_activate_sff_host() from ata_pci_one()
  [libata] Prefer SCSI_SENSE_BUFFERSIZE to sizeof()
  pata_legacy: resychronize with upstream changes and resubmit
  [libata] pata_legacy: typo fix
  [libata] pata_winbond: update for new ->data_xfer hook
  pata_pcmcia: convert to new data_xfer prototype
  libata annotations and fixes
  libata: use dev_driver_string() instead of "libata" in libata-sff.c
  ata_piix: kill unused constants and flags
  ...
parents 99f1c97d a984f58d
......@@ -459,6 +459,15 @@ config PATA_NETCELL
If unsure, say N.
config PATA_NINJA32
tristate "Ninja32/Delkin Cardbus ATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the Ninja32, Delkin and
possibly other brands of Cardbus ATA adapter
If unsure, say N.
config PATA_NS87410
tristate "Nat Semi NS87410 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
......
......@@ -41,6 +41,7 @@ obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
......
......@@ -198,18 +198,18 @@ enum {
};
struct ahci_cmd_hdr {
u32 opts;
u32 status;
u32 tbl_addr;
u32 tbl_addr_hi;
u32 reserved[4];
__le32 opts;
__le32 status;
__le32 tbl_addr;
__le32 tbl_addr_hi;
__le32 reserved[4];
};
struct ahci_sg {
u32 addr;
u32 addr_hi;
u32 reserved;
u32 flags_size;
__le32 addr;
__le32 addr_hi;
__le32 reserved;
__le32 flags_size;
};
struct ahci_host_priv {
......@@ -597,6 +597,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
return __ahci_port_base(ap->host, ap->port_no);
}
static void ahci_enable_ahci(void __iomem *mmio)
{
u32 tmp;
/* turn on AHCI_EN */
tmp = readl(mmio + HOST_CTL);
if (!(tmp & HOST_AHCI_EN)) {
tmp |= HOST_AHCI_EN;
writel(tmp, mmio + HOST_CTL);
tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
WARN_ON(!(tmp & HOST_AHCI_EN));
}
}
/**
* ahci_save_initial_config - Save and fixup initial config values
* @pdev: target PCI device
......@@ -619,6 +633,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
u32 cap, port_map;
int i;
/* make sure AHCI mode is enabled before accessing CAP */
ahci_enable_ahci(mmio);
/* Values prefixed with saved_ are written back to host after
* reset. Values without are used for driver operation.
*/
......@@ -1036,19 +1053,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
static int ahci_reset_controller(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 tmp;
/* we must be in AHCI mode, before using anything
* AHCI-specific, such as HOST_RESET.
*/
tmp = readl(mmio + HOST_CTL);
if (!(tmp & HOST_AHCI_EN)) {
tmp |= HOST_AHCI_EN;
writel(tmp, mmio + HOST_CTL);
}
ahci_enable_ahci(mmio);
/* global controller reset */
tmp = readl(mmio + HOST_CTL);
if ((tmp & HOST_RESET) == 0) {
writel(tmp | HOST_RESET, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
......@@ -1067,8 +1082,7 @@ static int ahci_reset_controller(struct ata_host *host)
}
/* turn on AHCI mode */
writel(HOST_AHCI_EN, mmio + HOST_CTL);
(void) readl(mmio + HOST_CTL); /* flush */
ahci_enable_ahci(mmio);
/* some registers might be cleared on reset. restore initial values */
ahci_restore_initial_config(host);
......@@ -1078,8 +1092,10 @@ static int ahci_reset_controller(struct ata_host *host)
/* configure PCS */
pci_read_config_word(pdev, 0x92, &tmp16);
tmp16 |= 0xf;
pci_write_config_word(pdev, 0x92, tmp16);
if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
tmp16 |= hpriv->port_map;
pci_write_config_word(pdev, 0x92, tmp16);
}
}
return 0;
......@@ -1480,35 +1496,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{
struct scatterlist *sg;
struct ahci_sg *ahci_sg;
unsigned int n_sg = 0;
struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
unsigned int si;
VPRINTK("ENTER\n");
/*
* Next, the S/G list.
*/
ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
ata_for_each_sg(sg, qc) {
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);
ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
ahci_sg++;
n_sg++;
ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
}
return n_sg;
return si;
}
static void ahci_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
int is_atapi = is_atapi_taskfile(&qc->tf);
int is_atapi = ata_is_atapi(qc->tf.protocol);
void *cmd_tbl;
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
......
......@@ -26,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_generic"
#define DRV_VERSION "0.2.13"
#define DRV_VERSION "0.2.15"
/*
* A generic parallel ATA driver using libata
......@@ -48,27 +48,47 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
struct ata_port *ap = link->ap;
int dma_enabled = 0;
struct ata_device *dev;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
dma_enabled = 0xFF;
ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
if (dma_enabled & (1 << (5 + dev->devno))) {
ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
if (!ata_dev_enabled(dev))
continue;
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
if (dma_enabled & (1 << (5 + dev->devno))) {
unsigned int xfer_mask = ata_id_xfermask(dev->id);
const char *name;
if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA))
name = ata_mode_string(xfer_mask);
else {
/* SWDMA perhaps? */
name = "DMA";
xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0);
}
ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
name);
dev->xfer_mode = ata_xfer_mask2mode(xfer_mask);
dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
}
}
return 0;
......@@ -185,6 +205,7 @@ static struct pci_device_id ata_generic[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), },
{ PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
{ PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
......
......@@ -101,39 +101,21 @@ enum {
ICH5_PMR = 0x90, /* port mapping register */
ICH5_PCS = 0x92, /* port control and status */
PIIX_SCC = 0x0A, /* sub-class code register */
PIIX_SIDPR_BAR = 5,
PIIX_SIDPR_LEN = 16,
PIIX_SIDPR_IDX = 0,
PIIX_SIDPR_DATA = 4,
PIIX_FLAG_SCR = (1 << 26), /* SCR available */
PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
PIIX_FLAG_SIDPR = (1 << 29), /* SATA idx/data pair regs */
PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS,
PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
/* combined mode. if set, PATA is channel 0.
* if clear, PATA is channel 1.
*/
PIIX_PORT_ENABLED = (1 << 0),
PIIX_PORT_PRESENT = (1 << 4),
PIIX_80C_PRI = (1 << 5) | (1 << 4),
PIIX_80C_SEC = (1 << 7) | (1 << 6),
/* controller IDs */
piix_pata_mwdma = 0, /* PIIX3 MWDMA only */
piix_pata_33, /* PIIX4 at 33Mhz */
ich_pata_33, /* ICH up to UDMA 33 only */
ich_pata_66, /* ICH up to 66 Mhz */
ich_pata_100, /* ICH up to UDMA 100 */
ich5_sata,
ich6_sata,
ich6_sata_ahci,
ich6m_sata_ahci,
ich8_sata_ahci,
ich8_2port_sata,
ich8m_apple_sata_ahci, /* locks up on second port enable */
tolapai_sata_ahci,
piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */
/* constants for mapping table */
P0 = 0, /* port 0 */
P1 = 1, /* port 1 */
......@@ -149,6 +131,24 @@ enum {
PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
};
enum piix_controller_ids {
/* controller IDs */
piix_pata_mwdma, /* PIIX3 MWDMA only */
piix_pata_33, /* PIIX4 at 33Mhz */
ich_pata_33, /* ICH up to UDMA 33 only */
ich_pata_66, /* ICH up to 66 Mhz */
ich_pata_100, /* ICH up to UDMA 100 */
ich5_sata,
ich6_sata,
ich6_sata_ahci,
ich6m_sata_ahci,
ich8_sata_ahci,
ich8_2port_sata,
ich8m_apple_sata_ahci, /* locks up on second port enable */
tolapai_sata_ahci,
piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */
};
struct piix_map_db {
const u32 mask;
const u16 port_enable;
......@@ -157,6 +157,7 @@ struct piix_map_db {
struct piix_host_priv {
const int *map;
void __iomem *sidpr;
};
static int piix_init_one(struct pci_dev *pdev,
......@@ -167,6 +168,9 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static int ich_pata_cable_detect(struct ata_port *ap);
static u8 piix_vmw_bmdma_status(struct ata_port *ap);
static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
static void piix_sidpr_error_handler(struct ata_port *ap);
#ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int piix_pci_device_resume(struct pci_dev *pdev);
......@@ -321,7 +325,6 @@ static const struct ata_port_operations piix_pata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.cable_detect = ata_cable_40wire,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
......@@ -353,7 +356,6 @@ static const struct ata_port_operations ich_pata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.cable_detect = ich_pata_cable_detect,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
......@@ -380,7 +382,6 @@ static const struct ata_port_operations piix_sata_ops = {
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
......@@ -419,6 +420,35 @@ static const struct ata_port_operations piix_vmw_ops = {
.port_start = ata_port_start,
};
static const struct ata_port_operations piix_sidpr_sata_ops = {
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
.scr_read = piix_sidpr_scr_read,
.scr_write = piix_sidpr_scr_write,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = piix_sidpr_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.port_start = ata_port_start,
};
static const struct piix_map_db ich5_map_db = {
.mask = 0x7,
.port_enable = 0x3,
......@@ -526,7 +556,6 @@ static const struct piix_map_db *piix_map_db_table[] = {
static struct ata_port_info piix_port_info[] = {
[piix_pata_mwdma] = /* PIIX3 MWDMA only */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
......@@ -535,7 +564,6 @@ static struct ata_port_info piix_port_info[] = {
[piix_pata_33] = /* PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
......@@ -545,7 +573,6 @@ static struct ata_port_info piix_port_info[] = {
[ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
.pio_mask = 0x1f, /* pio 0-4 */
.mwdma_mask = 0x06, /* Check: maybe 0x07 */
......@@ -555,7 +582,6 @@ static struct ata_port_info piix_port_info[] = {
[ich_pata_66] = /* ICH controllers up to 66MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
.pio_mask = 0x1f, /* pio 0-4 */
.mwdma_mask = 0x06, /* MWDMA0 is broken on chip */
......@@ -565,7 +591,6 @@ static struct ata_port_info piix_port_info[] = {
[ich_pata_100] =
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x06, /* mwdma1-2 */
......@@ -575,7 +600,6 @@ static struct ata_port_info piix_port_info[] = {
[ich5_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
......@@ -585,8 +609,7 @@ static struct ata_port_info piix_port_info[] = {
[ich6_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
.flags = PIIX_SATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -595,9 +618,7 @@ static struct ata_port_info piix_port_info[] = {
[ich6_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -606,9 +627,7 @@ static struct ata_port_info piix_port_info[] = {
[ich6m_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -617,9 +636,8 @@ static struct ata_port_info piix_port_info[] = {
[ich8_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
PIIX_FLAG_SIDPR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -628,9 +646,8 @@ static struct ata_port_info piix_port_info[] = {
[ich8_2port_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
PIIX_FLAG_SIDPR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -639,9 +656,7 @@ static struct ata_port_info piix_port_info[] = {
[tolapai_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -650,9 +665,8 @@ static struct ata_port_info piix_port_info[] = {
[ich8m_apple_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
PIIX_FLAG_SIDPR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
......@@ -1001,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
do_pata_set_dmamode(ap, adev, 1);
}
/*
* Serial ATA Index/Data Pair Superset Registers access
*
* Beginning from ICH8, there's a sane way to access SCRs using index
* and data register pair located at BAR5. This creates an
* interesting problem of mapping two SCRs to one port.
*
* Although they have separate SCRs, the master and slave aren't
* independent enough to be treated as separate links - e.g. softreset
* resets both. Also, there's no protocol defined for hard resetting
* singled device sharing the virtual port (no defined way to acquire
* device signature). This is worked around by merging the SCR values
* into one sensible value and requesting follow-up SRST after
* hardreset.
*
* SCR merging is perfomed in nibbles which is the unit contents in
* SCRs are organized. If two values are equal, the value is used.
* When they differ, merge table which lists precedence of possible
* values is consulted and the first match or the last entry when
* nothing matches is used. When there's no merge table for the
* specific nibble, value from the first port is used.
*/
static const int piix_sidx_map[] = {
[SCR_STATUS] = 0,
[SCR_ERROR] = 2,
[SCR_CONTROL] = 1,
};
static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
{
struct ata_port *ap = dev->link->ap;
struct piix_host_priv *hpriv = ap->host->private_data;
iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
hpriv->sidpr + PIIX_SIDPR_IDX);
}
static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
{
struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
piix_sidpr_sel(dev, reg);
return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
}
static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
{
struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
piix_sidpr_sel(dev, reg);
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
}
u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
{
u32 val = 0;
int i, mi;
for (i = 0, mi = 0; i < 32 / 4; i++) {
u8 c0 = (val0 >> (i * 4)) & 0xf;
u8 c1 = (val1 >> (i * 4)) & 0xf;
u8 merged = c0;
const int *cur;
/* if no merge preference, assume the first value */
cur = merge_tbl[mi];
if (!cur)
goto done;
mi++;
/* if two values equal, use it */
if (c0 == c1)
goto done;
/* choose the first match or the last from the merge table */
while (*cur != -1) {
if (c0 == *cur || c1 == *cur)
break;
cur++;
}
if (*cur == -1)
cur--;
merged = *cur;
done:
val |= merged << (i * 4);
}
return val;
}
static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
{
const int * const sstatus_merge_tbl[] = {
/* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
/* SPD */ (const int []){ 2, 1, 0, -1 },
/* IPM */ (const int []){ 6, 2, 1, 0, -1 },
NULL,
};
const int * const scontrol_merge_tbl[] = {
/* DET */ (const int []){ 1, 0, 4, 0, -1 },
/* SPD */ (const int []){ 0, 2, 1, 0, -1 },
/* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
NULL,
};
u32 v0, v1;