From 3c387730ef2639811306c631e820711a70b98c5d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 10 Dec 2008 14:07:22 +0100 Subject: [libata] ata_piix: cleanup dmi strings checking Commit ATA: piix, fix pointer deref on suspend fixed a possible oops in an ugly manner. Use newly introduced dmi_match() to make the code pretty again. Signed-off-by: Jiri Slaby Cc: Alexandru Romanescu Cc: Tejun Heo Cc: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/ata/ata_piix.c') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index c11936e13dd..5fdf1678d0c 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1072,20 +1072,13 @@ static int piix_broken_suspend(void) * matching is necessary because dmi_system_id.matches is * limited to four entries. */ - if (dmi_get_system_info(DMI_SYS_VENDOR) && - dmi_get_system_info(DMI_PRODUCT_NAME) && - dmi_get_system_info(DMI_PRODUCT_VERSION) && - dmi_get_system_info(DMI_PRODUCT_SERIAL) && - dmi_get_system_info(DMI_BOARD_VENDOR) && - dmi_get_system_info(DMI_BOARD_NAME) && - dmi_get_system_info(DMI_BOARD_VERSION) && - !strcmp(dmi_get_system_info(DMI_SYS_VENDOR), "TOSHIBA") && - !strcmp(dmi_get_system_info(DMI_PRODUCT_NAME), "000000") && - !strcmp(dmi_get_system_info(DMI_PRODUCT_VERSION), "000000") && - !strcmp(dmi_get_system_info(DMI_PRODUCT_SERIAL), "000000") && - !strcmp(dmi_get_system_info(DMI_BOARD_VENDOR), "TOSHIBA") && - !strcmp(dmi_get_system_info(DMI_BOARD_NAME), "Portable PC") && - !strcmp(dmi_get_system_info(DMI_BOARD_VERSION), "Version A0")) + if (dmi_match(DMI_SYS_VENDOR, "TOSHIBA") && + dmi_match(DMI_PRODUCT_NAME, "000000") && + dmi_match(DMI_PRODUCT_VERSION, "000000") && + dmi_match(DMI_PRODUCT_SERIAL, "000000") && + dmi_match(DMI_BOARD_VENDOR, "TOSHIBA") && + dmi_match(DMI_BOARD_NAME, "Portable PC") && + dmi_match(DMI_BOARD_VERSION, "Version A0")) return 1; return 0; -- cgit v1.2.3-70-g09d2 From 2852bcf7c12d3027c5d10f4f5ca5fada24ce8088 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 2 Jan 2009 12:04:48 +0900 Subject: ata_piix: save, use saved and restore IOCFG Certain ACPI implementations mess up IOCFG on _STM making libata detect cable type incorrectly after a suspend/resume cycle. This patch makes ata_piix save IOCFG on attach, use the saved value for things which aren't dynamic and restore it on detach so that the next driver also gets the BIOS initialized value. This patch contains the following changes. * makes ich_pata_cable_detect() use saved_iocfg. * make piix_iocfg_bit18_quirk() take @host and use saved_iocfg. * hpriv allocation moved upwards to save iocfg before doing anything else. This fixes bz#11879. Andreas Mohr reported and diagnosed the problem. Signed-off-by: Tejun Heo Cc: Andreas Mohr Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) (limited to 'drivers/ata/ata_piix.c') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 5fdf1678d0c..78659546130 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -154,11 +154,13 @@ struct piix_map_db { struct piix_host_priv { const int *map; + u32 saved_iocfg; void __iomem *sidpr; }; static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void piix_remove_one(struct pci_dev *pdev); static int piix_pata_prereset(struct ata_link *link, unsigned long deadline); static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev); static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); @@ -296,7 +298,7 @@ static struct pci_driver piix_pci_driver = { .name = DRV_NAME, .id_table = piix_pci_tbl, .probe = piix_init_one, - .remove = ata_pci_remove_one, + .remove = piix_remove_one, #ifdef CONFIG_PM .suspend = piix_pci_device_suspend, .resume = piix_pci_device_resume, @@ -610,8 +612,9 @@ static const struct ich_laptop ich_laptop[] = { static int ich_pata_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct piix_host_priv *hpriv = ap->host->private_data; const struct ich_laptop *lap = &ich_laptop[0]; - u8 tmp, mask; + u8 mask; /* Check for specials - Acer Aspire 5602WLMi */ while (lap->device) { @@ -625,8 +628,7 @@ static int ich_pata_cable_detect(struct ata_port *ap) /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; - pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); - if ((tmp & mask) == 0) + if ((hpriv->saved_iocfg & mask) == 0) return ATA_CBL_PATA40; return ATA_CBL_PATA80; } @@ -1350,7 +1352,7 @@ static int __devinit piix_init_sidpr(struct ata_host *host) return 0; } -static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) +static void piix_iocfg_bit18_quirk(struct ata_host *host) { static const struct dmi_system_id sysids[] = { { @@ -1367,7 +1369,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) { } /* terminate list */ }; - u32 iocfg; + struct pci_dev *pdev = to_pci_dev(host->dev); + struct piix_host_priv *hpriv = host->private_data; if (!dmi_check_system(sysids)) return; @@ -1376,12 +1379,11 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) * seem to use it to disable a channel. Clear the bit on the * affected systems. */ - pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg); - if (iocfg & (1 << 18)) { + if (hpriv->saved_iocfg & (1 << 18)) { dev_printk(KERN_INFO, &pdev->dev, "applying IOCFG bit18 quirk\n"); - iocfg &= ~(1 << 18); - pci_write_config_dword(pdev, PIIX_IOCFG, iocfg); + pci_write_config_dword(pdev, PIIX_IOCFG, + hpriv->saved_iocfg & ~(1 << 18)); } } @@ -1430,6 +1432,17 @@ static int __devinit piix_init_one(struct pci_dev *pdev, if (rc) return rc; + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + /* Save IOCFG, this will be used for cable detection, quirk + * detection and restoration on detach. This is necessary + * because some ACPI implementations mess up cable related + * bits on _STM. Reported on kernel bz#11879. + */ + pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg); + /* ICH6R may be driven by either ata_piix or ahci driver * regardless of BIOS configuration. Make sure AHCI mode is * off. @@ -1441,10 +1454,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } /* SATA map init can change port_info, do it before prepping host */ - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) - return -ENOMEM; - if (port_flags & ATA_FLAG_SATA) hpriv->map = piix_init_sata_map(pdev, port_info, piix_map_db_table[ent->driver_data]); @@ -1463,7 +1472,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } /* apply IOCFG bit18 quirk */ - piix_iocfg_bit18_quirk(pdev); + piix_iocfg_bit18_quirk(host); /* On ICH5, some BIOSen disable the interrupt using the * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. @@ -1488,6 +1497,16 @@ static int __devinit piix_init_one(struct pci_dev *pdev, return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); } +static void piix_remove_one(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct piix_host_priv *hpriv = host->private_data; + + pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg); + + ata_pci_remove_one(pdev); +} + static int __init piix_init(void) { int rc; -- cgit v1.2.3-70-g09d2 From 871af1210f13966ab911ed2166e4ab2ce775b99d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 5 Jan 2009 14:16:39 +0000 Subject: libata: Add 32bit PIO support This matters for some controllers and in one or two cases almost doubles PIO performance. Add a bmdma32 operations set we can inherit and activate it for some controllers Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 2 +- drivers/ata/libata-sff.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/pata_ali.c | 6 +++--- drivers/ata/pata_amd.c | 4 ++-- drivers/ata/pata_mpiix.c | 3 ++- drivers/ata/pata_sil680.c | 4 ++-- include/linux/libata.h | 3 +++ 7 files changed, 66 insertions(+), 9 deletions(-) (limited to 'drivers/ata/ata_piix.c') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 78659546130..887d8f46a28 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -310,7 +310,7 @@ static struct scsi_host_template piix_sht = { }; static struct ata_port_operations piix_pata_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9033d164c4e..b58549fac46 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -78,6 +78,13 @@ const struct ata_port_operations ata_bmdma_port_ops = { .bmdma_status = ata_bmdma_status, }; +const struct ata_port_operations ata_bmdma32_port_ops = { + .inherits = &ata_bmdma_port_ops, + + .sff_data_xfer = ata_sff_data_xfer32, +}; +EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops); + /** * ata_fill_sg - Fill PCI IDE PRD table * @qc: Metadata associated with taskfile to be transferred @@ -718,6 +725,52 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, return words << 1; } +/** + * ata_sff_data_xfer32 - Transfer data by PIO + * @dev: device to target + * @buf: data buffer + * @buflen: buffer length + * @rw: read/write + * + * Transfer data from/to the device data register by PIO using 32bit + * I/O operations. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * Bytes consumed. + */ + +unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_port *ap = dev->link->ap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 2; + int slop = buflen & 3; + + /* Transfer multiple of 4 bytes */ + if (rw == READ) + ioread32_rep(data_addr, buf, words); + else + iowrite32_rep(data_addr, buf, words); + + if (unlikely(slop)) { + __le32 pad; + if (rw == READ) { + pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); + } else { + memcpy(&pad, buf + buflen - slop, slop); + iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); + } + words++; + } + return words << 2; +} +EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); + /** * ata_sff_data_xfer_noirq - Transfer data by PIO * @dev: device to target diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index a4f9e39442c..a7999c19f0c 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -151,8 +151,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o pci_read_config_byte(pdev, pio_fifo, &fifo); fifo &= ~(0x0F << shift); - if (on) - fifo |= (on << shift); + fifo |= (on << shift); pci_write_config_byte(pdev, pio_fifo, fifo); } @@ -370,10 +369,11 @@ static struct ata_port_operations ali_early_port_ops = { .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = ali_set_piomode, + .sff_data_xfer = ata_sff_data_xfer32, }; static const struct ata_port_operations ali_dma_base_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, }; diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 0ec9c7d9fe9..63719ab9ea4 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -24,7 +24,7 @@ #include #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.10" +#define DRV_VERSION "0.3.11" /** * timing_setup - shared timing computation and load @@ -345,7 +345,7 @@ static struct scsi_host_template amd_sht = { }; static const struct ata_port_operations amd_base_port_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .prereset = amd_pre_reset, }; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 7c8faa48b5f..aa576cac4d1 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.6" +#define DRV_VERSION "0.7.7" enum { IDETIM = 0x6C, /* IDE control register */ @@ -146,6 +146,7 @@ static struct ata_port_operations mpiix_port_ops = { .cable_detect = ata_cable_40wire, .set_piomode = mpiix_set_piomode, .prereset = mpiix_pre_reset, + .sff_data_xfer = ata_sff_data_xfer32, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 83580a59db5..9e764e5747e 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -32,7 +32,7 @@ #include #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.4.8" +#define DRV_VERSION "0.4.9" #define SIL680_MMIO_BAR 5 @@ -195,7 +195,7 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .cable_detect = sil680_cable_detect, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, diff --git a/include/linux/libata.h b/include/linux/libata.h index 3449de597ef..4f7c8fb4d3f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1518,6 +1518,7 @@ extern void sata_pmp_error_handler(struct ata_port *ap); extern const struct ata_port_operations ata_sff_port_ops; extern const struct ata_port_operations ata_bmdma_port_ops; +extern const struct ata_port_operations ata_bmdma32_port_ops; /* PIO only, sg_tablesize and dma_boundary limits can be removed */ #define ATA_PIO_SHT(drv_name) \ @@ -1545,6 +1546,8 @@ extern void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw); +extern unsigned int ata_sff_data_xfer32(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw); extern unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, unsigned int buflen, int rw); extern u8 ata_sff_irq_on(struct ata_port *ap); -- cgit v1.2.3-70-g09d2