From d830d1731fa5906aad20c228ac8b73005b13d468 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 21 Aug 2007 13:12:31 +0800 Subject: libata driver for bf548 on chip ATAPI controller. Fix all issues pointed out in Jeff's email. Acked-by: Alan Cox Signed-off-by: Sonic Zhang Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d8046a113c37..a427945f0bb1 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -596,4 +596,20 @@ config PATA_SCC If unsure, say N. +config PATA_BF54X + tristate "Blackfin 54x ATAPI support" + depends on BF542 || BF548 || BF549 + help + This option enables support for the built-in ATAPI controller on + Blackfin 54x family chips. + + If unsure, say N. + +config PATA_BF54X_DMA + bool "DMA mode" + depends on PATA_BF54X + default y + help + Enable DMA mode for Blackfin ATAPI controller. + endif # ATA -- cgit v1.2.3 From 7c9ef8e418374aec0a62e64d9b40d457634fd039 Mon Sep 17 00:00:00 2001 From: Kristoffer Nyborg Gregertsen Date: Wed, 8 Aug 2007 16:57:08 +0200 Subject: AVR32 PATA driver Updated and simplified driver. Use only register transfer timing for both data and register transfers. This gives poorer performance in PIO1 and 2, but should not be a problem in PIO3 and 4, correct me if I'm wrong :) The driver works very we'll but I still wonder about the interrupts. I have an interrupt line, that works nicely when POLLING flag is not set. The problem is the number of interrupts that eat away my CPU cycles. When using the POLLING flag there seem to be some interrupts that dosen't get cleared. Furthermore the device dosen't drive INTRQ high, it stays at 2.5 volts and generates a lot of interrupts due to ripple / noise. What to do? Signed-off-by: Kristoffer Nyborg Gregertsen Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_at32.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 drivers/ata/pata_at32.c (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a427945f0bb1..2cd0e7476718 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -199,6 +199,15 @@ config PATA_ARTOP If unsure, say N. +config PATA_AT32 + tristate "Atmel AVR32 PATA support (Experimental)" + depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL + help + This option enables support for the IDE devices on the + Atmel AT32AP platform. + + If unsure, say N. + config PATA_ATIIXP tristate "ATI PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c2ecba5f0b47..4eb7fb44be3f 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o obj-$(CONFIG_PATA_ALI) += pata_ali.o obj-$(CONFIG_PATA_AMD) += pata_amd.o obj-$(CONFIG_PATA_ARTOP) += pata_artop.o +obj-$(CONFIG_PATA_AT32) += pata_at32.o obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c new file mode 100644 index 000000000000..bb250a48e27c --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,441 @@ +/* + * AVR32 SMC/CFC PATA Driver + * + * Copyright (C) 2007 Atmel Norway + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_at32" +#define DRV_VERSION "0.0.2" + +/* + * CompactFlash controller memory layout relative to the base address: + * + * Attribute memory: 0000 0000 -> 003f ffff + * Common memory: 0040 0000 -> 007f ffff + * I/O memory: 0080 0000 -> 00bf ffff + * True IDE Mode: 00c0 0000 -> 00df ffff + * Alt IDE Mode: 00e0 0000 -> 00ff ffff + * + * Only True IDE and Alt True IDE mode are needed for this driver. + * + * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc) + * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat) + */ +#define CF_IDE_OFFSET 0x00c00000 +#define CF_ALT_IDE_OFFSET 0x00e00000 +#define CF_RES_SIZE 2048 + +/* + * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA + * adaptor with a logic analyzer or similar. + */ +#undef DEBUG_BUS + +/* + * ATA PIO modes + * + * Name | Mb/s | Min cycle time | Mask + * --------+-------+----------------+-------- + * Mode 0 | 3.3 | 600 ns | 0x01 + * Mode 1 | 5.2 | 383 ns | 0x03 + * Mode 2 | 8.3 | 240 ns | 0x07 + * Mode 3 | 11.1 | 180 ns | 0x0f + * Mode 4 | 16.7 | 120 ns | 0x1f + */ +#define PIO_MASK (0x1f) + +/* + * Struct containing private information about device. + */ +struct at32_ide_info { + unsigned int irq; + struct resource res_ide; + struct resource res_alt; + void __iomem *ide_addr; + void __iomem *alt_addr; + unsigned int cs; + struct smc_config smc; +}; + +/* + * Setup SMC for the given ATA timing. + */ +static int pata_at32_setup_timing(struct device *dev, + struct at32_ide_info *info, + const struct ata_timing *timing) +{ + /* These two values are found through testing */ + const int min_recover = 25; + const int ncs_hold = 15; + + struct smc_config *smc = &info->smc; + + int active; + int recover; + + /* Total cycle time */ + smc->read_cycle = timing->cyc8b; + + /* DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->act8b; + + /* Compute recover, extend total cycle if needed */ + active = smc->nrd_setup + smc->nrd_pulse; + recover = smc->read_cycle - active; + + if (recover < min_recover) { + smc->read_cycle = active + min_recover; + recover = min_recover; + } + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + smc->ncs_read_setup = 0; + smc->ncs_read_pulse = active + ncs_hold; + + /* Write timings same as read timings */ + smc->write_cycle = smc->read_cycle; + smc->nwe_setup = smc->nrd_setup; + smc->nwe_pulse = smc->nrd_pulse; + smc->ncs_write_setup = smc->ncs_read_setup; + smc->ncs_write_pulse = smc->ncs_read_pulse; + + /* Do some debugging output */ + dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n", + smc->read_cycle, smc->nrd_setup, smc->nrd_pulse, + recover, smc->ncs_read_setup, smc->ncs_read_pulse, + smc->read_cycle - smc->ncs_read_pulse); + + /* Finally, configure the SMC */ + return smc_set_configuration(info->cs, smc); +} + +/* + * Procedures for libATA. + */ +static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing timing; + struct at32_ide_info *info = ap->host->private_data; + + int ret; + + /* Compute ATA timing */ + ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0); + if (ret) { + dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret); + return; + } + + /* Setup SMC to ATA timing */ + ret = pata_at32_setup_timing(ap->dev, info, &timing); + if (ret) { + dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret); + return; + } +} + +static void pata_at32_irq_clear(struct ata_port *ap) +{ + /* No DMA controller yet */ +} + +static struct scsi_host_template at32_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations at32_port_ops = { + .port_disable = ata_port_disable, + .set_piomode = pata_at32_set_piomode, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .exec_command = ata_exec_command, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_clear = pata_at32_irq_clear, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, + + .port_start = ata_sff_port_start, +}; + +static int __init pata_at32_init_one(struct device *dev, + struct at32_ide_info *info) +{ + struct ata_host *host; + struct ata_port *ap; + + host = ata_host_alloc(dev, 1); + if (!host) + return -ENOMEM; + + ap = host->ports[0]; + + /* Setup ATA bindings */ + ap->ops = &at32_port_ops; + ap->pio_mask = PIO_MASK; + ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS + | ATA_FLAG_PIO_POLLING; + + /* + * Since all 8-bit taskfile transfers has to go on the lower + * byte of the data bus and there is a bug in the SMC that + * makes it impossible to alter the bus width during runtime, + * we need to hardwire the address signals as follows: + * + * A_IDE(2:0) <= A_EBI(3:1) + * + * This makes all addresses on the EBI even, thus all data + * will be on the lower byte of the data bus. All addresses + * used by libATA need to be altered according to this. + */ + ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1); + ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1); + + ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1); + ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1); + ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1); + ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1); + ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1); + ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1); + ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1); + ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1); + ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1); + ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1); + + /* Set info as private data of ATA host */ + host->private_data = info; + + /* Register ATA device and return */ + return ata_host_activate(host, info->irq, ata_interrupt, + IRQF_SHARED | IRQF_TRIGGER_RISING, + &at32_sht); +} + +/* + * This function may come in handy for people analyzing their own + * EBI -> PATA adaptors. + */ +#ifdef DEBUG_BUS + +static void __init pata_at32_debug_bus(struct device *dev, + struct at32_ide_info *info) +{ + const int d1 = 0xff; + const int d2 = 0x00; + + int i; + + /* Write 8-bit values (registers) */ + iowrite8(d1, info->alt_addr + (0x06 << 1)); + iowrite8(d2, info->alt_addr + (0x06 << 1)); + + for (i = 0; i < 8; i++) { + iowrite8(d1, info->ide_addr + (i << 1)); + iowrite8(d2, info->ide_addr + (i << 1)); + } + + /* Write 16 bit values (data) */ + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); +} + +#endif + +static int __init pata_at32_probe(struct platform_device *pdev) +{ + const struct ata_timing initial_timing = + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; + + struct device *dev = &pdev->dev; + struct at32_ide_info *info; + struct ide_platform_data *board = pdev->dev.platform_data; + struct resource *res; + + int irq; + int ret; + + if (!board) + return -ENXIO; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + /* Retrive IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Setup struct containing private infomation */ + info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct at32_ide_info)); + + info->irq = irq; + info->cs = board->cs; + + /* Request memory resources */ + info->res_ide.start = res->start + CF_IDE_OFFSET; + info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1; + info->res_ide.name = "ide"; + info->res_ide.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_ide); + if (ret) + goto err_req_res_ide; + + info->res_alt.start = res->start + CF_ALT_IDE_OFFSET; + info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1; + info->res_alt.name = "alt"; + info->res_alt.flags = IORESOURCE_MEM; + + ret = request_resource(res, &info->res_alt); + if (ret) + goto err_req_res_alt; + + /* Setup non-timing elements of SMC */ + info->smc.bus_width = 2; /* 16 bit data bus */ + info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */ + info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */ + info->smc.nwait_mode = 3; /* NWAIT is in READY mode */ + info->smc.byte_write = 0; /* Byte select access type */ + info->smc.tdf_mode = 0; /* TDF optimization disabled */ + info->smc.tdf_cycles = 0; /* No TDF wait cycles */ + + /* Setup ATA timing */ + ret = pata_at32_setup_timing(dev, info, &initial_timing); + if (ret) + goto err_setup_timing; + + /* Setup ATA addresses */ + ret = -ENOMEM; + info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16); + info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16); + if (!info->ide_addr || !info->alt_addr) + goto err_ioremap; + +#ifdef DEBUG_BUS + pata_at32_debug_bus(dev, info); +#endif + + /* Register ATA device */ + ret = pata_at32_init_one(dev, info); + if (ret) + goto err_ata_device; + + return 0; + + err_ata_device: + err_ioremap: + err_setup_timing: + release_resource(&info->res_alt); + err_req_res_alt: + release_resource(&info->res_ide); + err_req_res_ide: + kfree(info); + + return ret; +} + +static int __exit pata_at32_remove(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct at32_ide_info *info; + + if (!host) + return 0; + + info = host->private_data; + ata_host_detach(host); + + if (!info) + return 0; + + release_resource(&info->res_ide); + release_resource(&info->res_alt); + + kfree(info); + + return 0; +} + +static struct platform_driver pata_at32_driver = { + .remove = __exit_p(pata_at32_remove), + .driver = { + .name = "at32_ide", + .owner = THIS_MODULE, + }, +}; + +static int __init pata_at32_init(void) +{ + return platform_driver_probe(&pata_at32_driver, pata_at32_probe); +} + +static void __exit pata_at32_exit(void) +{ + platform_driver_unregister(&pata_at32_driver); +} + +module_init(pata_at32_init); +module_exit(pata_at32_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver"); +MODULE_AUTHOR("Kristoffer Nyborg Gregertsen "); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3 From c645fd34256e8ef4986d3e8acd569890cc421e5d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 20 Sep 2007 14:58:48 +0100 Subject: libata: Update experimental tags to reflect reality better Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2cd0e7476718..3a737bdce2ec 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -192,8 +192,8 @@ config PATA_AMD If unsure, say N. config PATA_ARTOP - tristate "ARTOP 6210/6260 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ARTOP 6210/6260 PATA support" + depends on PCI help This option enables support for ARTOP PATA controllers. @@ -209,8 +209,8 @@ config PATA_AT32 If unsure, say N. config PATA_ATIIXP - tristate "ATI PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "ATI PATA support" + depends on PCI help This option enables support for the ATI ATA interfaces found on the many ATI chipsets. @@ -228,8 +228,8 @@ config PATA_CMD640_PCI If unsure, say N. config PATA_CMD64X - tristate "CMD64x PATA support (Very Experimental)" - depends on PCI&& EXPERIMENTAL + tristate "CMD64x PATA support" + depends on PCI help This option enables support for the CMD64x series chips except for the CMD640. @@ -291,8 +291,8 @@ config ATA_GENERIC If unsure, say N. config PATA_HPT366 - tristate "HPT 366/368 PATA support (Experimental)" - depends on PCI && EXPERIMENTAL + tristate "HPT 366/368 PATA support" + depends on PCI help This option enables support for the HPT 366 and 368 PATA controllers via the new ATA layer. -- cgit v1.2.3 From c4b5b7b6c4423ec4ced4177c87d2da04de324028 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 29 Sep 2007 02:35:10 -0400 Subject: pata_ns87415: Initial cut at 87415/87560 IDE support Signed-off-by: Alan Cox [plus SuperIO fixes by Kyle McMartin] [plus a cleanup from me] Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 + drivers/ata/Makefile | 1 + drivers/ata/pata_ns87415.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 477 insertions(+) create mode 100644 drivers/ata/pata_ns87415.c (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 3a737bdce2ec..cf960bd1c00a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -441,6 +441,15 @@ config PATA_NS87410 If unsure, say N. +config PATA_NS87415 + tristate "Nat Semi NS87415 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the National Semiconductor + NS87415 PCI-IDE controller. + + If unsure, say N. + config PATA_OPTI tristate "OPTI621/6215 PATA support (Very Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 4eb7fb44be3f..56bf13cbd198 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o +obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c new file mode 100644 index 000000000000..bb97ef583f9b --- /dev/null +++ b/drivers/ata/pata_ns87415.c @@ -0,0 +1,467 @@ +/* + * pata_ns87415.c - NS87415 (non PARISC) PATA + * + * (C) 2005 Red Hat + * + * This is a fairly generic MWDMA controller. It has some limitations + * as it requires timing reloads on PIO/DMA transitions but it is otherwise + * fairly well designed. + * + * This driver assumes the firmware has left the chip in a valid ST506 + * compliant state, either legacy IRQ 14/15 or native INTA shared. You + * may need to add platform code if your system fails to do this. + * + * The same cell appears in the 87560 controller used by some PARISC + * systems. This has its own special mountain of errata. + * + * TODO: + * Test PARISC SuperIO + * Get someone to test on SPARC + * Implement lazy pio/dma switching for better performance + * 8bit shared timing. + * See if we need to kill the FIFO for ATAPI + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_ns87415" +#define DRV_VERSION "0.0.1" + +/** + * ns87415_set_mode - Initialize host controller mode timings + * @ap: Port whose timings we are configuring + * @adev: Device whose timings we are configuring + * @mode: Mode to set + * + * Program the mode registers for this controller, channel and + * device. Because the chip is quite an old design we have to do this + * for PIO/DMA switches. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + int unit = 2 * ap->port_no + adev->devno; + int timing = 0x44 + 2 * unit; + unsigned long T = 1000000000 / 33333; /* PCI clocks */ + struct ata_timing t; + u16 clocking; + u8 iordy; + u8 status; + + /* Timing register format is 17 - low nybble read timing with + the high nybble being 16 - x for recovery time in PCI clocks */ + + ata_timing_compute(adev, adev->pio_mode, &t, T, 0); + + clocking = 17 - FIT(t.active, 2, 17); + clocking |= (16 - FIT(t.recover, 1, 16)) << 4; + /* Use the same timing for read and write bytes */ + clocking |= (clocking << 8); + pci_write_config_word(dev, timing, clocking); + + /* Set the IORDY enable versus DMA enable on or off properly */ + pci_read_config_byte(dev, 0x42, &iordy); + iordy &= ~(1 << (4 + unit)); + if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev)) + iordy |= (1 << (4 + unit)); + + /* Paranoia: We shouldn't ever get here with busy write buffers + but if so wait */ + + pci_read_config_byte(dev, 0x43, &status); + while (status & 0x03) { + udelay(1); + pci_read_config_byte(dev, 0x43, &status); + } + /* Flip the IORDY/DMA bits now we are sure the write buffers are + clear */ + pci_write_config_byte(dev, 0x42, iordy); + + /* TODO: Set byte 54 command timing to the best 8bit + mode shared by all four devices */ +} + +/** + * ns87415_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + ns87415_set_mode(ap, adev, adev->pio_mode); +} + +/** + * ns87415_bmdma_setup - Set up DMA + * @qc: Command block + * + * Set up for bus masterng DMA. We have to do this ourselves + * rather than use the helper due to a chip erratum + */ + +static void ns87415_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + + /* load PRD table addr. */ + mb(); /* make sure PRD table writes are visible to controller */ + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + + /* specify data direction, triple-check start bit is clear */ + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + /* Due to an erratum we need to write these bits to the wrong + place - which does save us an I/O bizarrely */ + dmactl |= ATA_DMA_INTR | ATA_DMA_ERR; + if (!rw) + dmactl |= ATA_DMA_WR; + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * ns87415_bmdma_start - Begin DMA transfer + * @qc: Command block + * + * Switch the timings for the chip and set up for a DMA transfer + * before the DMA burst begins. + * + * FIXME: We should do lazy switching on bmdma_start versus + * ata_pio_data_xfer for better performance. + */ + +static void ns87415_bmdma_start(struct ata_queued_cmd *qc) +{ + ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode); + ata_bmdma_start(qc); +} + +/** + * ns87415_bmdma_stop - End DMA transfer + * @qc: Command block + * + * End DMA mode and switch the controller back into PIO mode + */ + +static void ns87415_bmdma_stop(struct ata_queued_cmd *qc) +{ + ata_bmdma_stop(qc); + ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode); +} + +/** + * ns87415_bmdma_irq_clear - Clear interrupt + * @ap: Channel to clear + * + * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the + * error bits) are reset by writing to register 00 or 08. + */ + +static void ns87415_bmdma_irq_clear(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), + mmio + ATA_DMA_CMD); +} + +/** + * ns87415_check_atapi_dma - ATAPI DMA filter + * @qc: Command block + * + * Disable ATAPI DMA (for now). We may be able to do DMA if we + * kill the prefetching. This isn't clear. + */ + +static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc) +{ + return -EOPNOTSUPP; +} + +#if defined(CONFIG_SUPERIO) + +/* SUPERIO 87560 is a PoS chip that NatSem denies exists. + * Unfortunately, it's built-in on all Astro-based PA-RISC workstations + * which use the integrated NS87514 cell for CD-ROM support. + * i.e we have to support for CD-ROM installs. + * See drivers/parisc/superio.c for more gory details. + * + * Workarounds taken from drivers/ide/pci/ns87415.c + */ + +#include + +/** + * ns87560_read_buggy - workaround buggy Super I/O chip + * @port: Port to read + * + * Work around chipset problems in the 87560 SuperIO chip + */ + +static u8 ns87560_read_buggy(void __iomem *port) +{ + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + do { + tmp = ioread8(port); + if (tmp != 0) + return tmp; + udelay(50); + } while(retries-- > 0); + return tmp; +} + +/** + * ns87560_check_status + * @ap: channel to check + * + * Return the status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_check_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.status_addr); +} + +/** + * ns87560_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Reads ATA taskfile registers for currently-selected device + * into @tf. Work around the 87560 bugs. + * + * LOCKING: + * Inherited from caller. + */ +void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ns87560_check_status(ap); + tf->feature = ioread8(ioaddr->error_addr); + tf->nsect = ioread8(ioaddr->nsect_addr); + tf->lbal = ioread8(ioaddr->lbal_addr); + tf->lbam = ioread8(ioaddr->lbam_addr); + tf->lbah = ioread8(ioaddr->lbah_addr); + tf->device = ns87560_read_buggy(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ioread8(ioaddr->error_addr); + tf->hob_nsect = ioread8(ioaddr->nsect_addr); + tf->hob_lbal = ioread8(ioaddr->lbal_addr); + tf->hob_lbam = ioread8(ioaddr->lbam_addr); + tf->hob_lbah = ioread8(ioaddr->lbah_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } +} + +/** + * ns87560_bmdma_status + * @ap: channel to check + * + * Return the DMA status of the channel working around the + * 87560 flaws. + */ + +static u8 ns87560_bmdma_status(struct ata_port *ap) +{ + return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); +} + +static const struct ata_port_operations ns87560_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ns87560_tf_read, + .check_status = ns87560_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ns87560_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +#endif /* 87560 SuperIO Support */ + + +static const struct ata_port_operations ns87415_pata_ops = { + .set_piomode = ns87415_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .check_atapi_dma = ns87415_check_atapi_dma, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ns87415_bmdma_setup, + .bmdma_start = ns87415_bmdma_start, + .bmdma_stop = ns87415_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ns87415_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct scsi_host_template ns87415_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + + +/** + * ns87415_init_one - Register 87415 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in ns87415_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. We probe for combined mode (sigh), + * and then hand over control to libata, for it to do the rest. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static const struct ata_port_info info = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87415_pata_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; +#if defined(CONFIG_SUPERIO) + static const struct ata_port_info info87560 = { + .sht = &ns87415_sht, + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .port_ops = &ns87560_pata_ops, + }; + + if (PCI_SLOT(pdev->devfn) == 0x0E) + ppi[0] = &info87560; +#endif + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + /* Select 512 byte sectors */ + pci_write_config_byte(pdev, 0x55, 0xEE); + /* Select PIO0 8bit clocking */ + pci_write_config_byte(pdev, 0x54, 0xB7); + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id ns87415_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), }, + + { } /* terminate list */ +}; + +static struct pci_driver ns87415_pci_driver = { + .name = DRV_NAME, + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init ns87415_init(void) +{ + return pci_register_driver(&ns87415_pci_driver); +} + +static void __exit ns87415_exit(void) +{ + pci_unregister_driver(&ns87415_pci_driver); +} + +module_init(ns87415_init); +module_exit(ns87415_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3 From 025621f9a7c0efe1139d43d246136a0f3e8ea675 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 4 Oct 2007 21:32:58 +0100 Subject: pata_acpi: ACPI driver support On a cable there may be eighty wires or perhaps forty and we learn about its type In the world of ACPI So we call the GTM And we find the the timing rate And we look through it to see If eighty wire it must be Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines And the drivers last you see Picking up unknown pci ids and the code begins to work Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines [Full speed ahead, Mr Hacker, full speed ahead] Full speed over here sir! Checking Cable, checking cable Aye aye, 80 wire, Heaven heaven] If we use ACPI (ACPI) Every box (every box) has all we need (has all we need) Cable type (cable type) and mode timing (mode timing) In our ATA (in our ATA) subroutines (subroutines, ha ha) Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Timing lives in ACPI routines ACPI routines, ACPI routines Timing lives in ACPI routines ACPI routes ACPI routines Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 2 + drivers/ata/pata_acpi.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 drivers/ata/pata_acpi.c (limited to 'drivers/ata/Kconfig') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index cf960bd1c00a..4672066167e3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -173,6 +173,15 @@ config SATA_INIC162X help This option enables support for Initio 162x Serial ATA. +config PATA_ACPI + tristate "ACPI firmware driver for PATA" + depends on ATA_ACPI + help + This option enables an ACPI method driver which drives + motherboard PATA controller interfaces through the ACPI + firmware in the BIOS. This driver can sometimes handle + otherwise unsupported hardware. + config PATA_ALI tristate "ALi PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 7e937519a930..2a63645003eb 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -66,6 +66,8 @@ obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o +# Should be last but two libata driver +obj-$(CONFIG_PATA_ACPI) += pata_acpi.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o # Should be last libata driver diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c new file mode 100644 index 000000000000..5d3920f6fd69 --- /dev/null +++ b/drivers/ata/pata_acpi.c @@ -0,0 +1,395 @@ +/* + * ACPI PATA driver + * + * (c) 2007 Red Hat + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "pata_acpi" +#define DRV_VERSION "0.2.3" + +struct pata_acpi { + struct ata_acpi_gtm gtm; + void *last; + unsigned long mask[2]; +}; + +/** + * pacpi_pre_reset - check for 40/80 pin + * @ap: Port + * @deadline: deadline jiffies for the operation + * + * Perform the PATA port setup we need. + */ + +static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct pata_acpi *acpi = ap->private_data; + if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0) + return -ENODEV; + + return ata_std_prereset(link, deadline); +} + +/** + * pacpi_cable_detect - cable type detection + * @ap: port to detect + * + * Perform device specific cable detection + */ + +static int pacpi_cable_detect(struct ata_port *ap) +{ + struct pata_acpi *acpi = ap->private_data; + + if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA)) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * pacpi_error_handler - Setup and error handler + * @ap: Port to handle + * + * LOCKING: + * None (inherited from caller). + */ + +static void pacpi_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, + NULL, ata_std_postreset); +} + +/* Welcome to ACPI, bring a bucket */ +static const unsigned int pio_cycle[7] = { + 600, 383, 240, 180, 120, 100, 80 +}; +static const unsigned int mwdma_cycle[5] = { + 480, 150, 120, 100, 80 +}; +static const unsigned int udma_cycle[7] = { + 120, 80, 60, 45, 30, 20, 15 +}; + +/** + * pacpi_discover_modes - filter non ACPI modes + * @adev: ATA device + * @mask: proposed modes + * + * Try the modes available and see which ones the ACPI method will + * set up sensibly. From this we get a mask of ACPI modes we can use + */ + +static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + int i; + u32 t; + unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); + + struct ata_acpi_gtm probe; + + probe = acpi->gtm; + + /* We always use the 0 slot for crap hardware */ + if (!(probe.flags & 0x10)) + unit = 0; + + ata_acpi_gtm(ap, &probe); + + /* Start by scanning for PIO modes */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].pio; + if (t <= pio_cycle[i]) { + mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; + break; + } + } + + /* See if we have MWDMA or UDMA data. We don't bother with MWDMA + if UDMA is availabe as this means the BIOS set UDMA and our + error changedown if it works is UDMA to PIO anyway */ + if (probe.flags & (1 << (2 * unit))) { + /* MWDMA */ + for (i = 0; i < 5; i++) { + t = probe.drive[unit].dma; + if (t <= mwdma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; + break; + } + } + } else { + /* UDMA */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].dma; + if (t <= udma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; + break; + } + } + } + if (mask & (0xF8 << ATA_SHIFT_UDMA)) + ap->cbl = ATA_CBL_PATA80; + return mask; +} + +/** + * pacpi_mode_filter - mode filter for ACPI + * @adev: device + * @mask: mask of valid modes + * + * Filter the valid mode list according to our own specific rules, in + * this case the list of discovered valid modes obtained by ACPI probing + */ + +static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask) +{ + struct pata_acpi *acpi = adev->link->ap->private_data; + return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]); +} + +/** + * pacpi_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_set_dmamode - set initial DMA mode data + * @ap: ATA interface + * @adev: ATA device + */ + +static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + int unit = adev->devno; + struct pata_acpi *acpi = ap->private_data; + + if(!(acpi->gtm.flags & 0x10)) + unit = 0; + + /* Now stuff the nS values into the structure */ + if (adev->dma_mode >= XFER_UDMA_0) { + acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; + acpi->gtm.flags |= (1 << (2 * unit)); + } else { + acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; + acpi->gtm.flags &= ~(1 << (2 * unit)); + } + ata_acpi_stm(ap, &acpi->gtm); + /* See what mode we actually got */ + ata_acpi_gtm(ap, &acpi->gtm); +} + +/** + * pacpi_qc_issue_prot - command issue + * @qc: command pending + * + * Called when the libata layer is about to issue a command. We wrap + * this interface so that we can load the correct ATA timings if + * neccessary. + */ + +static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *adev = qc->dev; + struct pata_acpi *acpi = ap->private_data; + + if (acpi->gtm.flags & 0x10) + return ata_qc_issue_prot(qc); + + if (adev != acpi->last) { + pacpi_set_piomode(ap, adev); + if (adev->dma_mode) + pacpi_set_dmamode(ap, adev); + acpi->last = adev; + } + return ata_qc_issue_prot(qc); +} + +/** + * pacpi_port_start - port setup + * @ap: ATA port being set up + * + * Use the port_start hook to maintain private control structures + */ + +static int pacpi_port_start(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct pata_acpi *acpi; + + int ret; + + if (ap->acpi_handle == NULL) + return -ENODEV; + + acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL); + if (ap->private_data == NULL) + return -ENOMEM; + acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]); + acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]); + ret = ata_sff_port_start(ap); + if (ret < 0) + return ret; + + return ret; +} + +static struct scsi_host_template pacpi_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + /* Use standard CHS mapping rules */ + .bios_param = ata_std_bios_param, +}; + +static const struct ata_port_operations pacpi_ops = { + .set_piomode = pacpi_set_piomode, + .set_dmamode = pacpi_set_dmamode, + .mode_filter = pacpi_mode_filter, + + /* Task file is PCI ATA format, use helpers */ + .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, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = pacpi_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = pacpi_cable_detect, + + /* BMDMA handling is PCI ATA format, use helpers */ + .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 = pacpi_qc_issue_prot, + .data_xfer = ata_data_xfer, + + /* Timeout handling */ + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + /* Generic PATA PCI ATA helpers */ + .port_start = pacpi_port_start, +}; + + +/** + * pacpi_init_one - Register ACPI ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in pacpi_pci_tbl matching with @pdev + * + * Called from kernel PCI layer. + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .sht = &pacpi_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + + .port_ops = &pacpi_ops, + }; + const struct ata_port_info *ppi[] = { &info, NULL }; + return ata_pci_init_one(pdev, ppi); +} + +static const struct pci_device_id pacpi_pci_tbl[] = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, + { } /* terminate list */ +}; + +static struct pci_driver pacpi_pci_driver = { + .name = DRV_NAME, + .id_table = pacpi_pci_tbl, + .probe = pacpi_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init pacpi_init(void) +{ + return pci_register_driver(&pacpi_pci_driver); +} + +static void __exit pacpi_exit(void) +{ + pci_unregister_driver(&pacpi_pci_driver); +} + +module_init(pacpi_init); +module_exit(pacpi_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl); +MODULE_VERSION(DRV_VERSION); + -- cgit v1.2.3