* [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT @ 2007-03-30 11:00 Russell King 2007-03-30 11:08 ` [RFC] pata_platform for ARM RiscPC Russell King 2007-03-30 11:08 ` [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Christoph Hellwig 0 siblings, 2 replies; 19+ messages in thread From: Russell King @ 2007-03-30 11:00 UTC (permalink / raw) To: linux-kernel, Andrew Morton, Al Viro Provide an dummy implementation of devm_ioport_map() and devm_ioport_unmap() to allow drivers (eg, pata_platform) to build for platforms where CONFIG_NO_IOPORT is selected. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- include/linux/io.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/io.h b/include/linux/io.h index c244a0c..8cf8df6 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -33,9 +33,22 @@ int ioremap_page_range(unsigned long addr, unsigned long end, /* * Managed iomap interface */ +#ifdef CONFIG_HAS_IOPORT void __iomem * devm_ioport_map(struct device *dev, unsigned long port, unsigned int nr); void devm_ioport_unmap(struct device *dev, void __iomem *addr); +#else +static inline void __iomem * devm_ioport_map(struct device *dev, + unsigned long port, + unsigned int nr) +{ + return NULL; +} + +static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr) +{ +} +#endif void __iomem * devm_ioremap(struct device *dev, unsigned long offset, unsigned long size); -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC] pata_platform for ARM RiscPC 2007-03-30 11:00 [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Russell King @ 2007-03-30 11:08 ` Russell King 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King 2007-04-09 11:32 ` [RFC] pata_platform for ARM RiscPC Jeff Garzik 2007-03-30 11:08 ` [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Christoph Hellwig 1 sibling, 2 replies; 19+ messages in thread From: Russell King @ 2007-03-30 11:08 UTC (permalink / raw) To: linux-kernel, Andrew Morton, Jeff Garzik Add pata_platform device for RiscPC, thereby converting the primary IDE channel on the machine to PATA. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> --- Since this is dependent on the previous patch (to avoid build errors) this needs to wait until the devm_ioport patch is merged. I'll therefore push this through the ARM tree at the appropriate time. arch/arm/mach-rpc/riscpc.c | 35 +++++++++++++++++++++++++++++++++++ drivers/ata/Kconfig | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c index 208a2b5..711a2db 100644 --- a/arch/arm/mach-rpc/riscpc.c +++ b/arch/arm/mach-rpc/riscpc.c @@ -17,6 +17,7 @@ #include <linux/sched.h> #include <linux/device.h> #include <linux/serial_8250.h> +#include <linux/pata_platform.h> #include <asm/elf.h> #include <asm/io.h> @@ -159,11 +160,45 @@ static struct plat_serial8250_port serial_platform_data[] = { }, }; +static struct pata_platform_info pata_platform_data = { + .ioport_shift = 2, +}; + +static struct resource pata_resources[] = { + [0] = { + .start = 0x030107c0, + .end = 0x030107df, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x03010fd8, + .end = 0x03010fdb, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_HARDDISK, + .end = IRQ_HARDDISK, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pata_device = { + .name = "pata_platform", + .id = -1, + .num_resources = ARRAY_SIZE(pata_resources), + .resource = pata_resources, + .dev = { + .platform_data = &pata_platform_data, + .coherent_dma_mask = ~0, /* grumble */ + }, +}; + static struct platform_device *devs[] __initdata = { &iomd_device, &kbd_device, &serial_device, &acornfb_device, + &pata_device, }; static int __init rpc_init(void) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d16b5b0..d8a9758 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -545,7 +545,7 @@ config PATA_WINBOND_VLB config PATA_PLATFORM tristate "Generic platform device PATA support" - depends on EMBEDDED + depends on EMBEDDED || ARCH_RPC help This option enables support for generic directly connected ATA devices commonly found on embedded systems. -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-03-30 11:08 ` [RFC] pata_platform for ARM RiscPC Russell King @ 2007-04-08 10:18 ` Russell King 2007-04-08 18:59 ` Alan Cox ` (2 more replies) 2007-04-09 11:32 ` [RFC] pata_platform for ARM RiscPC Jeff Garzik 1 sibling, 3 replies; 19+ messages in thread From: Russell King @ 2007-04-08 10:18 UTC (permalink / raw) To: linux-kernel, Andrew Morton, Jeff Garzik Below is an initial attempt at converting the ICS IDE driver to fit into the PATA infrastructure. There's a number of FIXMEs in there: due to the hardware missing resistors on the interrupt signals from the drives, a port without any drives attached results in spurious interrupts being generated. To prevent this, we need to disable the interrupts from the port on the card if no drives are found, but unfortunately ATA doesn't call the "port_disable" method in this circumstance. The second FIXME area is ata_irq_ack - it is unconditionally coded for SFF-type interfaces. I believe that using this function in non-BMDMA interfaces is wrong - it attempts to read from the BMDMA registers irrespective of whether ap->ioaddr.bmdma_addr is set or not. The question this poses is: what should non-BMDMA implementations use for this method? Note that pata_platform also uses this function despite not supporting BMDMA which seems even more suspicious. diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7bdbe5a..9cd8a61 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -552,6 +552,14 @@ config PATA_PLATFORM If unsure, say N. +config PATA_ICSIDE + tristate "Acorn ICS PATA support" + depends on ARM && ARCH_ACORN + help + On Acorn systems, say Y here if you wish to use the ICS PATA + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. + config PATA_IXP4XX_CF tristate "IXP4XX Compact Flash support" depends on ARCH_IXP4XX diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 13d7397..cc8798b 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o +obj-$(CONFIG_PATA_ICSIDE) += pata_icside.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_icside.c b/drivers/ata/pata_icside.c new file mode 100644 index 0000000..68eecfc --- /dev/null +++ b/drivers/ata/pata_icside.c @@ -0,0 +1,679 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> + +#include <asm/dma.h> +#include <asm/ecard.h> + +#define DRV_NAME "pata_icside" + +#define ICS_IDENT_OFFSET 0x2280 + +#define ICS_ARCIN_V5_INTRSTAT 0x0000 +#define ICS_ARCIN_V5_INTROFFSET 0x0004 + +#define ICS_ARCIN_V6_INTROFFSET_1 0x2200 +#define ICS_ARCIN_V6_INTRSTAT_1 0x2290 +#define ICS_ARCIN_V6_INTROFFSET_2 0x3200 +#define ICS_ARCIN_V6_INTRSTAT_2 0x3290 + +struct portinfo { + unsigned int dataoffset; + unsigned int ctrloffset; + unsigned int stepping; +}; + +static const struct portinfo pata_icside_portinfo_v5 = { + .dataoffset = 0x2800, + .ctrloffset = 0x2b80, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_1 = { + .dataoffset = 0x2000, + .ctrloffset = 0x2380, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_2 = { + .dataoffset = 0x3000, + .ctrloffset = 0x3380, + .stepping = 6, +}; + +#define PATA_ICSIDE_MAX_SG 128 + +struct pata_icside_state { + void __iomem *irq_port; + void __iomem *ioc_base; + unsigned int type; + unsigned int dma; + struct { + u8 port_sel; + u8 disabled; + unsigned int speed[ATA_MAX_DEVICES]; + } port[2]; + struct scatterlist sg[PATA_ICSIDE_MAX_SG]; +}; + +#define ICS_TYPE_A3IN 0 +#define ICS_TYPE_A3USER 1 +#define ICS_TYPE_V6 3 +#define ICS_TYPE_V5 15 +#define ICS_TYPE_NOTYPE ((unsigned int)-1) + +/* ---------------- Version 5 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v5 = { + .irqenable = pata_icside_irqenable_arcin_v5, + .irqdisable = pata_icside_irqdisable_arcin_v5, +}; + + +/* ---------------- Version 6 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + void __iomem *base = state->irq_port; + + if (!state->port[0].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); + if (!state->port[1].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + struct pata_icside_state *state = ec->irq_data; + + return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v6 = { + .irqenable = pata_icside_irqenable_arcin_v6, + .irqdisable = pata_icside_irqdisable_arcin_v6, + .irqpending = pata_icside_irqpending_arcin_v6, +}; + + +/* + * SG-DMA support. + * + * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. + * There is only one DMA controller per card, which means that only + * one drive can be accessed at one time. NOTE! We do not enforce that + * here, but we rely on the main IDE driver spotting that both + * interfaces use the same IRQ, which should guarantee this. + */ + +/* + * Configure the IOMD to give the appropriate timings for the transfer + * mode being requested. We take the advice of the ATA standards, and + * calculate the cycle time based on the transfer mode, and the EIDE + * MW DMA specs that the drive provides in the IDENTIFY command. + * + * We have the following IOMD DMA modes to choose from: + * + * Type Active Recovery Cycle + * A 250 (250) 312 (550) 562 (800) + * B 187 (200) 250 (550) 437 (750) + * C 125 (125) 125 (375) 250 (500) + * D 62 (50) 125 (375) 187 (425) + * + * (figures in brackets are actual measured timings on DIOR/DIOW) + * + * However, we also need to take care of the read/write active and + * recovery timings: + * + * Read Write + * Mode Active -- Recovery -- Cycle IOMD type + * MW0 215 50 215 480 A + * MW1 80 50 50 150 C + * MW2 70 25 25 120 C + */ +static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pata_icside_state *state = ap->host->private_data; + struct ata_timing t; + unsigned int cycle; + char iomd_type; + + /* + * DMA is based on a 16MHz clock + */ + if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1)) + return; + + /* + * Now, properly adjust the timings. If we have a 62.5ns clock + * period and we ask for MWDMA2, it calculates the following + * timings: active 125ns, recovery 62.5ns, cycle 125ns. + * Quite obviously bogus. Tweak the cycle time to be sufficiently + * long to satisfy the active and recovery time. + */ + if (t.active + t.recover > t.cycle) + t.cycle = t.active + t.recover; + + /* + * Choose the IOMD cycle timing which ensure that the interface + * satisfies the measured active, recovery and cycle times. + */ + if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425) + iomd_type = 'D', cycle = 187; + else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500) + iomd_type = 'C', cycle = 250; + else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750) + iomd_type = 'B', cycle = 437; + else + iomd_type = 'A', cycle = 562; + + ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n", + t.active, t.recover, t.cycle, iomd_type); + + state->port[ap->port_no].speed[adev->devno] = cycle; +} + +static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + struct scatterlist *sg, *rsg = state->sg; + unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE; + + /* + * We are simplex; BUG if we try to fiddle with DMA + * while it's active. + */ + BUG_ON(dma_channel_active(state->dma)); + + /* + * Copy ATAs scattered sg list into a contiguous array of sg + */ + ata_for_each_sg(sg, qc) { + memcpy(rsg, sg, sizeof(*sg)); + rsg++; + } + + /* + * Route the DMA signals to the correct interface + */ + writeb(state->port[ap->port_no].port_sel, state->ioc_base); + + set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]); + set_dma_sg(state->dma, state->sg, rsg - state->sg); + set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ); + + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +static void pata_icside_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + BUG_ON(dma_channel_active(state->dma)); + enable_dma(state->dma); +} + +static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + disable_dma(state->dma); + + /* see ata_bmdma_stop */ + ata_altstatus(ap); +} + +static u8 pata_icside_bmdma_status(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + void __iomem *irq_port; + + irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 : + ICS_ARCIN_V6_INTRSTAT_1); + + return readb(irq_port) & 1 ? ATA_DMA_INTR : 0; +} + +static int icside_dma_init(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + state->port[0].speed[i] = 480; + state->port[1].speed[i] = 480; + } + + if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { + state->dma = ec->dma; + ae->mwdma_mask = 0x07; /* MW0..2 */ + } + + return 0; +} + + +static int pata_icside_port_start(struct ata_port *ap) +{ + /* No PRD to alloc */ + return ata_pad_alloc(ap, ap->dev); +} + +static struct scsi_host_template pata_icside_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 = PATA_ICSIDE_MAX_SG, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ~0, /* no dma boundaries */ + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +/* wish this was exported from libata-core */ +static void ata_dummy_noret(struct ata_port *port) +{ +} + +/* + * We need to shut down unused ports to prevent spurious interrupts. + * FIXME: the libata core doesn't call this function for PATA interfaces. + */ +static void pata_icside_port_disable(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + + ata_port_printk(ap, KERN_ERR, "disabling icside port\n"); + + ata_port_disable(ap); + + state->port[ap->port_no].disabled = 1; + + if (state->type == ICS_TYPE_V6) { + /* + * Disable interrupts from this port, otherwise we + * receive spurious interrupts from the floating + * interrupt line. + */ + void __iomem *irq_port = state->irq_port + + (ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1); + readb(irq_port); + } +} + +static struct ata_port_operations pata_icside_port_ops = { + .port_disable = pata_icside_port_disable, + + .set_dmamode = pata_icside_set_dmamode, + + .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, + + .bmdma_setup = pata_icside_bmdma_setup, + .bmdma_start = pata_icside_bmdma_start, + + .data_xfer = ata_data_xfer_noirq, + + /* no need to build any PRD tables for DMA */ + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = pata_icside_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = ata_dummy_noret, + .irq_on = ata_irq_on, + .irq_ack = ata_irq_ack, /* FIXME */ + + .port_start = pata_icside_port_start, + + .bmdma_stop = pata_icside_bmdma_stop, + .bmdma_status = pata_icside_bmdma_status, +}; + +static void +pata_icside_add_port(struct ata_probe_ent *ae, void __iomem *base, + const struct portinfo *info) +{ + struct ata_ioports *ioaddr = &ae->port[ae->n_ports++]; + void __iomem *cmd = base + info->dataoffset; + + ioaddr->cmd_addr = cmd; + ioaddr->data_addr = cmd + (ATA_REG_DATA << info->stepping); + ioaddr->error_addr = cmd + (ATA_REG_ERR << info->stepping); + ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << info->stepping); + ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << info->stepping); + ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << info->stepping); + ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << info->stepping); + ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << info->stepping); + ioaddr->device_addr = cmd + (ATA_REG_DEVICE << info->stepping); + ioaddr->status_addr = cmd + (ATA_REG_STATUS << info->stepping); + ioaddr->command_addr = cmd + (ATA_REG_CMD << info->stepping); + + ioaddr->ctl_addr = base + info->ctrloffset; + ioaddr->altstatus_addr = ioaddr->ctl_addr; +} + +static int __init +pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *base; + + base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), + ecard_resource_len(ec, ECARD_RES_MEMC)); + if (!base) + return -ENOMEM; + + state->irq_port = base; + + ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; + ec->irqmask = 1; + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v5; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + pata_icside_add_port(ae, base, &pata_icside_portinfo_v5); + + return 0; +} + +static int __init +pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *ioc_base, *easi_base; + unsigned int sel = 0; + int ret; + + ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (!ioc_base) { + ret = -ENOMEM; + goto out; + } + + easi_base = ioc_base; + + if (ecard_resource_flags(ec, ECARD_RES_EASI)) { + easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI), + ecard_resource_len(ec, ECARD_RES_EASI)); + if (!easi_base) { + ret = -ENOMEM; + goto unmap_slot; + } + + /* + * Enable access to the EASI region. + */ + sel = 1 << 5; + } + + writeb(sel, ioc_base); + + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v6; + + state->irq_port = easi_base; + state->ioc_base = ioc_base; + state->port[0].port_sel = sel; + state->port[1].port_sel = sel | 1; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + /* + * Find and register the interfaces. + */ + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_1); + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_2); + + /* + * FIXME: work around libata's aversion to calling port_disable. + * This permanently disables interrupts on port 0 - bad luck if + * you have a drive on that port. + */ + state->port[0].disabled = 1; + + return icside_dma_init(ae, ec); + + unmap_slot: + iounmap(ioc_base); + out: + return ret; +} + +static int __devinit +pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + struct pata_icside_state *state; + struct ata_probe_ent ae; + void __iomem *idmem; + int ret; + + ret = ecard_request_resources(ec); + if (ret) + goto out; + + state = kzalloc(sizeof(struct pata_icside_state), GFP_KERNEL); + if (!state) { + ret = -ENOMEM; + goto release; + } + + state->type = ICS_TYPE_NOTYPE; + state->dma = NO_DMA; + + idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (idmem) { + unsigned int type; + + type = readb(idmem + ICS_IDENT_OFFSET) & 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2; + type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3; + iounmap(idmem); + + state->type = type; + } + + memset(&ae, 0, sizeof(ae)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &ec->dev; + ae.port_ops = &pata_icside_port_ops; + ae.sht = &pata_icside_sht; + ae.pio_mask = 0x1f; + ae.irq = ec->irq; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae._host_flags = ATA_HOST_SIMPLEX; + ae.private_data = state; + + switch (state->type) { + case ICS_TYPE_A3IN: + dev_warn(&ec->dev, "A3IN unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_A3USER: + dev_warn(&ec->dev, "A3USER unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_V5: + ret = pata_icside_register_v5(&ae, ec); + break; + + case ICS_TYPE_V6: + ret = pata_icside_register_v6(&ae, ec); + break; + + default: + dev_warn(&ec->dev, "unknown interface type\n"); + ret = -ENODEV; + break; + } + + if (ret == 0) + ret = ata_device_add(&ae) == 0 ? -ENODEV : 0; + + if (ret == 0) + goto out; + + kfree(state); + release: + ecard_release_resources(ec); + out: + return ret; +} + +static void pata_icside_shutdown(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + unsigned long flags; + + /* + * Disable interrupts from this card. We need to do + * this before disabling EASI since we may be accessing + * this register via that region. + */ + local_irq_save(flags); + if (ec->ops) + ec->ops->irqdisable(ec, ec->irq); + local_irq_restore(flags); + + /* + * Reset the ROM pointer so that we can read the ROM + * after a soft reboot. This also disables access to + * the IDE taskfile via the EASI region. + */ + if (host) { + struct pata_icside_state *state = host->private_data; + if (state->ioc_base) + writeb(0, state->ioc_base); + } +} + +static void __devexit pata_icside_remove(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + struct pata_icside_state *state = host->private_data; + + ata_host_detach(host); + + pata_icside_shutdown(ec); + + /* + * don't NULL out the drvdata - devres/libata wants it + * to free the ata_host structure. + */ + ec->ops = NULL; + ec->irq_data = NULL; + + if (state->dma != NO_DMA) + free_dma(state->dma); + if (state->ioc_base) + iounmap(state->ioc_base); + if (state->ioc_base != state->irq_port) + iounmap(state->irq_port); + + kfree(state); + ecard_release_resources(ec); +} + +static const struct ecard_id pata_icside_ids[] = { + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver pata_icside_driver = { + .probe = pata_icside_probe, + .remove = __devexit_p(pata_icside_remove), + .shutdown = pata_icside_shutdown, + .id_table = pata_icside_ids, + .drv = { + .name = DRV_NAME, + }, +}; + +static int __init pata_icside_init(void) +{ + return ecard_register_driver(&pata_icside_driver); +} + +static void __exit pata_icside_exit(void) +{ + ecard_remove_driver(&pata_icside_driver); +} + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ICS PATA driver"); + +module_init(pata_icside_init); +module_exit(pata_icside_exit); -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King @ 2007-04-08 18:59 ` Alan Cox 2007-04-09 1:03 ` Jeff Garzik 2007-04-08 20:09 ` Alan Cox 2007-04-21 15:09 ` Russell King 2 siblings, 1 reply; 19+ messages in thread From: Alan Cox @ 2007-04-08 18:59 UTC (permalink / raw) To: Russell King; +Cc: linux-kernel, Andrew Morton, Jeff Garzik > The second FIXME area is ata_irq_ack - it is unconditionally coded > for SFF-type interfaces. I believe that using this function in > non-BMDMA interfaces is wrong - it attempts to read from the BMDMA > registers irrespective of whether ap->ioaddr.bmdma_addr is set or > not. The question this poses is: what should non-BMDMA implementations > use for this method? Note that pata_platform also uses this > function despite not supporting BMDMA which seems even more suspicious. Thats a bug that has arrived again. The older code was corrected to handle this properly but the fix appears to have become lost. The ioread/iowrite code actually made quite a mess (all the address reporting is also broken) and we do some iffy things like compare the iomap result with zero and assume thats the same as checking for true bus zero addresses. ata_irq_ack is part of the SFF layer so its fine that it assumes SFF but its wrong that it is used unconditionally and it shouldn't be used this way. It just needs a (!ap->ioaddr.bmdma_addr) test adding (assuming thats valid for iomap) Alan ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-08 18:59 ` Alan Cox @ 2007-04-09 1:03 ` Jeff Garzik 2007-04-09 9:56 ` Alan Cox 0 siblings, 1 reply; 19+ messages in thread From: Jeff Garzik @ 2007-04-09 1:03 UTC (permalink / raw) To: Alan Cox; +Cc: Russell King, linux-kernel, Andrew Morton Alan Cox wrote: >> The second FIXME area is ata_irq_ack - it is unconditionally coded >> for SFF-type interfaces. I believe that using this function in >> non-BMDMA interfaces is wrong - it attempts to read from the BMDMA >> registers irrespective of whether ap->ioaddr.bmdma_addr is set or >> not. The question this poses is: what should non-BMDMA implementations >> use for this method? Note that pata_platform also uses this >> function despite not supporting BMDMA which seems even more suspicious. > > Thats a bug that has arrived again. The older code was corrected to > handle this properly but the fix appears to have become lost. The > ioread/iowrite code actually made quite a mess (all the address reporting > is also broken) and we do some iffy things like compare the iomap result > with zero and assume thats the same as checking for true bus zero > addresses. > > ata_irq_ack is part of the SFF layer so its fine that it assumes SFF but > its wrong that it is used unconditionally and it shouldn't be used this > way. It just needs a (!ap->ioaddr.bmdma_addr) test adding (assuming thats > valid for iomap) No. It does not need such a test, as it requires BMDMA, not just an SFF-style Status register. It is up to the driver to decide whether or not ata_irq_ack() is appropriate for your hardware. pata_icside needs its own ata_irq_ack -- which may just be as simple as reading the Status register to clear the interrupt condition. If others need this as well, ata_sff_irq_ack() would be a good generic function to create. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 1:03 ` Jeff Garzik @ 2007-04-09 9:56 ` Alan Cox 2007-04-09 10:56 ` Jeff Garzik 0 siblings, 1 reply; 19+ messages in thread From: Alan Cox @ 2007-04-09 9:56 UTC (permalink / raw) To: Jeff Garzik; +Cc: Russell King, linux-kernel, Andrew Morton On Sun, 08 Apr 2007 21:03:10 -0400 Jeff Garzik <jgarzik@pobox.com> wrote: > > ata_irq_ack is part of the SFF layer so its fine that it assumes SFF but > > its wrong that it is used unconditionally and it shouldn't be used this > > way. It just needs a (!ap->ioaddr.bmdma_addr) test adding (assuming thats > > valid for iomap) > > No. It does not need such a test, as it requires BMDMA, not just an > SFF-style Status register. It is up to the driver to decide whether or > not ata_irq_ack() is appropriate for your hardware. Then no SFF hardware can use ata_irq_ack. Not one card: Because in every case it is permissible that BAR4 is not allocated and the device is running non-DMA, or that the SFF hardware does not support DMA. > pata_icside needs its own ata_irq_ack -- which may just be as simple as > reading the Status register to clear the interrupt condition. > > If others need this as well, ata_sff_irq_ack() would be a good generic > function to create. We should just rename ata_irq_ack(). It is in libata-sff, so it's either wrong (missing a test), or in the wrong file completely. Alan ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 9:56 ` Alan Cox @ 2007-04-09 10:56 ` Jeff Garzik 2007-04-09 11:13 ` Jeff Garzik 0 siblings, 1 reply; 19+ messages in thread From: Jeff Garzik @ 2007-04-09 10:56 UTC (permalink / raw) To: Alan Cox; +Cc: Russell King, linux-kernel, Andrew Morton Alan Cox wrote: > Then no SFF hardware can use ata_irq_ack. Not one card: Because in every OK > We should just rename ata_irq_ack(). It is in libata-sff, so it's either > wrong (missing a test), or in the wrong file completely. There is plenty of BMDMA-specific stuff in libata-sff, so neither assertion is correct. It's fine to rename it, though. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 10:56 ` Jeff Garzik @ 2007-04-09 11:13 ` Jeff Garzik 2007-04-09 11:36 ` Russell King 0 siblings, 1 reply; 19+ messages in thread From: Jeff Garzik @ 2007-04-09 11:13 UTC (permalink / raw) To: Alan Cox, Russell King; +Cc: linux-kernel, Andrew Morton It should be noted, mainly for russell's benefit, that the ->irq_ack() hook is only called if a debug define is manually enabled in libata.h, in a single callsite. The number of people that actually use the hook -- kernel hackers debugging screaming interrupts -- can probably be counted on one hand. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 11:13 ` Jeff Garzik @ 2007-04-09 11:36 ` Russell King 2007-04-09 12:02 ` Jeff Garzik 0 siblings, 1 reply; 19+ messages in thread From: Russell King @ 2007-04-09 11:36 UTC (permalink / raw) To: Jeff Garzik; +Cc: Alan Cox, linux-kernel, Andrew Morton On Mon, Apr 09, 2007 at 07:13:05AM -0400, Jeff Garzik wrote: > It should be noted, mainly for russell's benefit, that the ->irq_ack() > hook is only called if a debug define is manually enabled in libata.h, > in a single callsite. > > The number of people that actually use the hook -- kernel hackers > debugging screaming interrupts -- can probably be counted on one hand. Ok, in that case it makes sense for me to set this to ata_dummy_irq_ack since I don't have any additional status registers specific to the interface. Presumably a similar change to pata_platform.c would be appropriate? -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 11:36 ` Russell King @ 2007-04-09 12:02 ` Jeff Garzik 0 siblings, 0 replies; 19+ messages in thread From: Jeff Garzik @ 2007-04-09 12:02 UTC (permalink / raw) To: Jeff Garzik, Alan Cox, linux-kernel, Andrew Morton Russell King wrote: > On Mon, Apr 09, 2007 at 07:13:05AM -0400, Jeff Garzik wrote: >> It should be noted, mainly for russell's benefit, that the ->irq_ack() >> hook is only called if a debug define is manually enabled in libata.h, >> in a single callsite. >> >> The number of people that actually use the hook -- kernel hackers >> debugging screaming interrupts -- can probably be counted on one hand. > > Ok, in that case it makes sense for me to set this to ata_dummy_irq_ack > since I don't have any additional status registers specific to the > interface. > > Presumably a similar change to pata_platform.c would be appropriate? I was just pointing out the practical reality. The proper implementation of the hook is likely /not/ a dummy on your platform. I presume you clear the interrupt condition by reading the ATA shadow register 'Status', like most other SFF-like controllers, so your implementation of ->irq_ack() should reflect that. The proper implementation is basically what Alan described: ata_irq_ack() minus the BMDMA bitbanging. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King 2007-04-08 18:59 ` Alan Cox @ 2007-04-08 20:09 ` Alan Cox 2007-04-09 8:18 ` Russell King 2007-04-21 15:09 ` Russell King 2 siblings, 1 reply; 19+ messages in thread From: Alan Cox @ 2007-04-08 20:09 UTC (permalink / raw) To: Russell King; +Cc: linux-kernel, Andrew Morton, Jeff Garzik > + /* > + * DMA is based on a 16MHz clock > + */ > + if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1)) > + return; This seems strange for a 16MHz clock. > + > + /* > + * Now, properly adjust the timings. If we have a 62.5ns clock > + * period and we ask for MWDMA2, it calculates the following > + * timings: active 125ns, recovery 62.5ns, cycle 125ns. > + * Quite obviously bogus. NAK. At this point you need to work out why you are getting bogus results and fix it or demonstrate a bug in the core code and fix that. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-08 20:09 ` Alan Cox @ 2007-04-09 8:18 ` Russell King 2007-04-09 8:24 ` Roland Dreier 2007-04-09 10:25 ` Alan Cox 0 siblings, 2 replies; 19+ messages in thread From: Russell King @ 2007-04-09 8:18 UTC (permalink / raw) To: Alan Cox; +Cc: linux-kernel, Andrew Morton, Jeff Garzik On Sun, Apr 08, 2007 at 09:09:17PM +0100, Alan Cox wrote: > > + /* > > + * DMA is based on a 16MHz clock > > + */ > > + if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1)) > > + return; > > This seems strange for a 16MHz clock. We do this because, although the underlying clock is 16MHz, the DIOR and DIOW signals go through a bit of logic and are not synchronised to this clock. As explained in the comments above: + * Type Active Recovery Cycle + * A 250 (250) 312 (550) 562 (800) + * B 187 (200) 250 (550) 437 (750) + * C 125 (125) 125 (375) 250 (500) + * D 62 (50) 125 (375) 187 (425) + * + * (figures in brackets are actual measured timings on DIOR/DIOW) The figures outside the brackets are the documented timings on the host bus, but these are not what the drive sees. The timings which the drive sees are those in brackets. The timings the drive sees clearly are not based upon a 16MHz clock period. Therefore, I'd prefer to get the nanoseconds from the calculation and work from that. > > + > > + /* > > + * Now, properly adjust the timings. If we have a 62.5ns clock > > + * period and we ask for MWDMA2, it calculates the following > > + * timings: active 125ns, recovery 62.5ns, cycle 125ns. > > + * Quite obviously bogus. > > NAK. > > At this point you need to work out why you are getting bogus results and > fix it or demonstrate a bug in the core code and fix that. Obviously I can demonstrate a bug. 8) Lets say that we want to do MW DMA mode 2. This has the minimum timing of 70ns active, 25ns recovery, 120ns cycle time. When you quantise those figures using a clock period of 62.5ns (16MHz) you end up with: 2 clocks active (2*62.5 > 70), 1 clock recovery (1*62.5 > 25) and 2 clocks cycle (2*62.5 > 120). Last time I checked, active + recovery must always be equal to the cycle time, and unless my math is failing me, 2 + 1 does not equal 2. It's quite obvious that returning the active time _equal_ to the cycle time is even more utterly bogus - that means you're asking for the signal to remain active for the entire cycle without any recovery. So, you probably need to incorporate that logic from pata_icside into the libata core. -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 8:18 ` Russell King @ 2007-04-09 8:24 ` Roland Dreier 2007-04-09 8:44 ` Russell King 2007-04-09 10:25 ` Alan Cox 1 sibling, 1 reply; 19+ messages in thread From: Roland Dreier @ 2007-04-09 8:24 UTC (permalink / raw) To: Alan Cox; +Cc: linux-kernel, Andrew Morton, Jeff Garzik > Lets say that we want to do MW DMA mode 2. This has the minimum timing > of 70ns active, 25ns recovery, 120ns cycle time. > > When you quantise those figures using a clock period of 62.5ns (16MHz) > you end up with: 2 clocks active (2*62.5 > 70), 1 clock recovery > (1*62.5 > 25) and 2 clocks cycle (2*62.5 > 120). > > Last time I checked, active + recovery must always be equal to the cycle > time, and unless my math is failing me, 2 + 1 does not equal 2. Do you mean active + recovery must be less than or equal to the cycle time? Because 70ns + 25ns does not equal 120ns either... - R. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 8:24 ` Roland Dreier @ 2007-04-09 8:44 ` Russell King 0 siblings, 0 replies; 19+ messages in thread From: Russell King @ 2007-04-09 8:44 UTC (permalink / raw) To: Roland Dreier; +Cc: Alan Cox, linux-kernel, Andrew Morton, Jeff Garzik On Mon, Apr 09, 2007 at 01:24:45AM -0700, Roland Dreier wrote: > > Lets say that we want to do MW DMA mode 2. This has the minimum timing > > of 70ns active, 25ns recovery, 120ns cycle time. > > > > When you quantise those figures using a clock period of 62.5ns (16MHz) > > you end up with: 2 clocks active (2*62.5 > 70), 1 clock recovery > > (1*62.5 > 25) and 2 clocks cycle (2*62.5 > 120). > > > > Last time I checked, active + recovery must always be equal to the cycle > > time, and unless my math is failing me, 2 + 1 does not equal 2. > > Do you mean active + recovery must be less than or equal to the cycle > time? Because 70ns + 25ns does not equal 120ns either... Now that I've had some breakfast, yes. In any case, active + recovery must never be greater than the cycle time. -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 8:18 ` Russell King 2007-04-09 8:24 ` Roland Dreier @ 2007-04-09 10:25 ` Alan Cox 2007-04-09 11:33 ` Russell King 1 sibling, 1 reply; 19+ messages in thread From: Alan Cox @ 2007-04-09 10:25 UTC (permalink / raw) To: Russell King; +Cc: linux-kernel, Andrew Morton, Jeff Garzik > The timings the drive sees clearly are not based upon a 16MHz clock > period. Therefore, I'd prefer to get the nanoseconds from the > calculation and work from that. Makes sense. > Obviously I can demonstrate a bug. 8) > > Lets say that we want to do MW DMA mode 2. This has the minimum timing > of 70ns active, 25ns recovery, 120ns cycle time. Well it depends on the drive id data but assuming the defaults yes > When you quantise those figures using a clock period of 62.5ns (16MHz) > you end up with: 2 clocks active (2*62.5 > 70), 1 clock recovery > (1*62.5 > 25) and 2 clocks cycle (2*62.5 > 120). > > Last time I checked, active + recovery must always be equal to the cycle > time, and unless my math is failing me, 2 + 1 does not equal 2. The libata code does the following: if (t->active + t->recover < t->cycle) { t->active += (t->cycle - (t->active + t->recover)) / 2; t->recover = t->cycle - t->active; } which probably means for 16MHz you don't have enough resolution to be sure you'll error in this direction in all cases. If so you just need to try adding if (t->active + t->recover > t->cycle) t->cycle = t->active + t->recover to stretch the cycle time to fit the resolution as well. And we should get this tested/fixed by someone seeing the problem, before and instead of putting hacks/notes in drivers that may then get lost Alan ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-09 10:25 ` Alan Cox @ 2007-04-09 11:33 ` Russell King 0 siblings, 0 replies; 19+ messages in thread From: Russell King @ 2007-04-09 11:33 UTC (permalink / raw) To: Alan Cox; +Cc: linux-kernel, Andrew Morton, Jeff Garzik On Mon, Apr 09, 2007 at 11:25:06AM +0100, Alan Cox wrote: > > When you quantise those figures using a clock period of 62.5ns (16MHz) > > you end up with: 2 clocks active (2*62.5 > 70), 1 clock recovery > > (1*62.5 > 25) and 2 clocks cycle (2*62.5 > 120). > > > > Last time I checked, active + recovery must always be equal to the cycle > > time, and unless my math is failing me, 2 + 1 does not equal 2. > > The libata code does the following: > > if (t->active + t->recover < t->cycle) { > t->active += (t->cycle - (t->active + t->recover)) / 2; > t->recover = t->cycle - t->active; > } > > which probably means for 16MHz you don't have enough resolution to be sure > you'll error in this direction in all cases. If so you just need to try > adding > > if (t->active + t->recover > t->cycle) > t->cycle = t->active + t->recover > > to stretch the cycle time to fit the resolution as well. > > And we should get this tested/fixed by someone seeing the problem, before > and instead of putting hacks/notes in drivers that may then get lost I agree; this is why I sent the patch out as an RFC before wanting it merged. My feeling at the time when I wrote this is it's something that the libata timing calculation code should already be catering for. I should've explicitly mentioned that in the comments, but forgot. -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC] pata_icside driver 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King 2007-04-08 18:59 ` Alan Cox 2007-04-08 20:09 ` Alan Cox @ 2007-04-21 15:09 ` Russell King 2 siblings, 0 replies; 19+ messages in thread From: Russell King @ 2007-04-21 15:09 UTC (permalink / raw) To: linux-kernel, Andrew Morton, Jeff Garzik, linux-ide On Sun, Apr 08, 2007 at 11:18:26AM +0100, Russell King wrote: > Below is an initial attempt at converting the ICS IDE driver to fit > into the PATA infrastructure. > > There's a number of FIXMEs in there: due to the hardware missing > resistors on the interrupt signals from the drives, a port > without any drives attached results in spurious interrupts being > generated. > > To prevent this, we need to disable the interrupts from the port > on the card if no drives are found, but unfortunately ATA doesn't > call the "port_disable" method in this circumstance. Here's an updated version. I've removed the correction of the cycle time - since we're checking whether all of active, recovery and cycle periods fit the hardware, the correction becomes unnecessary. I still suggest that the PATA core folk consider fixing their timing calculation function in that respect though. This driver continues to have the so far ignored issue concerning port_disable. It would be good to have some feedback on this instead of this driver continuing to be crippled by the libata core code. This really needs resolving before this driver can be merged, though I'm not sure how. diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7bdbe5a..9cd8a61 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -552,6 +552,14 @@ config PATA_PLATFORM If unsure, say N. +config PATA_ICSIDE + tristate "Acorn ICS PATA support" + depends on ARM && ARCH_ACORN + help + On Acorn systems, say Y here if you wish to use the ICS PATA + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. + config PATA_IXP4XX_CF tristate "IXP4XX Compact Flash support" depends on ARCH_IXP4XX diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 13d7397..cc8798b 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o +obj-$(CONFIG_PATA_ICSIDE) += pata_icside.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_icside.c b/drivers/ata/pata_icside.c new file mode 100644 index 0000000..75b22da --- /dev/null +++ b/drivers/ata/pata_icside.c @@ -0,0 +1,686 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <scsi/scsi_host.h> +#include <linux/ata.h> +#include <linux/libata.h> + +#include <asm/dma.h> +#include <asm/ecard.h> + +#define DRV_NAME "pata_icside" + +#define ICS_IDENT_OFFSET 0x2280 + +#define ICS_ARCIN_V5_INTRSTAT 0x0000 +#define ICS_ARCIN_V5_INTROFFSET 0x0004 + +#define ICS_ARCIN_V6_INTROFFSET_1 0x2200 +#define ICS_ARCIN_V6_INTRSTAT_1 0x2290 +#define ICS_ARCIN_V6_INTROFFSET_2 0x3200 +#define ICS_ARCIN_V6_INTRSTAT_2 0x3290 + +struct portinfo { + unsigned int dataoffset; + unsigned int ctrloffset; + unsigned int stepping; +}; + +static const struct portinfo pata_icside_portinfo_v5 = { + .dataoffset = 0x2800, + .ctrloffset = 0x2b80, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_1 = { + .dataoffset = 0x2000, + .ctrloffset = 0x2380, + .stepping = 6, +}; + +static const struct portinfo pata_icside_portinfo_v6_2 = { + .dataoffset = 0x3000, + .ctrloffset = 0x3380, + .stepping = 6, +}; + +#define PATA_ICSIDE_MAX_SG 128 + +struct pata_icside_state { + void __iomem *irq_port; + void __iomem *ioc_base; + unsigned int type; + unsigned int dma; + struct { + u8 port_sel; + u8 disabled; + unsigned int speed[ATA_MAX_DEVICES]; + } port[2]; + struct scatterlist sg[PATA_ICSIDE_MAX_SG]; +}; + +#define ICS_TYPE_A3IN 0 +#define ICS_TYPE_A3USER 1 +#define ICS_TYPE_V6 3 +#define ICS_TYPE_V5 15 +#define ICS_TYPE_NOTYPE ((unsigned int)-1) + +/* ---------------- Version 5 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET); +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v5 = { + .irqenable = pata_icside_irqenable_arcin_v5, + .irqdisable = pata_icside_irqdisable_arcin_v5, +}; + + +/* ---------------- Version 6 PCB Support Functions --------------------- */ +/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + void __iomem *base = state->irq_port; + + if (!state->port[0].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); + if (!state->port[1].disabled) + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + struct pata_icside_state *state = ec->irq_data; + + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: pata_icside_irqprobe(struct expansion_card *ec) + * Purpose : detect an active interrupt from card + */ +static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec) +{ + struct pata_icside_state *state = ec->irq_data; + + return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || + readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; +} + +static const expansioncard_ops_t pata_icside_ops_arcin_v6 = { + .irqenable = pata_icside_irqenable_arcin_v6, + .irqdisable = pata_icside_irqdisable_arcin_v6, + .irqpending = pata_icside_irqpending_arcin_v6, +}; + + +/* + * SG-DMA support. + * + * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers. + * There is only one DMA controller per card, which means that only + * one drive can be accessed at one time. NOTE! We do not enforce that + * here, but we rely on the main IDE driver spotting that both + * interfaces use the same IRQ, which should guarantee this. + */ + +/* + * Configure the IOMD to give the appropriate timings for the transfer + * mode being requested. We take the advice of the ATA standards, and + * calculate the cycle time based on the transfer mode, and the EIDE + * MW DMA specs that the drive provides in the IDENTIFY command. + * + * We have the following IOMD DMA modes to choose from: + * + * Type Active Recovery Cycle + * A 250 (250) 312 (550) 562 (800) + * B 187 (200) 250 (550) 437 (750) + * C 125 (125) 125 (375) 250 (500) + * D 62 (50) 125 (375) 187 (425) + * + * (figures in brackets are actual measured timings on DIOR/DIOW) + * + * However, we also need to take care of the read/write active and + * recovery timings: + * + * Read Write + * Mode Active -- Recovery -- Cycle IOMD type + * MW0 215 50 215 480 A + * MW1 80 50 50 150 C + * MW2 70 25 25 120 C + */ +static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pata_icside_state *state = ap->host->private_data; + struct ata_timing t; + unsigned int cycle; + char iomd_type; + + /* + * DMA is based on a 16MHz clock + */ + if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1)) + return; + + /* + * Choose the IOMD cycle timing which ensure that the interface + * satisfies the measured active, recovery and cycle times. + */ + if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425) + iomd_type = 'D', cycle = 187; + else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500) + iomd_type = 'C', cycle = 250; + else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750) + iomd_type = 'B', cycle = 437; + else + iomd_type = 'A', cycle = 562; + + ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n", + t.active, t.recover, t.cycle, iomd_type); + + state->port[ap->port_no].speed[adev->devno] = cycle; +} + +static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + struct scatterlist *sg, *rsg = state->sg; + unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE; + + /* + * We are simplex; BUG if we try to fiddle with DMA + * while it's active. + */ + BUG_ON(dma_channel_active(state->dma)); + + /* + * Copy ATAs scattered sg list into a contiguous array of sg + */ + ata_for_each_sg(sg, qc) { + memcpy(rsg, sg, sizeof(*sg)); + rsg++; + } + + /* + * Route the DMA signals to the correct interface + */ + writeb(state->port[ap->port_no].port_sel, state->ioc_base); + + set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]); + set_dma_sg(state->dma, state->sg, rsg - state->sg); + set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ); + + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +static void pata_icside_bmdma_start(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + BUG_ON(dma_channel_active(state->dma)); + enable_dma(state->dma); +} + +static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct pata_icside_state *state = ap->host->private_data; + + disable_dma(state->dma); + + /* see ata_bmdma_stop */ + ata_altstatus(ap); +} + +static u8 pata_icside_bmdma_status(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + void __iomem *irq_port; + + irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 : + ICS_ARCIN_V6_INTRSTAT_1); + + return readb(irq_port) & 1 ? ATA_DMA_INTR : 0; +} + +static int icside_dma_init(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + int i; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + state->port[0].speed[i] = 480; + state->port[1].speed[i] = 480; + } + + if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { + state->dma = ec->dma; + ae->mwdma_mask = 0x07; /* MW0..2 */ + } + + return 0; +} + + +static int pata_icside_port_start(struct ata_port *ap) +{ + /* No PRD to alloc */ + return ata_pad_alloc(ap, ap->dev); +} + +static struct scsi_host_template pata_icside_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 = PATA_ICSIDE_MAX_SG, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ~0, /* no dma boundaries */ + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +/* wish this was exported from libata-core */ +static void ata_dummy_noret(struct ata_port *port) +{ +} + +/* + * We need to shut down unused ports to prevent spurious interrupts. + * FIXME: the libata core doesn't call this function for PATA interfaces. + */ +static void pata_icside_port_disable(struct ata_port *ap) +{ + struct pata_icside_state *state = ap->host->private_data; + + ata_port_printk(ap, KERN_ERR, "disabling icside port\n"); + + ata_port_disable(ap); + + state->port[ap->port_no].disabled = 1; + + if (state->type == ICS_TYPE_V6) { + /* + * Disable interrupts from this port, otherwise we + * receive spurious interrupts from the floating + * interrupt line. + */ + void __iomem *irq_port = state->irq_port + + (ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1); + readb(irq_port); + } +} + +static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq) +{ + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + u8 status; + + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + printk(KERN_ERR "abnormal status 0x%X\n", status); + + if (ata_msg_intr(ap)) + printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n", + __FUNCTION__, status); + + return status; +} + +static struct ata_port_operations pata_icside_port_ops = { + .port_disable = pata_icside_port_disable, + + .set_dmamode = pata_icside_set_dmamode, + + .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, + + .bmdma_setup = pata_icside_bmdma_setup, + .bmdma_start = pata_icside_bmdma_start, + + .data_xfer = ata_data_xfer_noirq, + + /* no need to build any PRD tables for DMA */ + .qc_prep = ata_noop_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = pata_icside_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = ata_dummy_noret, + .irq_on = ata_irq_on, + .irq_ack = pata_icside_irq_ack, + + .port_start = pata_icside_port_start, + + .bmdma_stop = pata_icside_bmdma_stop, + .bmdma_status = pata_icside_bmdma_status, +}; + +static void +pata_icside_add_port(struct ata_probe_ent *ae, void __iomem *base, + const struct portinfo *info) +{ + struct ata_ioports *ioaddr = &ae->port[ae->n_ports++]; + void __iomem *cmd = base + info->dataoffset; + + ioaddr->cmd_addr = cmd; + ioaddr->data_addr = cmd + (ATA_REG_DATA << info->stepping); + ioaddr->error_addr = cmd + (ATA_REG_ERR << info->stepping); + ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << info->stepping); + ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << info->stepping); + ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << info->stepping); + ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << info->stepping); + ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << info->stepping); + ioaddr->device_addr = cmd + (ATA_REG_DEVICE << info->stepping); + ioaddr->status_addr = cmd + (ATA_REG_STATUS << info->stepping); + ioaddr->command_addr = cmd + (ATA_REG_CMD << info->stepping); + + ioaddr->ctl_addr = base + info->ctrloffset; + ioaddr->altstatus_addr = ioaddr->ctl_addr; +} + +static int __init +pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *base; + + base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), + ecard_resource_len(ec, ECARD_RES_MEMC)); + if (!base) + return -ENOMEM; + + state->irq_port = base; + + ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; + ec->irqmask = 1; + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v5; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + pata_icside_add_port(ae, base, &pata_icside_portinfo_v5); + + return 0; +} + +static int __init +pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec) +{ + struct pata_icside_state *state = ae->private_data; + void __iomem *ioc_base, *easi_base; + unsigned int sel = 0; + int ret; + + ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (!ioc_base) { + ret = -ENOMEM; + goto out; + } + + easi_base = ioc_base; + + if (ecard_resource_flags(ec, ECARD_RES_EASI)) { + easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI), + ecard_resource_len(ec, ECARD_RES_EASI)); + if (!easi_base) { + ret = -ENOMEM; + goto unmap_slot; + } + + /* + * Enable access to the EASI region. + */ + sel = 1 << 5; + } + + writeb(sel, ioc_base); + + ec->irq_data = state; + ec->ops = &pata_icside_ops_arcin_v6; + + state->irq_port = easi_base; + state->ioc_base = ioc_base; + state->port[0].port_sel = sel; + state->port[1].port_sel = sel | 1; + + /* + * Be on the safe side - disable interrupts + */ + ec->ops->irqdisable(ec, ec->irq); + + /* + * Find and register the interfaces. + */ + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_1); + pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_2); + + /* + * FIXME: work around libata's aversion to calling port_disable. + * This permanently disables interrupts on port 0 - bad luck if + * you have a drive on that port. + */ + state->port[0].disabled = 1; + + return icside_dma_init(ae, ec); + + unmap_slot: + iounmap(ioc_base); + out: + return ret; +} + +static int __devinit +pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + struct pata_icside_state *state; + struct ata_probe_ent ae; + void __iomem *idmem; + int ret; + + ret = ecard_request_resources(ec); + if (ret) + goto out; + + state = kzalloc(sizeof(struct pata_icside_state), GFP_KERNEL); + if (!state) { + ret = -ENOMEM; + goto release; + } + + state->type = ICS_TYPE_NOTYPE; + state->dma = NO_DMA; + + idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), + ecard_resource_len(ec, ECARD_RES_IOCFAST)); + if (idmem) { + unsigned int type; + + type = readb(idmem + ICS_IDENT_OFFSET) & 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1; + type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2; + type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3; + iounmap(idmem); + + state->type = type; + } + + memset(&ae, 0, sizeof(ae)); + INIT_LIST_HEAD(&ae.node); + ae.dev = &ec->dev; + ae.port_ops = &pata_icside_port_ops; + ae.sht = &pata_icside_sht; + ae.pio_mask = 0x1f; + ae.irq = ec->irq; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + ae._host_flags = ATA_HOST_SIMPLEX; + ae.private_data = state; + + switch (state->type) { + case ICS_TYPE_A3IN: + dev_warn(&ec->dev, "A3IN unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_A3USER: + dev_warn(&ec->dev, "A3USER unsupported\n"); + ret = -ENODEV; + break; + + case ICS_TYPE_V5: + ret = pata_icside_register_v5(&ae, ec); + break; + + case ICS_TYPE_V6: + ret = pata_icside_register_v6(&ae, ec); + break; + + default: + dev_warn(&ec->dev, "unknown interface type\n"); + ret = -ENODEV; + break; + } + + if (ret == 0) + ret = ata_device_add(&ae) == 0 ? -ENODEV : 0; + + if (ret == 0) + goto out; + + kfree(state); + release: + ecard_release_resources(ec); + out: + return ret; +} + +static void pata_icside_shutdown(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + unsigned long flags; + + /* + * Disable interrupts from this card. We need to do + * this before disabling EASI since we may be accessing + * this register via that region. + */ + local_irq_save(flags); + if (ec->ops) + ec->ops->irqdisable(ec, ec->irq); + local_irq_restore(flags); + + /* + * Reset the ROM pointer so that we can read the ROM + * after a soft reboot. This also disables access to + * the IDE taskfile via the EASI region. + */ + if (host) { + struct pata_icside_state *state = host->private_data; + if (state->ioc_base) + writeb(0, state->ioc_base); + } +} + +static void __devexit pata_icside_remove(struct expansion_card *ec) +{ + struct ata_host *host = ecard_get_drvdata(ec); + struct pata_icside_state *state = host->private_data; + + ata_host_detach(host); + + pata_icside_shutdown(ec); + + /* + * don't NULL out the drvdata - devres/libata wants it + * to free the ata_host structure. + */ + ec->ops = NULL; + ec->irq_data = NULL; + + if (state->dma != NO_DMA) + free_dma(state->dma); + if (state->ioc_base) + iounmap(state->ioc_base); + if (state->ioc_base != state->irq_port) + iounmap(state->irq_port); + + kfree(state); + ecard_release_resources(ec); +} + +static const struct ecard_id pata_icside_ids[] = { + { MANU_ICS, PROD_ICS_IDE }, + { MANU_ICS2, PROD_ICS2_IDE }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver pata_icside_driver = { + .probe = pata_icside_probe, + .remove = __devexit_p(pata_icside_remove), + .shutdown = pata_icside_shutdown, + .id_table = pata_icside_ids, + .drv = { + .name = DRV_NAME, + }, +}; + +static int __init pata_icside_init(void) +{ + return ecard_register_driver(&pata_icside_driver); +} + +static void __exit pata_icside_exit(void) +{ + ecard_remove_driver(&pata_icside_driver); +} + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ICS PATA driver"); + +module_init(pata_icside_init); +module_exit(pata_icside_exit); -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC] pata_platform for ARM RiscPC 2007-03-30 11:08 ` [RFC] pata_platform for ARM RiscPC Russell King 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King @ 2007-04-09 11:32 ` Jeff Garzik 1 sibling, 0 replies; 19+ messages in thread From: Jeff Garzik @ 2007-04-09 11:32 UTC (permalink / raw) To: linux-kernel, Andrew Morton Russell King wrote: > Add pata_platform device for RiscPC, thereby converting the primary > IDE channel on the machine to PATA. > > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> ACK BTW, please CC linux-ide on anything related to old-IDE or libata. Thanks. > Since this is dependent on the previous patch (to avoid build errors) > this needs to wait until the devm_ioport patch is merged. I'll > therefore push this through the ARM tree at the appropriate time. Sounds good. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT 2007-03-30 11:00 [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Russell King 2007-03-30 11:08 ` [RFC] pata_platform for ARM RiscPC Russell King @ 2007-03-30 11:08 ` Christoph Hellwig 1 sibling, 0 replies; 19+ messages in thread From: Christoph Hellwig @ 2007-03-30 11:08 UTC (permalink / raw) To: linux-kernel, Andrew Morton, Al Viro On Fri, Mar 30, 2007 at 12:00:22PM +0100, Russell King wrote: > Provide an dummy implementation of devm_ioport_map() and > devm_ioport_unmap() to allow drivers (eg, pata_platform) to build for Btw, I there a chance we can collect all the devm_* crap into a single implementation and header file instead of spreading it all over the tree? ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2007-04-21 15:09 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-03-30 11:00 [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Russell King 2007-03-30 11:08 ` [RFC] pata_platform for ARM RiscPC Russell King 2007-04-08 10:18 ` [RFC] pata_icside driver Russell King 2007-04-08 18:59 ` Alan Cox 2007-04-09 1:03 ` Jeff Garzik 2007-04-09 9:56 ` Alan Cox 2007-04-09 10:56 ` Jeff Garzik 2007-04-09 11:13 ` Jeff Garzik 2007-04-09 11:36 ` Russell King 2007-04-09 12:02 ` Jeff Garzik 2007-04-08 20:09 ` Alan Cox 2007-04-09 8:18 ` Russell King 2007-04-09 8:24 ` Roland Dreier 2007-04-09 8:44 ` Russell King 2007-04-09 10:25 ` Alan Cox 2007-04-09 11:33 ` Russell King 2007-04-21 15:09 ` Russell King 2007-04-09 11:32 ` [RFC] pata_platform for ARM RiscPC Jeff Garzik 2007-03-30 11:08 ` [PATCH] Provide dummy devm_ioport_* if !HAS_IOPORT Christoph Hellwig
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.