X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fata%2Fata_piix.c;h=9c2515f67de56c41237ceb20c221a5fa4e5db2a5;hb=11e0704b7ec3abfeaee7e3a56f11c82024d1ae01;hp=6846b5629ed284332b94f72e194d38830903c6a6;hpb=f89b2b5ddcace8959f760c0556369bd19bda0548;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 6846b56..9c2515f 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -40,7 +40,7 @@ * Documentation * Publically available from Intel web site. Errata documentation * is also publically available. As an aide to anyone hacking on this - * driver the list of errata that are relevant is below.going back to + * driver the list of errata that are relevant is below, going back to * PIIX4. Older device documentation is now a bit tricky to find. * * The chipsets all follow very much the same design. The orginal Triton @@ -91,40 +91,31 @@ #include #include #include +#include #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00" +#define DRV_VERSION "2.12" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ 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_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */ - 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 */ - /* 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_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, + PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), - /* controller IDs */ - piix4_pata = 0, - ich5_pata = 1, - ich5_sata = 2, - esb_sata = 3, - ich6_sata = 4, - ich6_sata_ahci = 5, - ich6m_sata_ahci = 6, - ich8_sata_ahci = 7, - /* constants for mapping table */ P0 = 0, /* port 0 */ P1 = 1, /* port 1 */ @@ -135,37 +126,100 @@ enum { RV = -3, /* reserved */ PIIX_AHCI_DEVICE = 6, + + /* host->flags bits */ + 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; - const int present_shift; const int map[][4]; }; struct piix_host_priv { const int *map; - const struct piix_map_db *map_db; + void __iomem *sidpr; }; -static int piix_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent); -static void piix_host_stop(struct ata_host_set *host_set); -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); +static int piix_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent); static void piix_pata_error_handler(struct ata_port *ap); -static void piix_sata_error_handler(struct ata_port *ap); +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); +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); +#endif static unsigned int in_module_init = 1; static const struct pci_device_id piix_pci_tbl[] = { -#ifdef ATA_ENABLE_PATA - { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, - { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, - { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, - { 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, -#endif + /* Intel PIIX3 for the 430HX etc */ + { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma }, + /* VMware ICH4 */ + { 0x8086, 0x7111, 0x15ad, 0x1976, 0, 0, piix_pata_vmw }, + /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ + /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */ + { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, + /* Intel PIIX4 */ + { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, + /* Intel PIIX4 */ + { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, + /* Intel PIIX */ + { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, + /* Intel ICH (i810, i815, i840) UDMA 66*/ + { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 }, + /* Intel ICH0 : UDMA 33*/ + { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 }, + /* Intel ICH2M */ + { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */ + { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH3M */ + { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH3 (E7500/1) UDMA 100 */ + { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */ + { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* Intel ICH5 */ + { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* C-ICH (i810E2) */ + { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ESB (855GME/875P + 6300ESB) UDMA 100 */ + { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ICH6 (and 6) (i915) UDMA 100 */ + { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ICH7/7-R (i945, i975) UDMA 100*/ + { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, + /* ICH8 Mobile PATA Controller */ + { 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* NOTE: The following PCI ids must be kept in sync with the * list in drivers/pci/quirks.c. @@ -176,9 +230,9 @@ static const struct pci_device_id piix_pci_tbl[] = { /* 82801EB (ICH5) */ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB (ICH5 variant with broken PCS present bits) */ - { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 6300ESB pretending RAID */ - { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata }, + { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, /* 82801FB/FW (ICH6/ICH6W) */ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, /* 82801FR/FRW (ICH6R/ICH6RW) */ @@ -189,14 +243,38 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, /* 2801GBM/GHM (ICH7M, identical to ICH6M) */ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci }, - /* Enterprise Southbridge 2 (where's the datasheet?) */ + /* Enterprise Southbridge 2 (631xESB/632xESB) */ { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, - /* SATA Controller 1 IDE (ICH8, no datasheet yet) */ + /* SATA Controller 1 IDE (ICH8) */ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, - /* SATA Controller 2 IDE (ICH8, ditto) */ - { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, - /* Mobile SATA Controller IDE (ICH8M, ditto) */ + /* SATA Controller 2 IDE (ICH8) */ + { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* Mobile SATA Controller IDE (ICH8M) */ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* Mobile SATA Controller IDE (ICH8M), Apple */ + { 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata_ahci }, + /* SATA Controller IDE (ICH9) */ + { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (ICH9) */ + { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH9) */ + { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH9M) */ + { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH9M) */ + { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH9M) */ + { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (Tolapai) */ + { 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, + /* SATA Controller IDE (ICH10) */ + { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; @@ -206,8 +284,10 @@ static struct pci_driver piix_pci_driver = { .id_table = piix_pci_tbl, .probe = piix_init_one, .remove = ata_pci_remove_one, - .suspend = ata_pci_device_suspend, - .resume = ata_pci_device_resume, +#ifdef CONFIG_PM + .suspend = piix_pci_device_suspend, + .resume = piix_pci_device_resume, +#endif }; static struct scsi_host_template piix_sht = { @@ -226,12 +306,9 @@ static struct scsi_host_template piix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, - .resume = ata_scsi_device_resume, - .suspend = ata_scsi_device_suspend, }; static const struct ata_port_operations piix_pata_ops = { - .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, .mode_filter = ata_pci_default_filter, @@ -248,24 +325,52 @@ static const struct ata_port_operations piix_pata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = piix_pata_error_handler, .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, .port_start = ata_port_start, - .port_stop = ata_port_stop, - .host_stop = piix_host_stop, }; -static const struct ata_port_operations piix_sata_ops = { - .port_disable = ata_port_disable, +static const struct ata_port_operations ich_pata_ops = { + .set_piomode = piix_set_piomode, + .set_dmamode = ich_set_dmamode, + .mode_filter = ata_pci_default_filter, + + .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, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = piix_pata_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ich_pata_cable_detect, + + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_port_start, +}; +static const struct ata_port_operations piix_sata_ops = { .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -278,25 +383,83 @@ static const struct ata_port_operations piix_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_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 ata_port_operations piix_vmw_ops = { + .set_piomode = piix_set_piomode, + .set_dmamode = piix_set_dmamode, + .mode_filter = ata_pci_default_filter, + + .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 = piix_vmw_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, - .error_handler = piix_sata_error_handler, + .error_handler = piix_pata_error_handler, .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, + + .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, - .port_stop = ata_port_stop, - .host_stop = piix_host_stop, }; static const struct piix_map_db ich5_map_db = { .mask = 0x7, .port_enable = 0x3, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, NA, P1, NA }, /* 000b */ @@ -313,7 +476,6 @@ static const struct piix_map_db ich5_map_db = { static const struct piix_map_db ich6_map_db = { .mask = 0x3, .port_enable = 0xf, - .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b */ @@ -326,11 +488,15 @@ static const struct piix_map_db ich6_map_db = { static const struct piix_map_db ich6m_map_db = { .mask = 0x3, .port_enable = 0x5, - .present_shift = 4, + + /* Map 01b isn't specified in the doc but some notebooks use + * it anyway. MAP 01b have been spotted on both ICH6M and + * ICH7M. + */ .map = { /* PM PS SM SS MAP */ - { P0, P2, RV, RV }, /* 00b */ - { RV, RV, RV, RV }, + { P0, P2, NA, NA }, /* 00b */ + { IDE, IDE, P1, P3 }, /* 01b */ { P0, P2, IDE, IDE }, /* 10b */ { RV, RV, RV, RV }, }, @@ -338,122 +504,193 @@ static const struct piix_map_db ich6m_map_db = { static const struct piix_map_db ich8_map_db = { .mask = 0x3, + .port_enable = 0xf, + .map = { + /* PM PS SM SS MAP */ + { P0, P2, P1, P3 }, /* 00b (hardwired when in AHCI) */ + { RV, RV, RV, RV }, + { P0, P2, IDE, IDE }, /* 10b (IDE mode) */ + { RV, RV, RV, RV }, + }, +}; + +static const struct piix_map_db ich8_2port_map_db = { + .mask = 0x3, .port_enable = 0x3, - .present_shift = 8, .map = { /* PM PS SM SS MAP */ - { P0, NA, P1, NA }, /* 00b (hardwired) */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ + { RV, RV, RV, RV }, + }, +}; + +static const struct piix_map_db ich8m_apple_map_db = { + .mask = 0x3, + .port_enable = 0x1, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, NA, NA }, /* 00b */ + { RV, RV, RV, RV }, + { P0, P2, IDE, IDE }, /* 10b */ { RV, RV, RV, RV }, - { RV, RV, RV, RV }, /* 10b (never) */ + }, +}; + +static const struct piix_map_db tolapai_map_db = { + .mask = 0x3, + .port_enable = 0x3, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b */ + { RV, RV, RV, RV }, /* 01b */ + { RV, RV, RV, RV }, /* 10b */ { RV, RV, RV, RV }, }, }; static const struct piix_map_db *piix_map_db_table[] = { [ich5_sata] = &ich5_map_db, - [esb_sata] = &ich5_map_db, [ich6_sata] = &ich6_map_db, [ich6_sata_ahci] = &ich6_map_db, [ich6m_sata_ahci] = &ich6m_map_db, [ich8_sata_ahci] = &ich8_map_db, + [ich8_2port_sata] = &ich8_2port_map_db, + [ich8m_apple_sata_ahci] = &ich8m_apple_map_db, + [tolapai_sata_ahci] = &tolapai_map_db, }; static struct ata_port_info piix_port_info[] = { - /* piix4_pata */ + [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS, + .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ -#if 0 - .mwdma_mask = 0x06, /* mwdma1-2 */ -#else - .mwdma_mask = 0x00, /* mwdma broken */ -#endif + .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ + .port_ops = &piix_pata_ops, + }, + + [piix_pata_33] = /* PIIX4 at 33MHz */ + { + .flags = PIIX_PATA_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ .udma_mask = ATA_UDMA_MASK_40C, .port_ops = &piix_pata_ops, }, - /* ich5_pata */ + [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR, + .flags = PIIX_PATA_FLAGS, + .pio_mask = 0x1f, /* pio 0-4 */ + .mwdma_mask = 0x06, /* Check: maybe 0x07 */ + .udma_mask = ATA_UDMA2, /* UDMA33 */ + .port_ops = &ich_pata_ops, + }, + + [ich_pata_66] = /* ICH controllers up to 66MHz */ + { + .flags = PIIX_PATA_FLAGS, + .pio_mask = 0x1f, /* pio 0-4 */ + .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ + .udma_mask = ATA_UDMA4, + .port_ops = &ich_pata_ops, + }, + + [ich_pata_100] = + { + .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ -#if 0 .mwdma_mask = 0x06, /* mwdma1-2 */ -#else - .mwdma_mask = 0x00, /* mwdma broken */ -#endif - .udma_mask = 0x3f, /* udma0-5 */ - .port_ops = &piix_pata_ops, + .udma_mask = ATA_UDMA5, /* udma0-5 */ + .port_ops = &ich_pata_ops, }, - /* ich5_sata */ + [ich5_sata] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, - /* i6300esb_sata */ + [ich6_sata] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, - /* ich6_sata */ + [ich6_sata_ahci] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ - .udma_mask = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, - /* ich6_sata_ahci */ + [ich6m_sata_ahci] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | 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 = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, - /* ich6m_sata_ahci */ + [ich8_sata_ahci] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | 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 = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, - /* ich8_sata_ahci */ + [ich8_2port_sata] = { - .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | - PIIX_FLAG_CHECKINTR | 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 = 0x7f, /* udma0-6 */ + .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, + + [tolapai_sata_ahci] = + { + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA6, + .port_ops = &piix_sata_ops, + }, + + [ich8m_apple_sata_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, + .port_ops = &piix_sata_ops, + }, + + [piix_pata_vmw] = + { + .sht = &piix_sht, + .flags = PIIX_PATA_FLAGS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ + .udma_mask = ATA_UDMA_MASK_40C, + .port_ops = &piix_vmw_ops, + }, + }; static struct pci_bits piix_enable_bits[] = { @@ -467,8 +704,30 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, piix_pci_tbl); MODULE_VERSION(DRV_VERSION); +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */ + { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ + { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ + { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ + /* end marker */ + { 0, } +}; + /** - * piix_pata_cbl_detect - Probe host controller cable detect info + * ich_pata_cable_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired * * Read 80c cable indicator from ATA PCI device's PCI config @@ -477,51 +736,47 @@ MODULE_VERSION(DRV_VERSION); * LOCKING: * None (inherited from caller). */ -static void piix_pata_cbl_detect(struct ata_port *ap) + +static int ich_pata_cable_detect(struct ata_port *ap) { - struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + const struct ich_laptop *lap = &ich_laptop[0]; u8 tmp, mask; - /* no 80c support in host controller? */ - if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0) - goto cbl40; + /* Check for specials - Acer Aspire 5602WLMi */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) + return ATA_CBL_PATA40_SHORT; + + lap++; + } /* 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) - goto cbl40; - - ap->cbl = ATA_CBL_PATA80; - return; - -cbl40: - ap->cbl = ATA_CBL_PATA40; - ap->udma_mask &= ATA_UDMA_MASK_40C; + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; } /** * piix_pata_prereset - prereset for PATA host controller - * @ap: Target port - * - * Prereset including cable detection. + * @link: Target link + * @deadline: deadline jiffies for the operation * * LOCKING: * None (inherited from caller). */ -static int piix_pata_prereset(struct ata_port *ap) +static int piix_pata_prereset(struct ata_link *link, unsigned long deadline) { - struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - - if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) { - ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; - return 0; - } + struct ata_port *ap = link->ap; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); - piix_pata_cbl_detect(ap); - - return ata_std_prereset(ap); + if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) + return -ENOENT; + return ata_std_prereset(link, deadline); } static void piix_pata_error_handler(struct ata_port *ap) @@ -531,87 +786,6 @@ static void piix_pata_error_handler(struct ata_port *ap) } /** - * piix_sata_present_mask - determine present mask for SATA host controller - * @ap: Target port - * - * Reads SATA PCI device's PCI config register Port Configuration - * and Status (PCS) to determine port and device availability. - * - * LOCKING: - * None (inherited from caller). - * - * RETURNS: - * determined present_mask - */ -static unsigned int piix_sata_present_mask(struct ata_port *ap) -{ - struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - struct piix_host_priv *hpriv = ap->host_set->private_data; - const unsigned int *map = hpriv->map; - int base = 2 * ap->port_no; - unsigned int present_mask = 0; - int port, i; - u16 pcs; - - pci_read_config_word(pdev, ICH5_PCS, &pcs); - DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base); - - for (i = 0; i < 2; i++) { - port = map[base + i]; - if (port < 0) - continue; - if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || - (pcs & 1 << (hpriv->map_db->present_shift + port))) - present_mask |= 1 << i; - } - - DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", - ap->id, pcs, present_mask); - - return present_mask; -} - -/** - * piix_sata_softreset - reset SATA host port via ATA SRST - * @ap: port to reset - * @classes: resulting classes of attached devices - * - * Reset SATA host port via ATA SRST. On controllers with - * reliable PCS present bits, the bits are used to determine - * device presence. - * - * LOCKING: - * Kernel thread context (may sleep) - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) -{ - unsigned int present_mask; - int i, rc; - - present_mask = piix_sata_present_mask(ap); - - rc = ata_std_softreset(ap, classes); - if (rc) - return rc; - - for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (!(present_mask & (1 << i))) - classes[i] = ATA_DEV_NONE; - } - - return 0; -} - -static void piix_sata_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, - ata_std_postreset); -} - -/** * piix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um @@ -622,15 +796,22 @@ static void piix_sata_error_handler(struct ata_port *ap) * None (inherited from caller). */ -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) +static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev) { unsigned int pio = adev->pio_mode - XFER_PIO_0; - struct pci_dev *dev = to_pci_dev(ap->host_set->dev); + struct pci_dev *dev = to_pci_dev(ap->host->dev); unsigned int is_slave = (adev->devno != 0); unsigned int master_port= ap->port_no ? 0x42 : 0x40; unsigned int slave_port = 0x44; u16 master_data; u8 slave_data; + u8 udma_enable; + int control = 0; + + /* + * See Intel Document 298600-004 for the timing programing rules + * for ICH controllers. + */ static const /* ISP RTC */ u8 timings[][2] = { { 0, 0 }, @@ -639,20 +820,38 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) { 2, 1 }, { 2, 3 }, }; + if (pio >= 2) + control |= 1; /* TIME1 enable */ + if (ata_pio_need_iordy(adev)) + control |= 2; /* IE enable */ + + /* Intel specifies that the PPE functionality is for disk only */ + if (adev->class == ATA_DEV_ATA) + control |= 4; /* PPE enable */ + + /* PIO configuration clears DTE unconditionally. It will be + * programmed in set_dmamode which is guaranteed to be called + * after set_piomode if any DMA mode is available. + */ pci_read_config_word(dev, master_port, &master_data); if (is_slave) { + /* clear TIME1|IE1|PPE1|DTE1 */ + master_data &= 0xff0f; + /* Enable SITRE (separate slave timing register) */ master_data |= 0x4000; - /* enable PPE, IE and TIME */ - master_data |= 0x0070; + /* enable PPE1, IE1 and TIME1 as needed */ + master_data |= (control << 4); pci_read_config_byte(dev, slave_port, &slave_data); slave_data &= (ap->port_no ? 0x0f : 0xf0); - slave_data |= - (timings[pio][0] << 2) | - (timings[pio][1] << (ap->port_no ? 4 : 0)); + /* Load the timing nibble for this slave */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) + << (ap->port_no ? 4 : 0); } else { - master_data &= 0xccf8; - /* enable PPE, IE and TIME */ - master_data |= 0x0007; + /* clear ISP|RCT|TIME0|IE0|PPE0|DTE0 */ + master_data &= 0xccf0; + /* Enable PPE, IE and TIME as appropriate */ + master_data |= control; + /* load ISP and RCT */ master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); @@ -660,13 +859,23 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) pci_write_config_word(dev, master_port, master_data); if (is_slave) pci_write_config_byte(dev, slave_port, slave_data); + + /* Ensure the UDMA bit is off - it will be turned back on if + UDMA is selected */ + + if (ap->udma_mask) { + pci_read_config_byte(dev, 0x48, &udma_enable); + udma_enable &= ~(1 << (2 * ap->port_no + adev->devno)); + pci_write_config_byte(dev, 0x48, udma_enable); + } } /** - * piix_set_dmamode - Initialize host controller PATA PIO timings + * do_pata_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring - * @adev: um + * @adev: Drive in question * @udma: udma mode, 0 - 6 + * @isich: set if the chip is an ICH device * * Set UDMA mode for device, in host controller PCI config space. * @@ -674,70 +883,517 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) * None (inherited from caller). */ -static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) +static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, int isich) { - unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ - struct pci_dev *dev = to_pci_dev(ap->host_set->dev); - u8 maslave = ap->port_no ? 0x42 : 0x40; - u8 speed = udma; - unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno; - int a_speed = 3 << (drive_dn * 4); - int u_flag = 1 << drive_dn; - int v_flag = 0x01 << drive_dn; - int w_flag = 0x10 << drive_dn; - int u_speed = 0; - int sitre; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; - - pci_read_config_word(dev, maslave, ®4042); - DPRINTK("reg4042 = 0x%04x\n", reg4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); - pci_read_config_byte(dev, 0x55, ®55); - - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break; - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: break; - default: - BUG(); - return; - } + struct pci_dev *dev = to_pci_dev(ap->host->dev); + u8 master_port = ap->port_no ? 0x42 : 0x40; + u16 master_data; + u8 speed = adev->dma_mode; + int devid = adev->devno + 2 * ap->port_no; + u8 udma_enable = 0; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, master_port, &master_data); + if (ap->udma_mask) + pci_read_config_byte(dev, 0x48, &udma_enable); if (speed >= XFER_UDMA_0) { - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); - } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + unsigned int udma = adev->dma_mode - XFER_UDMA_0; + u16 udma_timing; + u16 ideconf; + int u_clock, u_speed; + + /* + * UDMA is handled by a combination of clock switching and + * selection of dividers + * + * Handy rule: Odd modes are UDMATIMx 01, even are 02 + * except UDMA0 which is 00 + */ + u_speed = min(2 - (udma & 1), udma); + if (udma == 5) + u_clock = 0x1000; /* 100Mhz */ + else if (udma > 2) + u_clock = 1; /* 66Mhz */ + else + u_clock = 0; /* 33Mhz */ + + udma_enable |= (1 << devid); + + /* Load the CT/RP selection */ + pci_read_config_word(dev, 0x4A, &udma_timing); + udma_timing &= ~(3 << (4 * devid)); + udma_timing |= u_speed << (4 * devid); + pci_write_config_word(dev, 0x4A, udma_timing); + + if (isich) { + /* Select a 33/66/100Mhz clock */ + pci_read_config_word(dev, 0x54, &ideconf); + ideconf &= ~(0x1001 << devid); + ideconf |= u_clock << devid; + /* For ICH or later we should set bit 10 for better + performance (WR_PingPong_En) */ + pci_write_config_word(dev, 0x54, ideconf); } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { - if (reg48 & u_flag) - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & v_flag) - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - if (reg55 & w_flag) - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + /* + * MWDMA is driven by the PIO timings. We must also enable + * IORDY unconditionally along with TIME1. PPE has already + * been set when the PIO timing was set. + */ + unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; + unsigned int control; + u8 slave_data; + const unsigned int needed_pio[3] = { + XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 + }; + int pio = needed_pio[mwdma] - XFER_PIO_0; + + control = 3; /* IORDY|TIME1 */ + + /* If the drive MWDMA is faster than it can do PIO then + we must force PIO into PIO0 */ + + if (adev->pio_mode < needed_pio[mwdma]) + /* Enable DMA timing only */ + control |= 8; /* PIO cycles in PIO0 */ + + if (adev->devno) { /* Slave */ + master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ + master_data |= control << 4; + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= (ap->port_no ? 0x0f : 0xf0); + /* Load the matching timing */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); + pci_write_config_byte(dev, 0x44, slave_data); + } else { /* Master */ + master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY + and master timing bits */ + master_data |= control; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + + if (ap->udma_mask) { + udma_enable &= ~(1 << devid); + pci_write_config_word(dev, master_port, master_data); + } + } + /* Don't scribble on 0x48 if the controller does not support UDMA */ + if (ap->udma_mask) + pci_write_config_byte(dev, 0x48, udma_enable); +} + +/** + * piix_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set MW/UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + do_pata_set_dmamode(ap, adev, 0); +} + +/** + * ich_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set MW/UDMA mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +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); +} + +static 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; + + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + + if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { + *val = piix_sidpr_read(&ap->link.device[0], reg); + return 0; + } + + v0 = piix_sidpr_read(&ap->link.device[0], reg); + v1 = piix_sidpr_read(&ap->link.device[1], reg); + + switch (reg) { + case SCR_STATUS: + *val = piix_merge_scr(v0, v1, sstatus_merge_tbl); + break; + case SCR_ERROR: + *val = v0 | v1; + break; + case SCR_CONTROL: + *val = piix_merge_scr(v0, v1, scontrol_merge_tbl); + break; + } + + return 0; +} + +static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) +{ + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + + piix_sidpr_write(&ap->link.device[0], reg, val); + + if (ap->flags & ATA_FLAG_SLAVE_POSS) + piix_sidpr_write(&ap->link.device[1], reg, val); + + return 0; +} + +static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + int rc; + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } + + /* TODO: phy layer with polling, timeouts, etc. */ + if (ata_link_offline(link)) { + *class = ATA_DEV_NONE; + return 0; + } + + return -EAGAIN; +} + +static void piix_sidpr_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + piix_sidpr_hardreset, ata_std_postreset); +} + +#ifdef CONFIG_PM +static int piix_broken_suspend(void) +{ + static const struct dmi_system_id sysids[] = { + { + .ident = "TECRA M3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"), + }, + }, + { + .ident = "TECRA M3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M3"), + }, + }, + { + .ident = "TECRA M4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Tecra M4"), + }, + }, + { + .ident = "TECRA M5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"), + }, + }, + { + .ident = "TECRA M6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"), + }, + }, + { + .ident = "TECRA M7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M7"), + }, + }, + { + .ident = "TECRA A8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A8"), + }, + }, + { + .ident = "Satellite R20", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"), + }, + }, + { + .ident = "Satellite R25", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R25"), + }, + }, + { + .ident = "Satellite U200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"), + }, + }, + { + .ident = "Satellite U200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U200"), + }, + }, + { + .ident = "Satellite Pro U200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"), + }, + }, + { + .ident = "Satellite U205", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"), + }, + }, + { + .ident = "SATELLITE U205", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE U205"), + }, + }, + { + .ident = "Portege M500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"), + }, + }, + + { } /* terminate list */ + }; + static const char *oemstrs[] = { + "Tecra M3,", + }; + int i; + + if (dmi_check_system(sysids)) + return 1; + + for (i = 0; i < ARRAY_SIZE(oemstrs); i++) + if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL)) + return 1; + + return 0; +} + +static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + unsigned long flags; + int rc = 0; + + rc = ata_host_suspend(host, mesg); + if (rc) + return rc; + + /* Some braindamaged ACPI suspend implementations expect the + * controller to be awake on entry; otherwise, it burns cpu + * cycles and power trying to do something to the sleeping + * beauty. + */ + if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) { + pci_save_state(pdev); + + /* mark its power state as "unknown", since we don't + * know if e.g. the BIOS will change its device state + * when we suspend. + */ + if (pdev->current_state == PCI_D0) + pdev->current_state = PCI_UNKNOWN; + + /* tell resume that it's waking up from broken suspend */ + spin_lock_irqsave(&host->lock, flags); + host->flags |= PIIX_HOST_BROKEN_SUSPEND; + spin_unlock_irqrestore(&host->lock, flags); + } else + ata_pci_device_do_suspend(pdev, mesg); + + return 0; +} + +static int piix_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + unsigned long flags; + int rc; + + if (host->flags & PIIX_HOST_BROKEN_SUSPEND) { + spin_lock_irqsave(&host->lock, flags); + host->flags &= ~PIIX_HOST_BROKEN_SUSPEND; + spin_unlock_irqrestore(&host->lock, flags); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + /* PCI device wasn't disabled during suspend. Use + * pci_reenable_device() to avoid affecting the enable + * count. + */ + rc = pci_reenable_device(pdev); + if (rc) + dev_printk(KERN_ERR, &pdev->dev, "failed to enable " + "device after resume (%d)\n", rc); + } else + rc = ata_pci_device_do_resume(pdev); + + if (rc == 0) + ata_host_resume(host); + + return rc; +} +#endif + +static u8 piix_vmw_bmdma_status(struct ata_port *ap) +{ + return ata_bmdma_status(ap) & ~ATA_DMA_ERR; } #define AHCI_PCI_BAR 5 @@ -761,12 +1417,12 @@ static int piix_disable_ahci(struct pci_dev *pdev) if (!mmio) return -ENOMEM; - tmp = readl(mmio + AHCI_GLOBAL_CTL); + tmp = ioread32(mmio + AHCI_GLOBAL_CTL); if (tmp & AHCI_ENABLE) { tmp &= ~AHCI_ENABLE; - writel(tmp, mmio + AHCI_GLOBAL_CTL); + iowrite32(tmp, mmio + AHCI_GLOBAL_CTL); - tmp = readl(mmio + AHCI_GLOBAL_CTL); + tmp = ioread32(mmio + AHCI_GLOBAL_CTL); if (tmp & AHCI_ENABLE) rc = -EIO; } @@ -787,20 +1443,17 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) { struct pci_dev *pdev = NULL; u16 cfg; - u8 rev; int no_piix_dma = 0; - while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL) - { + while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL) { /* Look for 450NX PXB. Check for problem configurations A PCI quirk checks bit 6 already */ - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); pci_read_config_word(pdev, 0x41, &cfg); /* Only on the original revision: IDE DMA can hang */ - if (rev == 0x00) + if (pdev->revision == 0x00) no_piix_dma = 1; /* On all revisions below 5 PXB bus lock must be disabled for IDE */ - else if (cfg & (1<<14) && rev < 5) + else if (cfg & (1<<14) && pdev->revision < 5) no_piix_dma = 2; } if (no_piix_dma) @@ -810,9 +1463,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) return no_piix_dma; } -static void __devinit piix_init_pcs(struct pci_dev *pdev, +static void __devinit piix_init_pcs(struct ata_host *host, const struct piix_map_db *map_db) { + struct pci_dev *pdev = to_pci_dev(host->dev); u16 pcs, new_pcs; pci_read_config_word(pdev, ICH5_PCS, &pcs); @@ -826,12 +1480,11 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, } } -static void __devinit piix_init_sata_map(struct pci_dev *pdev, - struct ata_port_info *pinfo, - const struct piix_map_db *map_db) +static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, + struct ata_port_info *pinfo, + const struct piix_map_db *map_db) { - struct piix_host_priv *hpriv = pinfo[0].private_data; - const unsigned int *map; + const int *map; int i, invalid_map = 0; u8 map_value; @@ -853,8 +1506,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); - pinfo[i / 2] = piix_port_info[ich5_pata]; - pinfo[i / 2].private_data = hpriv; + pinfo[i / 2] = piix_port_info[ich_pata_100]; i++; printk(" IDE IDE"); break; @@ -862,7 +1514,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, default: printk(" P%d", map[i]); if (i & 1) - pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS; + pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS; break; } } @@ -872,8 +1524,68 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, dev_printk(KERN_ERR, &pdev->dev, "invalid MAP value %u\n", map_value); - hpriv->map = map; - hpriv->map_db = map_db; + return map; +} + +static void __devinit piix_init_sidpr(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + struct piix_host_priv *hpriv = host->private_data; + int i; + + /* check for availability */ + for (i = 0; i < 4; i++) + if (hpriv->map[i] == IDE) + return; + + if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) + return; + + if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || + pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) + return; + + if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) + return; + + hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; + host->ports[0]->ops = &piix_sidpr_sata_ops; + host->ports[1]->ops = &piix_sidpr_sata_ops; +} + +static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) +{ + static const struct dmi_system_id sysids[] = { + { + /* Clevo M570U sets IOCFG bit 18 if the cdrom + * isn't used to boot the system which + * disables the channel. + */ + .ident = "M570U", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."), + DMI_MATCH(DMI_PRODUCT_NAME, "M570U"), + }, + }, + + { } /* terminate list */ + }; + u32 iocfg; + + if (!dmi_check_system(sysids)) + return; + + /* The datasheet says that bit 18 is NOOP but certain systems + * 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)) { + dev_printk(KERN_INFO, &pdev->dev, + "applying IOCFG bit18 quirk\n"); + iocfg &= ~(1 << 18); + pci_write_config_dword(pdev, PIIX_IOCFG, iocfg); + } } /** @@ -891,13 +1603,17 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, * Zero on success, or -ERRNO value. */ -static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit piix_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static int printed_version; + struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; - struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] }; + const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; + unsigned long port_flags; + struct ata_host *host; struct piix_host_priv *hpriv; - unsigned long host_flags; + int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, @@ -907,18 +1623,32 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (!in_module_init) return -ENODEV; - hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); + port_info[0] = piix_port_info[ent->driver_data]; + port_info[1] = piix_port_info[ent->driver_data]; + + port_flags = port_info[0].flags; + + /* enable device and prepare host */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + /* SATA map init can change port_info, do it before prepping host */ + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - port_info[0] = piix_port_info[ent->driver_data]; - port_info[1] = piix_port_info[ent->driver_data]; - port_info[0].private_data = hpriv; - port_info[1].private_data = hpriv; + if (port_flags & ATA_FLAG_SATA) + hpriv->map = piix_init_sata_map(pdev, port_info, + piix_map_db_table[ent->driver_data]); - host_flags = port_info[0].host_flags; + rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + if (rc) + return rc; + host->private_data = hpriv; - if (host_flags & PIIX_FLAG_AHCI) { + /* initialize controller */ + if (port_flags & PIIX_FLAG_AHCI) { u8 tmp; pci_read_config_byte(pdev, PIIX_SCC, &tmp); if (tmp == PIIX_AHCI_DEVICE) { @@ -928,41 +1658,35 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } } - /* Initialize SATA map */ - if (host_flags & ATA_FLAG_SATA) { - piix_init_sata_map(pdev, port_info, - piix_map_db_table[ent->driver_data]); - piix_init_pcs(pdev, piix_map_db_table[ent->driver_data]); + if (port_flags & ATA_FLAG_SATA) { + piix_init_pcs(host, piix_map_db_table[ent->driver_data]); + piix_init_sidpr(host); } + /* apply IOCFG bit18 quirk */ + piix_iocfg_bit18_quirk(pdev); + /* On ICH5, some BIOSen disable the interrupt using the * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. * On ICH6, this bit has the same effect, but only when * MSI is disabled (and it is disabled, as we don't use * message-signalled interrupts currently). */ - if (host_flags & PIIX_FLAG_CHECKINTR) + if (port_flags & PIIX_FLAG_CHECKINTR) pci_intx(pdev, 1); if (piix_check_450nx_errata(pdev)) { /* This writes into the master table but it does not really matter for this errata as we will apply it to all the PIIX devices on the board */ - port_info[0].mwdma_mask = 0; - port_info[0].udma_mask = 0; - port_info[1].mwdma_mask = 0; - port_info[1].udma_mask = 0; + host->ports[0]->mwdma_mask = 0; + host->ports[0]->udma_mask = 0; + host->ports[1]->mwdma_mask = 0; + host->ports[1]->udma_mask = 0; } - return ata_pci_init_one(pdev, ppinfo, 2); -} - -static void piix_host_stop(struct ata_host_set *host_set) -{ - struct piix_host_priv *hpriv = host_set->private_data; - ata_host_stop(host_set); - - kfree(hpriv); + pci_set_master(pdev); + return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht); } static int __init piix_init(void) @@ -987,4 +1711,3 @@ static void __exit piix_exit(void) module_init(piix_init); module_exit(piix_exit); -