* [PATCH 0/1] AVR32 PATA driver
@ 2007-08-07 9:26 Kristoffer Nyborg Gregertsen
2007-08-07 9:27 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Kristoffer Nyborg Gregertsen @ 2007-08-07 9:26 UTC (permalink / raw)
To: linux-ide; +Cc: kngregertsen, gregerts
Hi everybody,
My PATA driver for AVR32 is now working in all PIO modes. I have
tested the driver for two weeks and it seems pretty stable, there
are no file corruption or fatal errors.
This is a typical result by running Bonnie in PIO4 (file size 104857600):
-------Sequential Output-------- ---Sequential Input-- --Random--
-Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU /sec %CPU
100 1599 80.5 5305 20.4 2581 17.4 1385 78.0 5068 14.8 45.8 1.9
Yet there are still some issues:
1) In PIO1 and PIO2 there are rare freezes:
ata3.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x2 frozen
ata3.00: cmd 20/00:00:d3:7e:5d/00:00:00:00:00/e1 tag 0 cdb 0x0 data 131072 in
res 58/00:01:d2:7f:5d/00:00:01:00:00/e1 Emask 0x2 (HSM violation)
The freezes happen close to each other in time. The freezes does not make file
operations fail.
2) After being in operation for a long time (+24 hours) the disk reports wrong
identity:
ata4.00: model number mismatch 'IC35L060AVV207-0' != ''
ata4.00: revalidation failed (errno=-19)
ata4.00: limiting speed to PIO2
ata4: failed to recover some devices, retrying in 5 secs
ata4.00: model number mismatch 'IC35L060AVV207-0' != 'AV07-0 *GARBEL*
This has happend with both the devices I am testing, the 'Quantum Fireball'
reported it self to be 'Quanpum Fiveball' after 24 hours of testing.
I also have a question regrding INTRQ / IRQ handeling. Since I am not using
DMA, there seems to be no reason to handle interrupts, so I set the polling
flag. Not using the polling flag gives a lot of interrupts that does not seem
to do anything except eating my CPU cycles. Is this correct?
If so, what shall I do when activating the host to not get "irq 65: nobody
cared" ... "Disabling IRQ #65". Should I give an negative irq number?
Any help and reviews of my code would be appriciate :)
--
Kristoffer Nyborg Gregertsen
MSc. student / Summer intern
Atmel Norway
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 1/1] AVR32 PATA driver 2007-08-07 9:26 [PATCH 0/1] AVR32 PATA driver Kristoffer Nyborg Gregertsen @ 2007-08-07 9:27 ` Kristoffer Nyborg Gregertsen 2007-08-07 15:54 ` Alan Cox 2007-08-07 15:58 ` [PATCH 0/1] " Alan Cox 2007-08-14 6:41 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen 2 siblings, 1 reply; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-07 9:27 UTC (permalink / raw) To: linux-ide; +Cc: gregerts This patch adds support for PATA devices on the AVR32 using the CompactFlash controller in 'True IDE mode'. DMA is currently not supported due to lack of DMACK pins on the current AP7000 series. Tested on AP7000 / STK1000. Signed-off-by: Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com> --- diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4ad8675..7de15e6 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 (Very 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 8149c68..7c5e319 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 0000000..3f57624 --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,569 @@ +/* + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/gpio.h> +#include <asm/arch/board.h> +#include <asm/arch/smc.h> + +#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 + * + * This parameter allows users to set max PIO mode. + */ +static int max_pio = 4; +module_param(max_pio, int, 0444); +MODULE_PARM_DESC(max_pio, "Max PIO mode, range 0..4, default 4"); + +/* + * Return PIO mask as given by parameter max_pio. + */ +static int pata_at32_get_pio_mask(void) +{ + switch (max_pio) { + case 0: + return 0x01; + case 1: + return 0x03; + case 2: + return 0x07; + case 3: + return 0x0f; + case 4: + return 0x1f; + default: + return 0x01; + } +} + +/* + * 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_8; + struct smc_config smc_16; + int smc_pio_mode; +}; + +/* + * Computes SMC timing for the given ATA timing and bus width. + */ +static void pata_at32_compute_smc_timing(struct device *dev, + struct smc_config *smc, + const struct ata_timing *timing, + int bus_width) +{ + /* These two values are found through testing */ + const int min_recover = 50; + const int ncs_hold = 20; + + int read_active; + int read_recover; + int write_active; + int write_recover; + + /* Compute SMC timings given data or register transfer */ + if (bus_width == 2) { + /* Data transfer total cycle time */ + smc->read_cycle = timing->cycle; + smc->write_cycle = timing->cycle; + + /* Data transfer DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->active; + + /* Data transfer DIOW <= CFIOW timings */ + smc->nwe_setup = timing->setup; + smc->nwe_pulse = timing->active; + } else { + /* Register transfer total cycle time */ + smc->read_cycle = timing->cyc8b; + smc->write_cycle = timing->cyc8b; + + /* Register transfer DIOR <= CFIOR timings */ + smc->nrd_setup = timing->setup; + smc->nrd_pulse = timing->act8b; + + /* Register transfer DIOW <= CFIOW timings */ + smc->nwe_setup = timing->setup; + smc->nwe_pulse = timing->act8b; + } + + /* Compute read recover, extend total cycle if needed */ + read_active = smc->nrd_setup + smc->nrd_pulse; + read_recover = smc->read_cycle - read_active; + + if (read_recover < min_recover) { + smc->read_cycle = read_active + min_recover; + read_recover = min_recover; + } + + /* Compute write recover, extend total cycle if needed */ + write_active = smc->nwe_setup + smc->nwe_pulse; + write_recover = smc->write_cycle - write_active; + + if (write_recover < min_recover) { + smc->write_cycle = write_active + min_recover; + write_recover = min_recover; + } + + /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ + smc->ncs_read_setup = 0; + smc->ncs_read_pulse = read_active + ncs_hold; + smc->ncs_write_setup = 0; + smc->ncs_write_pulse = write_active + ncs_hold; + + /* Compute number of TDF cycles */ + smc->tdf_cycles = smc_get_clock_cycles(ncs_hold) + 1; + + /* Do some debugging output */ + dev_dbg(dev, "SMC_%s READ : C=%d S=%d P=%d R=%d " + "NCSS=%d NCSP=%d NCSR=%d\n", + bus_width == 2 ? "16" : "8", + smc->read_cycle, smc->nrd_setup, + smc->nrd_pulse, read_recover, + smc->ncs_read_setup, smc->ncs_read_pulse, + smc->read_cycle - smc->ncs_read_pulse); + + dev_dbg(dev, "SMC_%s WRITE: C=%d S=%d P=%d R=%d " + "NCSS=%d NCSP=%d NCSR=%d\n", + bus_width == 2 ? "16" : "8", + smc->write_cycle, smc->nwe_setup, + smc->nwe_pulse, write_recover, + smc->ncs_write_setup, smc->ncs_write_pulse, + smc->write_cycle - smc->ncs_write_pulse); + + dev_dbg(dev, "SMC_%s TDF: %s MODE %d CYCLES\n", + bus_width == 2 ? "16" : "8", + smc->tdf_mode ? "OPTIMIZED" : "NORMAL", + smc->tdf_cycles); +} + +/* + * 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) +{ + int ret; + + /* Compute SMC timings for register and data transfers */ + pata_at32_compute_smc_timing(dev, &info->smc_8, timing, 1); + pata_at32_compute_smc_timing(dev, &info->smc_16, timing, 2); + + /* + * Configure the SMC for data transfers first. The purpose is + * to validate the configuration and compute the register + * contents so they can be restored later (see procedure + * pata_at32_data_xfer). + */ + ret = smc_set_configuration(info->cs, &info->smc_16); + if (ret) + return ret; + + /* Then configure the SMC for register transfers */ + return smc_set_configuration(info->cs, &info->smc_8); +} + +/* + * 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 pio_mode = adev->pio_mode - XFER_PIO_0; + int ret; + + /* Exit if the SMC is already configured for this PIO mode */ + if (pio_mode == info->smc_pio_mode) + return; + + /* 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; + } + + info->smc_pio_mode = pio_mode; +} + +static void pata_at32_irq_clear(struct ata_port *ap) +{ +} + +static void pata_at32_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct at32_ide_info *info = adev->ap->host->private_data; + + /* Set SMC to data transfer speed */ + if (info->smc_pio_mode < 3) + smc_restore_registers(info->cs, &info->smc_16.reg); + + /* Transfer data */ + ata_data_xfer(adev, buf, buflen, write_data); + + /* Set SMC back to register transfer speed */ + if (info->smc_pio_mode < 3) + smc_restore_registers(info->cs, &info->smc_8.reg); +} + +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 = pata_at32_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 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 = pata_at32_get_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, ctld; + int iod[8]; + + 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)); + } + + ctld = ioread8(info->alt_addr + (0x06 << 1)); + + for (i = 0; i < 8; i++) + iod[i] = ioread8(info->ide_addr + (i << 1)); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + iowrite16(d1, info->ide_addr); + iowrite16(d1 << 8, info->ide_addr); + + dev_dbg(dev, "CTL = %x\n", ctld); + + for (i = 0; i < 8; i++) + dev_dbg(dev, "IO%d = %x\n", i, iod[i]); +} + +#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->cs = board->cs; + info->smc_pio_mode = 0; + info->irq = irq; + + /* 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 SMC, see Atmel AVR32 AP7000 datasheet chapter 27 */ + info->smc_8.bus_width = 2; /* 16 bit data bus */ + info->smc_8.nrd_controlled = 1; /* Sample data on rising edge of NRD */ + info->smc_8.nwe_controlled = 0; /* Drive data on falling edge of NCS */ + info->smc_8.nwait_mode = 3; /* NWAIT is in READY mode */ + info->smc_8.byte_write = 0; /* Byte select access type */ + info->smc_8.tdf_mode = 1; /* TDF optimization enabled */ + + info->smc_16 = info->smc_8; + + /* 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 <kngregertsen@norway.atmel.com>"); +MODULE_VERSION(DRV_VERSION); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-07 9:27 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen @ 2007-08-07 15:54 ` Alan Cox 2007-08-07 17:39 ` Kristoffer Nyborg Gregertsen 2007-08-08 14:57 ` Kristoffer Nyborg Gregertsen 0 siblings, 2 replies; 13+ messages in thread From: Alan Cox @ 2007-08-07 15:54 UTC (permalink / raw) To: Kristoffer Nyborg Gregertsen; +Cc: linux-ide, gregerts +static int pata_at32_get_pio_mask(void) > +{ > + switch (max_pio) { > + case 0: > + return 0x01; > + case 1: > + return 0x03; > + case 2: > + return 0x07; > + case 3: > + return 0x0f; > + case 4: > + return 0x1f; > + default: > + return 0x01; What is wrong with just using (1 << max_pio) - 1 as the range is only 0-4 anyway. > +static void pata_at32_data_xfer(struct ata_device *adev, unsigned char *buf, > + unsigned int buflen, int write_data) > +{ > + struct at32_ide_info *info = adev->ap->host->private_data; > + > + /* Set SMC to data transfer speed */ > + if (info->smc_pio_mode < 3) > + smc_restore_registers(info->cs, &info->smc_16.reg); > + > + /* Transfer data */ > + ata_data_xfer(adev, buf, buflen, write_data); > + > + /* Set SMC back to register transfer speed */ > + if (info->smc_pio_mode < 3) > + smc_restore_registers(info->cs, &info->smc_8.reg); Should be safe currently for IRQ driven behaviour, might be for polled but remember that without locking you could end up reading the status before you switch the clock back so I'm not 100% sure. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-07 15:54 ` Alan Cox @ 2007-08-07 17:39 ` Kristoffer Nyborg Gregertsen 2007-08-07 18:14 ` Jeff Garzik 2007-08-08 14:57 ` Kristoffer Nyborg Gregertsen 1 sibling, 1 reply; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-07 17:39 UTC (permalink / raw) To: Alan Cox; +Cc: Kristoffer Nyborg Gregertsen, linux-ide, gregerts On Tuesday 07 August 2007 17:54:09 Alan Cox wrote: > +static int pata_at32_get_pio_mask(void) > > > +{ > > + switch (max_pio) { > > + case 0: > > + return 0x01; > > + case 1: > > + return 0x03; > > + case 2: > > + return 0x07; > > + case 3: > > + return 0x0f; > > + case 4: > > + return 0x1f; > > + default: > > + return 0x01; > > What is wrong with just using (1 << max_pio) - 1 as the range is only > 0-4 anyway. Since max_pio is a module argument it may be invalid. Perhaps: if (0 <= max_pio && max_pio <= 4) return (1 << max_pio) - 1; else return 0x01; Or is it common to trust the module arguments to be sane? > > +static void pata_at32_data_xfer(struct ata_device *adev, unsigned char > > *buf, + unsigned int buflen, int write_data) > > +{ > > + struct at32_ide_info *info = adev->ap->host->private_data; > > + > > + /* Set SMC to data transfer speed */ > > + if (info->smc_pio_mode < 3) > > + smc_restore_registers(info->cs, &info->smc_16.reg); > > + > > + /* Transfer data */ > > + ata_data_xfer(adev, buf, buflen, write_data); > > + > > + /* Set SMC back to register transfer speed */ > > + if (info->smc_pio_mode < 3) > > + smc_restore_registers(info->cs, &info->smc_8.reg); > > Should be safe currently for IRQ driven behaviour, might be for polled but > remember that without locking you could end up reading the status before > you switch the clock back so I'm not 100% sure. I now see that things can get messed up. I can alter the hardware so that a seperate SMC memory space for data and register transfer can be used, each with their respective timing set at all times. This will cost one extra chip select pin and an AND port on the adaptor, but it might be worth it? -- With kind regards Kristoffer Nyborg Gregertsen Student, Department of Engineering Cybernetics Norwegian University of Science and Technology Trondheim, Norway ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-07 17:39 ` Kristoffer Nyborg Gregertsen @ 2007-08-07 18:14 ` Jeff Garzik 2007-08-07 18:26 ` Kristoffer Nyborg Gregertsen 0 siblings, 1 reply; 13+ messages in thread From: Jeff Garzik @ 2007-08-07 18:14 UTC (permalink / raw) To: Kristoffer Nyborg Gregertsen Cc: Alan Cox, Kristoffer Nyborg Gregertsen, linux-ide Kristoffer Nyborg Gregertsen wrote: > On Tuesday 07 August 2007 17:54:09 Alan Cox wrote: >> +static int pata_at32_get_pio_mask(void) >> >>> +{ >>> + switch (max_pio) { >>> + case 0: >>> + return 0x01; >>> + case 1: >>> + return 0x03; >>> + case 2: >>> + return 0x07; >>> + case 3: >>> + return 0x0f; >>> + case 4: >>> + return 0x1f; >>> + default: >>> + return 0x01; >> What is wrong with just using (1 << max_pio) - 1 as the range is only >> 0-4 anyway. > > Since max_pio is a module argument it may be invalid. Perhaps: > > if (0 <= max_pio && max_pio <= 4) > return (1 << max_pio) - 1; > else > return 0x01; > > Or is it common to trust the module arguments to be sane? Well, a higher level issue, you should not have a max_pio module parameter at all. Other drivers do not have such a thing. Jeff ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-07 18:14 ` Jeff Garzik @ 2007-08-07 18:26 ` Kristoffer Nyborg Gregertsen 0 siblings, 0 replies; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-07 18:26 UTC (permalink / raw) To: Jeff Garzik; +Cc: Alan Cox, Kristoffer Nyborg Gregertsen, linux-ide, gregerts On Tuesday 07 August 2007 20:14:27 Jeff Garzik wrote: > Well, a higher level issue, you should not have a max_pio module > parameter at all. Other drivers do not have such a thing. OK, I'll remove it then. It was very convenient during automated testing of all PIO modes, but I guess that's not needed by the end users. -- With kind regards Kristoffer Nyborg Gregertsen Student, Department of Engineering Cybernetics Norwegian University of Science and Technology Trondheim, Norway ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-07 15:54 ` Alan Cox 2007-08-07 17:39 ` Kristoffer Nyborg Gregertsen @ 2007-08-08 14:57 ` Kristoffer Nyborg Gregertsen 2007-08-31 9:38 ` Jeff Garzik 1 sibling, 1 reply; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-08 14:57 UTC (permalink / raw) To: Alan Cox; +Cc: linux-ide, gregerts, kngregertsen 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 <kngregertsen@norway.atmel.com> --- diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4ad8675..f6b8dd2 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 8149c68..7c5e319 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 0000000..bb250a4 --- /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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/arch/board.h> +#include <asm/arch/smc.h> + +#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 <kngregertsen@norway.atmel.com>"); +MODULE_VERSION(DRV_VERSION); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-08 14:57 ` Kristoffer Nyborg Gregertsen @ 2007-08-31 9:38 ` Jeff Garzik 0 siblings, 0 replies; 13+ messages in thread From: Jeff Garzik @ 2007-08-31 9:38 UTC (permalink / raw) To: Kristoffer Nyborg Gregertsen; +Cc: Alan Cox, linux-ide, gregerts Kristoffer Nyborg Gregertsen wrote: > 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 <kngregertsen@norway.atmel.com> applied ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/1] AVR32 PATA driver 2007-08-07 9:26 [PATCH 0/1] AVR32 PATA driver Kristoffer Nyborg Gregertsen 2007-08-07 9:27 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen @ 2007-08-07 15:58 ` Alan Cox 2007-08-07 18:18 ` Kristoffer Nyborg Gregertsen 2007-08-14 6:41 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen 2 siblings, 1 reply; 13+ messages in thread From: Alan Cox @ 2007-08-07 15:58 UTC (permalink / raw) Cc: linux-ide, kngregertsen, gregerts > 1) In PIO1 and PIO2 there are rare freezes: > > ata3.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x2 frozen > ata3.00: cmd 20/00:00:d3:7e:5d/00:00:00:00:00/e1 tag 0 cdb 0x0 data 131072 in > res 58/00:01:d2:7f:5d/00:00:01:00:00/e1 Emask 0x2 (HSM violation) > > The freezes happen close to each other in time. The freezes does not make file > operations fail. Are you 100% sure all your timings are right and there are no I/O posting prolems that might lead the various required delays to come out wrong ? > 2) After being in operation for a long time (+24 hours) the disk reports wrong > identity: > > ata4.00: model number mismatch 'IC35L060AVV207-0' != '' > ata4.00: revalidation failed (errno=-19) > ata4.00: limiting speed to PIO2 > ata4: failed to recover some devices, retrying in 5 secs > ata4.00: model number mismatch 'IC35L060AVV207-0' != 'AV07-0 *GARBEL* > > This has happend with both the devices I am testing, the 'Quantum Fireball' > reported it self to be 'Quanpum Fiveball' after 24 hours of testing. That sounds to me like your hardware - heat, clock drift ? > I also have a question regrding INTRQ / IRQ handeling. Since I am not using > DMA, there seems to be no reason to handle interrupts, so I set the polling > flag. Not using the polling flag gives a lot of interrupts that does not seem > to do anything except eating my CPU cycles. Is this correct? > > If so, what shall I do when activating the host to not get "irq 65: nobody > cared" ... "Disabling IRQ #65". Should I give an negative irq number? When you get an IRQ you need to clear the IRQ status. Good question why you are getting them but you may well do in the resetting phases even with nIEN in use. OTOH if you get one or two per command then someone must have nIEN wrong on command issue. Either way you need to clear down IRQs that occur - some hardware doesn't get nIEN right and interrupts anyway in some cases. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/1] AVR32 PATA driver 2007-08-07 15:58 ` [PATCH 0/1] " Alan Cox @ 2007-08-07 18:18 ` Kristoffer Nyborg Gregertsen 0 siblings, 0 replies; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-07 18:18 UTC (permalink / raw) To: Alan Cox; +Cc: Kristoffer Nyborg Gregertsen, linux-ide, gregerts On Tuesday 07 August 2007 17:58:12 Alan Cox wrote: > > 1) In PIO1 and PIO2 there are rare freezes: > > > > ata3.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x2 frozen > > ata3.00: cmd 20/00:00:d3:7e:5d/00:00:00:00:00/e1 tag 0 cdb 0x0 data > > 131072 in res 58/00:01:d2:7f:5d/00:00:01:00:00/e1 Emask 0x2 (HSM > > violation) > > > > The freezes happen close to each other in time. The freezes does not make > > file operations fail. > > Are you 100% sure all your timings are right and there are no I/O posting > prolems that might lead the various required delays to come out wrong ? I've looked at the signals with a logic analyzer, they seem to be correct. The timings are computed by ata_timing_compute. I've also added pull-up resistors on all the control signals just to make sure they are always sane. Since the there is no problems for PIO3 and 4, perhaps this error is related to the problem of pata_at32_data_xfer being non-atomic while changing the SMC timings that you addressed in your other mail? > + /* Set SMC to data transfer speed */ > + if (info->smc_pio_mode < 3) > + smc_restore_registers(info->cs, &info->smc_16.reg); > + > + /* Transfer data */ > + ata_data_xfer(adev, buf, buflen, write_data); > + > + /* Set SMC back to register transfer speed */ > + if (info->smc_pio_mode < 3) > + smc_restore_registers(info->cs, &info->smc_8.reg); I'll test to see if this is causing the errors. If so I'll setup different memory spaces for data and register transfers as described in the my last mail. > > 2) After being in operation for a long time (+24 hours) the disk reports > > wrong identity: > > > > ata4.00: model number mismatch 'IC35L060AVV207-0' != '' > > ata4.00: revalidation failed (errno=-19) > > ata4.00: limiting speed to PIO2 > > ata4: failed to recover some devices, retrying in 5 secs > > ata4.00: model number mismatch 'IC35L060AVV207-0' != 'AV07-0 *GARBEL* > > > > This has happend with both the devices I am testing, the 'Quantum > > Fireball' reported it self to be 'Quanpum Fiveball' after 24 hours of > > testing. > > That sounds to me like your hardware - heat, clock drift ? Perhaps it's heat. The disks lie on my desk with no ventilation besides the air circulating in the room. Turning them off for a little while solves the problem. > > I also have a question regrding INTRQ / IRQ handeling. Since I am not > > using DMA, there seems to be no reason to handle interrupts, so I set the > > polling flag. Not using the polling flag gives a lot of interrupts that > > does not seem to do anything except eating my CPU cycles. Is this > > correct? > > > > If so, what shall I do when activating the host to not get "irq 65: > > nobody cared" ... "Disabling IRQ #65". Should I give an negative irq > > number? > > When you get an IRQ you need to clear the IRQ status. Good question why > you are getting them but you may well do in the resetting phases even > with nIEN in use. > > OTOH if you get one or two per command then someone must have nIEN wrong > on command issue. Either way you need to clear down IRQs that occur - > some hardware doesn't get nIEN right and interrupts anyway in some cases. I just read in the ATA spec and realize that I need to add a pull-down resistor on the INTRQ signal. The signal is now floating when nIEN is set. I feel silly, sorry to bother you with HW design faults :) -- With kind regards Kristoffer Nyborg Gregertsen Student, Department of Engineering Cybernetics Norwegian University of Science and Technology Trondheim, Norway ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/1] AVR32 PATA driver 2007-08-07 9:26 [PATCH 0/1] AVR32 PATA driver Kristoffer Nyborg Gregertsen 2007-08-07 9:27 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen 2007-08-07 15:58 ` [PATCH 0/1] " Alan Cox @ 2007-08-14 6:41 ` Kristoffer Nyborg Gregertsen 2007-08-14 6:53 ` Kristoffer Nyborg Gregertsen 2 siblings, 1 reply; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-14 6:41 UTC (permalink / raw) To: linux-ide; +Cc: gregerts, kngregertsen, kernel, Haavard Skinnemoen This patch adds support for PATA devices on the AVR32 using the CompactFlash controller in 'True IDE mode'. DMA is currently not supported due to lack of DMACK pins on the current AP7000 series. Tested on AP7000 / STK1000. Signed-off-by: Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com> --- diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4ad8675..f6b8dd2 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 8149c68..7c5e319 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 0000000..cd20d4a --- /dev/null +++ b/drivers/ata/pata_at32.c @@ -0,0 +1,443 @@ +/* + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/arch/board.h> +#include <asm/arch/smc.h> + +#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 + * + * Alter PIO_MASK below according to table to set maximal PIO mode. + */ +#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) +{ + /* Values found through testing */ + const int min_recover = 30; + const int ncs_delay = 10; + const int ncs_hold = 20; + + 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 + ncs_delay; + smc->nrd_pulse = timing->act8b; + + /* Compute recovery time, 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 = ncs_delay; + smc->ncs_read_pulse = active + ncs_hold - ncs_delay; + + /* 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 of SMC timings */ + 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_setup + 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; + + /* + * 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 SMC to ATA timing */ + ret = pata_at32_setup_timing(dev, info, &initial_timing); + if (ret) + goto err_setup_timing; + + /* Map ATA address space */ + 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 + + /* Setup and 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 <kngregertsen@norway.atmel.com>"); +MODULE_VERSION(DRV_VERSION); ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-14 6:41 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen @ 2007-08-14 6:53 ` Kristoffer Nyborg Gregertsen 2007-08-15 8:44 ` Kristoffer Nyborg Gregertsen 0 siblings, 1 reply; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-14 6:53 UTC (permalink / raw) To: linux-ide; +Cc: gregerts, kernel, Haavard Skinnemoen, kngregertsen Hi again everybody, The driver is now working very nicely. The sporadic errors I reported earlier were mostly due to the state of the EBI to ATA adaptor prototype card. I have also added some time before R/W strobe to make sure signals are stable. The only thing that bothers me is the huge number of interrupts that occurs during data transfers. There is one interrupt for every ~500 bytes or so: -sh-3.2# cat /proc/interrupts ... 65: 62015176 eic at32_ide -sh-3.2# dd if=/dev/zero of=zero.dat count=10k 10240+0 records in 10240+0 records out -sh-3.2# cat /proc/interrupts ... 65: 62025176 eic at32_ide Would I be better off using polling mode? -- Kristoffer Nyborg Gregertsen MSc. student / Summer intern Atmel Norway ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/1] AVR32 PATA driver 2007-08-14 6:53 ` Kristoffer Nyborg Gregertsen @ 2007-08-15 8:44 ` Kristoffer Nyborg Gregertsen 0 siblings, 0 replies; 13+ messages in thread From: Kristoffer Nyborg Gregertsen @ 2007-08-15 8:44 UTC (permalink / raw) To: linux-ide; +Cc: gregerts, kernel, Haavard Skinnemoen, kngregertsen Forget about what I said about using polling, I was just fooled by the benchmark tool. Could the last patch I've sent you be accepted? - Kristoffer Nyborg Gregertsen ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2007-08-31 9:38 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-08-07 9:26 [PATCH 0/1] AVR32 PATA driver Kristoffer Nyborg Gregertsen 2007-08-07 9:27 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen 2007-08-07 15:54 ` Alan Cox 2007-08-07 17:39 ` Kristoffer Nyborg Gregertsen 2007-08-07 18:14 ` Jeff Garzik 2007-08-07 18:26 ` Kristoffer Nyborg Gregertsen 2007-08-08 14:57 ` Kristoffer Nyborg Gregertsen 2007-08-31 9:38 ` Jeff Garzik 2007-08-07 15:58 ` [PATCH 0/1] " Alan Cox 2007-08-07 18:18 ` Kristoffer Nyborg Gregertsen 2007-08-14 6:41 ` [PATCH 1/1] " Kristoffer Nyborg Gregertsen 2007-08-14 6:53 ` Kristoffer Nyborg Gregertsen 2007-08-15 8:44 ` Kristoffer Nyborg Gregertsen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).