From: "Albert Lee" <albertcc@tw.ibm.com>
To: Jeff Garzik <jgarzik@pobox.com>,
Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Cc: IDE Linux <linux-ide@vger.kernel.org>
Subject: Re: [PATCH/RFC] Port of pdc202xx_new driver to libata
Date: Mon, 18 Oct 2004 18:30:43 +0800 [thread overview]
Message-ID: <001901c4b4fd$88204bc0$294bbf09@tw.ibm.com> (raw)
In-Reply-To: 416D88FA.1050200@pobox.com
[-- Attachment #1: Type: text/plain, Size: 5822 bytes --]
Hi, Jeff and Bart:
Thanks for your review and sorry for the late reply.
The updated patch is attached for your review/comment.
(The patch is against libata-dev-2.6)
1.
> why not jus pata_pdc_new? or pata_pdc_27x?
changed to "pata_pdc2027x".
2.
> This table is redundant:
>* official names (more detailed) can be get from lspci
>* PDC_UDMA_[100,133] implies PDC_[100,133]_MHZ
>* max UDMA rate is available from ata_port_info etc.
Fixed.
3.
>> + /* For UDMA33, no 80c support is required */
>> + if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
>> + goto cbl40;
>
>this can't happen
Removed.
4.
> pds_set_pio() should be called only once
> pdc_set_ultra() should be called only once
Fixed.
5.
>> + /* Enable the ROM */
>> + if (pdev->resource[PCI_ROM_RESOURCE].start) {
>> + pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
>> + pdev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
>> + printk(KERN_INFO DRV_NAME ": ROM enabled at 0x%08lx\n",
>> + pdev->resource[PCI_ROM_RESOURCE].start);
>> + }
> is this really needed?
Removed.
6.
>> + * FIXME: If this driver happens to only be useful on Apple's K2, then
>> + * we should check that here as it has a normal Serverworks ID
>> + */
>
>cut'n'paste mistake
Fixed.
7.
> pdc_hardware_init() seems to be the only reason
> why generic ata_pci_init_one() can't be used here,
> what about adding sth. like ->init_device() to
> struct ata_port_info?
Could this be fixed later?
(I am afraid to touch the core. Need more time to study.)
Thanks,
Albert Lee
----- Original Message -----
From: "Jeff Garzik" <jgarzik@pobox.com>
To: "Bartlomiej Zolnierkiewicz" <bzolnier@gmail.com>; "Albert Lee"
<albertcc@tw.ibm.com>
Cc: "IDE Linux" <linux-ide@vger.kernel.org>
Sent: Thursday, October 14, 2004 3:58 AM
Subject: Re: [PATCH/RFC] Port of pdc202xx_new driver to libata
>
> I'll use this message to respond to both Albert and you (Bart).
>
> Bartlomiej Zolnierkiewicz wrote:
> > On Wed, 13 Oct 2004 18:06:19 +0800, Albert Lee <albertcc@tw.ibm.com>
wrote:
> >
> >>Hi, Jeff and Bart:
> >
> >
> > Hi!
> >
> >
> >> I am trying to port the Promise pdc202xx_new driver to libata and
adding
> >>the
> >>PLL tuning code to it. (The motivation is hotplug of the Promise host
> >>adapter.)
> >
> >
> > I have libata version of pdc202xx_new for a long time now
> > but this one looks superior as it handles PLL. :-)
> >
> >
> >>The ported driver has been tested with pdc20269 and pdc20275 on i386 and
> >>x86_64 boxes, with 33 MHz PCI bus and 66 MHz PCI bus respectively.
> >>It seems to be working fine with harddisk drives.
>
> I got a report that sata_promise has problems in some >=66Mhz
> configurations, but works fine with 33Mhz configuration. I bet I could
> learn a few things from this driver too, as the concepts probably apply
> to newer hardware.
>
>
> >>(However, CD-ROM drives not working yet, even when
> >>ATA_ENABLE_PATA and ATA_ENABLE_ATAPI are enabled.)
> >
> >
> > Somehow this doesn't surprise me...
>
> hehe :)
>
>
> >>My question is, in the current kernel, the IDE subsystem drives PATA
chips
> >>and libata drives SATA chips. Will PATA driver like this be accepted
into
> >>libata?
> >
> >
> > My opinion is: yes but not now, final answer is of course left to Jeff.
>
> With the progress currently being made, I think my preference would be
> to start collecting PATA drivers such this in my libata-dev queue.
>
> I would not send these PATA drivers upstream until the PATA to-do items
> are complete (see other email), but it would be nice to have a central
> location (both BK and patch on kernel.org) for developers and users to
> mess with PATA support.
>
> So, send PATA drivers to me and I will merge... but please understand
> that I will not send upstream for quite some time.
>
>
>
> >>Albert Lee
> >>(The patch is against 2.6.8.1.)
> >
> >
> > It seems your mail client screwed it.
> >
> > I will try to comment on the patch anyway...
>
> I agree with Bart's comments on the patch. It was also mangled here.
>
> Albert, if you would resend a patch with Bart's fixes, I'll merge into
> libata-dev.
>
> My own comments:
>
> >> obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
> >>> +obj-$(CONFIG_SCSI_PATA_PDC_NEW) += libata.o pata_pdc202xx_new.o
> >
> >
> > why not jus pata_pdc_new? or pata_pdc_27x?
>
> I would prefer to eliminate the "_new" suffix. Other than that I don't
> really care. If I had written the driver, I would have named it
> pata_pdc202xx I suppose.
>
>
> > +} pdc_pata_controller_tbl [] = {
> >> + { "Ultra100 TX2", PDC_UDMA_100, PDC_100_MHZ }, /* pdc20268 */
> >> + { "Ultra133 TX2", PDC_UDMA_133, PDC_133_MHZ }, /* pdc20269 */
> >> + { "FastTrak LP/TX2/TX4", PDC_UDMA_100, PDC_100_MHZ }, /* pdc20270 */
> >> + { "FastTrak TX2000", PDC_UDMA_133, PDC_133_MHZ }, /* pdc20271 */
> >> + { "MBUltra133", PDC_UDMA_133, PDC_133_MHZ }, /* pdc20275 */
> >> + { "MBFastTrak 133 Lite", PDC_UDMA_133, PDC_133_MHZ }, /* pdc20276 */
> >> + { "SBFastTrak 133 Lite", PDC_UDMA_133, PDC_133_MHZ }, /* pdc20277 */
> >> +};
>
> In general I prefer to eliminate _all_ "marketing strings" from all
> drivers. Model names appear on the market far faster than any
> maintainer could hope to keep up. (granted, this is old hardware and
> not changing, in this case) So as a general rule, it is preferred to
> only use strings when absolutely necessary, eliminating them completely
> if at all possible.
>
> > what exacty (besides PLL support) are the advantages
> > of libata driver?
>
> IDE controller hotplug is a lot easier, and proper locking is already
> there :)
>
> Jeff
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-ide" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
[-- Attachment #2: pdc2027x.diff --]
[-- Type: application/octet-stream, Size: 25770 bytes --]
diff -Nru libata-pdc-2.6-ori/drivers/scsi/Kconfig libata-pdc-2.6/drivers/scsi/Kconfig
--- libata-pdc-2.6-ori/drivers/scsi/Kconfig 2004-10-18 17:25:52.000000000 +0800
+++ libata-pdc-2.6/drivers/scsi/Kconfig 2004-10-18 17:27:36.759587840 +0800
@@ -441,6 +441,14 @@
If unsure, say N.
+config SCSI_PATA_PDC2027X
+ tristate "Promise PATA 2027x support"
+ depends on SCSI_SATA && PCI
+ help
+ This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
+
+ If unsure, say N.
+
config SCSI_SATA_PROMISE
tristate "Promise SATA TX2/TX4 support"
depends on SCSI_SATA && PCI
diff -Nru libata-pdc-2.6-ori/drivers/scsi/Makefile libata-pdc-2.6/drivers/scsi/Makefile
--- libata-pdc-2.6-ori/drivers/scsi/Makefile 2004-10-18 17:25:52.000000000 +0800
+++ libata-pdc-2.6/drivers/scsi/Makefile 2004-10-18 17:27:36.796582216 +0800
@@ -124,6 +124,7 @@
obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o
obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
+obj-$(CONFIG_SCSI_PATA_PDC2027X)+= libata.o pata_pdc2027x.o
obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
diff -Nru libata-pdc-2.6-ori/drivers/scsi/pata_pdc2027x.c libata-pdc-2.6/drivers/scsi/pata_pdc2027x.c
--- libata-pdc-2.6-ori/drivers/scsi/pata_pdc2027x.c 1970-01-01 08:00:00.000000000 +0800
+++ libata-pdc-2.6/drivers/scsi/pata_pdc2027x.c 2004-10-18 17:27:37.993400272 +0800
@@ -0,0 +1,758 @@
+/*
+ * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Ported to libata by:
+ * Albert Lee <albertcc@tw.ibm.com> IBM Corporation
+ *
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ *
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ *
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "pata_pdc2027x"
+#define DRV_VERSION "0.52"
+#undef PDC_DEBUG
+#undef PDC_20276_QUIRK
+#undef PDC_20270_QUIRK
+
+#ifdef PDC_DEBUG
+#define PDPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define PDPRINTK(fmt, args...)
+#endif
+
+enum {
+ PDC_UDMA_100 = 0,
+ PDC_UDMA_133 = 1,
+
+ PDC_100_MHZ = 100000000,
+ PDC_133_MHZ = 133333333,
+};
+
+static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc2027x_remove_one(struct pci_dev *pdev);
+static void pdc2027x_phy_reset(struct ata_port *ap);
+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+
+/*
+ * ATA Timing Tables based on 133MHz controller clock.
+ * These tables are only used when the controller is in 133MHz clock.
+ * If the controller is in 100MHz clock, the ASIC hardware will
+ * set the timing registers automatically when "set feature" command
+ * issued to the device. However, if the controller clock is 133MHz,
+ * the following tables must be used.
+ */
+static struct pdc2027x_pio_timing {
+ u8 value0, value1, value2;
+} pdc2027x_pio_timing_tbl [] = {
+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */
+ { 0x23, 0x26, 0x64 }, /* PIO mode 2 */
+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
+};
+
+static struct pdc2027x_mdma_timing {
+ u8 value0, value1;
+} pdc2027x_mdma_timing_tbl [] = {
+ { 0xdf, 0x5f }, /* MDMA mode 0 */
+ { 0x6b, 0x27 }, /* MDMA mode 1 */
+ { 0x69, 0x25 }, /* MDMA mode 2 */
+};
+
+static struct pdc2027x_udma_timing {
+ u8 value0, value1, value2;
+} pdc2027x_udma_timing_tbl [] = {
+ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
+ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
+ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
+ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
+ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
+ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
+ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
+};
+
+static struct pci_device_id pdc2027x_pci_tbl[] = {
+#ifdef ATA_ENABLE_PATA
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+#endif
+ { } /* terminate list */
+};
+
+static struct pci_driver pdc2027x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc2027x_pci_tbl,
+ .probe = pdc2027x_init_one,
+ .remove = __devexit_p(pdc2027x_remove_one),
+};
+
+static Scsi_Host_Template pdc2027x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = ata_scsi_queuecmd,
+ .eh_strategy_handler = ata_scsi_error,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .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,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc2027x_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc2027x_set_piomode,
+ .set_dmamode = pdc2027x_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = pdc2027x_phy_reset,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .eng_timeout = ata_eng_timeout,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+};
+
+static struct ata_port_info pdc2027x_port_info[] = {
+ /* PDC_UDMA_100 */
+ {
+ .sht = &pdc2027x_sht,
+ .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_SRST,
+ .pio_mask = 0x03, /* pio3-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 */
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &pdc2027x_pata_ops,
+ },
+ /* PDC_UDMA_133 */
+ {
+ .sht = &pdc2027x_sht,
+ .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_SRST,
+ .pio_mask = 0x03, /* pio3-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &pdc2027x_pata_ops,
+ },
+};
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee");
+MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
+
+/**
+ * pdc_get_indexed_reg - Set pdc202xx extended register
+ * @ap: Port to which the extended register is set
+ * @index: index of the extended register
+ */
+static u8 pdc_get_indexed_reg(struct ata_port *ap, u8 index)
+{
+ u8 tmp8;
+
+ outb(index, ap->ioaddr.bmdma_addr + 1);
+ tmp8 = inb(ap->ioaddr.bmdma_addr + 3);
+
+ PDPRINTK("Get index reg%X[%X] \n", index, tmp8);
+ return tmp8;
+}
+/**
+ * pdc_set_indexed_reg - Read pdc202xx extended register
+ * @ap: Port to which the extended register is read
+ * @index: index of the extended register
+ */
+static void pdc_set_indexed_reg(struct ata_port *ap, u8 index, u8 value)
+{
+ outb(index, ap->ioaddr.bmdma_addr + 1);
+ outb(value, ap->ioaddr.bmdma_addr + 3);
+ PDPRINTK("Set index reg%X[%X] \n", index, value);
+}
+/**
+ * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from Promise extended register.
+ * This register is latched when the system is reset.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_cbl_detect(struct ata_port *ap)
+{
+ u8 cbl40c;
+
+ /* check cable detect results */
+ cbl40c = pdc_get_indexed_reg(ap, 0x0b) & 0x04;
+
+ if (cbl40c)
+ goto cbl40;
+
+ PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
+
+ ap->cbl = ATA_CBL_PATA80;
+ return;
+
+cbl40:
+ printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+/**
+ * pdc2027x_port_enabled - Check extended register at 0x04 to see whether the port is enabled.
+ * @ap: Port to check
+ */
+static inline int pdc2027x_port_enabled(struct ata_port *ap)
+{
+ return pdc_get_indexed_reg(ap, 0x04) & 0x02;
+}
+/**
+ * pdc2027x_phy_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * Probe PATA phy.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_phy_reset(struct ata_port *ap)
+{
+ /* Check whether port enabled */
+ if (!pdc2027x_port_enabled(ap)) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return;
+ }
+
+ pdc2027x_cbl_detect(ap);
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
+}
+/**
+ * pdc2027x_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port to configure
+ * @adev: um
+ * @pio: PIO mode, 0 - 4
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno;
+ u8 adj = (drive_dn%2) ? 0x08 : 0x00;
+ u8 tmp8;
+
+
+ PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode);
+
+ /* Sanity check */
+ if(pio > 4) {
+ printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio);
+ return;
+
+ }
+
+ /* Set the PIO timing registers using value table for 133MHz */
+ PDPRINTK("Set pio regs... \n");
+
+ pdc_set_indexed_reg(ap, 0x0c + adj, pdc2027x_pio_timing_tbl[pio].value0);
+ pdc_set_indexed_reg(ap, 0x0d + adj, pdc2027x_pio_timing_tbl[pio].value1);
+ pdc_set_indexed_reg(ap, 0x13 + adj, pdc2027x_pio_timing_tbl[pio].value2);
+
+ PDPRINTK("Set pio regs done\n");
+
+ /*
+ * Check whether the device supports turning off IORDY.
+ * For PIO3 and above, the device must support IORDY and set bit 10
+ */
+ if (adev->id[49] & 0x400) {
+ /* IORDY_EN & PREFETCH_EN */
+ /* Turn on Prefetch */
+ tmp8 = pdc_get_indexed_reg(ap, 0x13 + adj);
+ pdc_set_indexed_reg(ap, 0x13 + adj, tmp8 | 0x03);
+
+ PDPRINTK("Turn on prefetch\n");
+ }
+
+ printk(KERN_INFO DRV_NAME ": Set to pio mode[%u] \n", pio);
+}
+/**
+ * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
+ * @ap: Port to configure
+ * @adev: um
+ * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno;
+ u8 adj = (drive_dn%2) ? 0x08 : 0x00;
+ u8 tmp8;
+
+ if((dma_mode >= XFER_UDMA_0) &&
+ (dma_mode <= XFER_UDMA_6)) {
+ /* Set the UDMA timing registers with value table for 133MHz */
+ unsigned int udma_mode = dma_mode & 0x07;
+
+ if (dma_mode == XFER_UDMA_2) {
+ /*
+ * Turn off tHOLD.
+ * If tHOLD is '1', the hardware will add half clock for data hold time.
+ * This code segment seems to be no effect. tHOLD will be overwritten below.
+ */
+ tmp8 = pdc_get_indexed_reg(ap, 0x10 + adj);
+ pdc_set_indexed_reg(ap, 0x10 + adj, tmp8 & 0x7f);
+ }
+
+ PDPRINTK("Set udma regs... \n");
+ pdc_set_indexed_reg(ap, 0x10 + adj, pdc2027x_udma_timing_tbl[udma_mode].value0);
+ pdc_set_indexed_reg(ap, 0x11 + adj, pdc2027x_udma_timing_tbl[udma_mode].value1);
+ pdc_set_indexed_reg(ap, 0x12 + adj, pdc2027x_udma_timing_tbl[udma_mode].value2);
+ PDPRINTK("Set udma regs done\n");
+
+ printk(KERN_INFO DRV_NAME ": Set to udma mode[%u] \n", udma_mode);
+
+ } else if((dma_mode >= XFER_MW_DMA_0) &&
+ (dma_mode <= XFER_MW_DMA_2)) {
+ /* Set the MDMA timing registers with value table for 133MHz */
+ unsigned int mdma_mode = dma_mode & 0x07;
+
+ PDPRINTK("Set mdma regs... \n");
+ pdc_set_indexed_reg(ap, 0x0e + adj, pdc2027x_mdma_timing_tbl[mdma_mode].value0);
+ pdc_set_indexed_reg(ap, 0x0f + adj, pdc2027x_mdma_timing_tbl[mdma_mode].value1);
+ PDPRINTK("Set mdma regs done\n");
+
+ printk(KERN_INFO DRV_NAME ": Set to mdma mode[%u] \n", mdma_mode);
+ } else {
+ printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode);
+ }
+}
+/**
+ * adjust_pll - Adjust the PLL input clock in Hz.
+ *
+ * @pdc_controller: controller specific information
+ * @probe_ent: For the port address
+ * @pll_clock: The input of PLL in HZ
+ */
+static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
+{
+
+ u8 pll_ctl0, pll_ctl1;
+ long pll_clock_khz = pll_clock / 1000;
+ long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
+ long ratio = pout_required / pll_clock_khz;
+ int F, R;
+
+
+ /* Sanity check */
+ if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) {
+ printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz);
+ return;
+ }
+
+#ifdef PDC_DEBUG
+ PDPRINTK("pout_required is %ld\n", pout_required);
+
+ /* Show the current clock value of PLL control register
+ * (maybe already configured by the firmware)
+ */
+ outb(0x02, probe_ent->port[1].bmdma_addr + 0x01);
+ pll_ctl0 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+ outb(0x03, probe_ent->port[1].bmdma_addr + 0x01);
+ pll_ctl1 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+
+ PDPRINTK("pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ /*
+ * Calculate the ratio of F, R and OD
+ * POUT = (F + 2) / (( R + 2) * NO)
+ */
+ if (ratio < 8600L) { // 8.6x
+ /* Using NO = 0x01, R = 0x0D */
+ R = 0x0d;
+ } else if (ratio < 12900L) { // 12.9x
+ /* Using NO = 0x01, R = 0x08 */
+ R = 0x08;
+ } else if (ratio < 16100L) { // 16.1x
+ /* Using NO = 0x01, R = 0x06 */
+ R = 0x06;
+ } else if (ratio < 64000L) { // 64x
+ R = 0x00;
+ } else {
+ /* Invalid ratio */
+ printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio);
+ return;
+ }
+
+ F = (ratio * (R+2)) / 1000 - 2;
+
+ if (unlikely(F < 0 || F > 127)) {
+ /* Invalid F */
+ printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F);
+ return;
+ }
+
+ PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio);
+
+ pll_ctl0 = (u8) F;
+ pll_ctl1 = (u8) R;
+
+ PDPRINTK("Writing pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1);
+
+ outb(0x02, probe_ent->port[1].bmdma_addr + 0x01);
+ outb(pll_ctl0, probe_ent->port[1].bmdma_addr + 0x03);
+ outb(0x03, probe_ent->port[1].bmdma_addr + 0x01);
+ outb(pll_ctl1, probe_ent->port[1].bmdma_addr + 0x03);
+
+ /* Wait the PLL circuit to be stable */
+ mdelay(30);
+
+#ifdef PDC_DEBUG
+ /*
+ * Show the current clock value of PLL control register
+ * (maybe configured by the firmware)
+ */
+ outb(0x02, probe_ent->port[1].bmdma_addr + 0x01);
+ pll_ctl0 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+ outb(0x03, probe_ent->port[1].bmdma_addr + 0x01);
+ pll_ctl1 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+
+ PDPRINTK("pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ return;
+}
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @probe_ent: for the port address
+ * Ex. 16949000 on 33MHz PCI bus for pdc20275.
+ * Half of the PCI clock.
+ */
+static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
+{
+ u8 scr1;
+ unsigned long ctr0;
+ unsigned long ctr1;
+ unsigned long ctr2 = 0;
+ unsigned long ctr3 = 0;
+
+ unsigned long start_count, end_count;
+ long pll_clock;
+
+ /* Read current counter value */
+ outb(0x20, probe_ent->port[0].bmdma_addr + 0x01);
+ ctr0 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+ outb(0x21, probe_ent->port[0].bmdma_addr + 0x01);
+ ctr1 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+
+ outb(0x20, probe_ent->port[1].bmdma_addr + 0x01);
+ ctr2 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+ outb(0x21, probe_ent->port[1].bmdma_addr + 0x01);
+ ctr3 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+
+ start_count = (ctr3 << 23 ) | (ctr2 << 15) | (ctr1 << 8) | ctr0;
+
+ PDPRINTK("ctr0[%lX] ctr1[%lX] ctr2 [%lX] ctr3 [%lX]\n", ctr0, ctr1, ctr2, ctr3);
+
+ /* Start the test mode */
+ outb(0x01, probe_ent->port[0].bmdma_addr + 0x01);
+ scr1 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+ PDPRINTK("scr1[%X]\n", scr1);
+ outb(scr1 | 0x40, probe_ent->port[0].bmdma_addr + 0x03);
+
+ /* Let the counter run for 1000 us. */
+ udelay(1000);
+
+ /* Read the counter values again */
+ outb(0x20, probe_ent->port[0].bmdma_addr + 0x01);
+ ctr0 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+ outb(0x21, probe_ent->port[0].bmdma_addr + 0x01);
+ ctr1 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+
+ outb(0x20, probe_ent->port[1].bmdma_addr + 0x01);
+ ctr2 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+ outb(0x21, probe_ent->port[1].bmdma_addr + 0x01);
+ ctr3 = inb(probe_ent->port[1].bmdma_addr + 0x03);
+
+ end_count = (ctr3 << 23 ) | (ctr2 << 15) | (ctr1 << 8) | ctr0;
+
+ PDPRINTK("ctr0[%lX] ctr1[%lX] ctr2 [%lX] ctr3 [%lX]\n", ctr0, ctr1, ctr2, ctr3);
+
+ /* Stop the test mode */
+ outb(0x01, probe_ent->port[0].bmdma_addr + 0x01);
+ scr1 = inb(probe_ent->port[0].bmdma_addr + 0x03);
+ PDPRINTK("scr1[%X]\n", scr1);
+ outb(scr1 & 0xBF, probe_ent->port[0].bmdma_addr + 0x03);
+
+ /* calculate the input clock in Hz */
+ pll_clock = (long) ((start_count - end_count) * 1000);
+
+ PDPRINTK("start[%lu] end[%lu] \n", start_count, end_count);
+ PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock);
+
+ return pll_clock;
+}
+/**
+ * pdc_hardware_init - Initialize the hardware.
+ * @pdev: instance of pci_dev found
+ * @pdc_controller: controller specific information
+ * @pe: for the port address
+ */
+static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+{
+ long pll_clock;
+
+ /* Enable the ROM */
+ /*
+ if (pdev->resource[PCI_ROM_RESOURCE].start) {
+ pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
+ pdev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO DRV_NAME ": ROM enabled at 0x%08lx\n",
+ pdev->resource[PCI_ROM_RESOURCE].start);
+ }
+ */
+
+ /*
+ * Detect PLL input clock rate.
+ * On some system, where PCI bus is running at non-standard clock rate.
+ * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
+ * The pdc20275 controller employs PLL circuit to help correct timing registers setting.
+ */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ if(pll_clock < 0) /* counter overflow? Try again. */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ printk(KERN_INFO DRV_NAME ": PLL input clock %ld kHz\n", pll_clock/1000);
+
+ /* Adjust PLL control register */
+ pdc_adjust_pll(pe, pll_clock, board_idx);
+
+ return 0;
+}
+/**
+ * pdc2027x_init_one - PCI probe function
+ * Called when an instance of PCI adapter is inserted.
+ * This function checks whether the hardware is supported,
+ * initialize hardware and register an instance of ata_host_set to
+ * libata by providing struct ata_probe_ent and ata_device_add().
+ * (implements struct pci_driver.probe() )
+ *
+ * @pdev: instance of pci_dev found
+ * @ent: matching entry in the id_tbl[]
+ */
+static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+
+ struct ata_probe_ent *probe_ent = NULL;
+ int rc;
+
+ if (!printed_version++)
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+#ifdef PDC_20276_QUIRK
+ /*
+ * Skip Promise PDC20276 attached to I2O RAID controller
+ */
+ if ((pdev->device == PCI_DEVICE_ID_PROMISE_20276) &&
+ (pdev->bus->self) &&
+ (pdev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+ ((pdev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+ (pdev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+ printk(KERN_INFO DRV_NAME ": Skipping Promise PDC20276 "
+ "attached to I2O RAID controller.\n");
+ return -ENODEV;
+ }
+#endif
+
+#ifdef PDC_20270_QUIRK
+ /*
+ * Special IRQ handling for Promise PDC20270 attached to the
+ * DEC DC21150 PCI south bridge. (DC21150 PCI bridge can be found
+ * on Compaq ProLiant 800 and ProLiant 1600 servers.)
+ * FIXME: Not tested yet on libata.
+ */
+ if ((pdev->device == PCI_DEVICE_ID_PROMISE_20270) &&
+ (pdev->bus->self) &&
+ (pdev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+ (pdev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+ struct pci_dev *findev = NULL;
+
+ if (PCI_SLOT(pdev->devfn) & 2) {
+ /* This pdc20270 is in PCI slot with bit 1 set.
+ * Find the other pdc20270 in PCI slot with bit 1 cleared.
+ * If found, override my IRQ setting to irq of that device.
+ */
+ //d->extra = 0; // No extra DMA address on pdc20270
+
+ while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ if ((findev->vendor == pdev->vendor) &&
+ (findev->device == pdev->device) &&
+ (!(PCI_SLOT(findev->devfn) & 2))) {
+
+ if (pdev->irq != findev->irq) {
+ // Override the IRQ setting
+ pdev->irq = findev->irq;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+#endif
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ /* Prepare the probe entry */
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->pdev = pdev;
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = pdc2027x_port_info[board_idx].sht;
+ probe_ent->host_flags = pdc2027x_port_info[board_idx].host_flags;
+ probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+
+ probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+ ata_std_ports(&probe_ent->port[0]);
+ probe_ent->port[0].altstatus_addr =
+ probe_ent->port[0].ctl_addr =
+ pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+ probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+
+ probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+ ata_std_ports(&probe_ent->port[1]);
+ probe_ent->port[1].altstatus_addr =
+ probe_ent->port[1].ctl_addr =
+ pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+ probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+
+ probe_ent->n_ports = 2;
+
+ pci_set_master(pdev);
+ //pci_enable_intx(pdev);
+
+ /* initialize adapter */
+ if(pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
+ goto err_out_free_ent;
+
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+/**
+ * pdc2027x_remove_one - Called to remove a single instance of the
+ * adapter.
+ *
+ * @dev: The PCI device to remove.
+ * FIXME: module load/unload not working yet
+ */
+static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
+{
+ ata_pci_remove_one(pdev);
+}
+/**
+ * pdc2027x_init - Called after this module is loaded into the kernel.
+ */
+static int __init pdc2027x_init(void)
+{
+ return pci_module_init(&pdc2027x_pci_driver);
+}
+/**
+ * pdc2027x_exit - Called before this module unloaded from the kernel
+ */
+static void __exit pdc2027x_exit(void)
+{
+ pci_unregister_driver(&pdc2027x_pci_driver);
+}
+
+module_init(pdc2027x_init);
+module_exit(pdc2027x_exit);
next prev parent reply other threads:[~2004-10-18 10:32 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-10-13 10:06 [PATCH/RFC] Port of pdc202xx_new driver to libata Albert Lee
2004-10-13 19:32 ` Bartlomiej Zolnierkiewicz
2004-10-13 19:58 ` Jeff Garzik
2004-10-13 20:16 ` Bartlomiej Zolnierkiewicz
2004-10-18 10:30 ` Albert Lee [this message]
2004-10-18 17:00 ` Jeff Garzik
2004-10-18 17:26 ` Jeff Garzik
2004-10-21 8:36 ` Albert Lee
2004-10-21 23:10 ` Jeff Garzik
2004-10-22 2:32 ` Albert Lee
2004-10-27 14:46 ` Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='001901c4b4fd$88204bc0$294bbf09@tw.ibm.com' \
--to=albertcc@tw.ibm.com \
--cc=bzolnier@gmail.com \
--cc=jgarzik@pobox.com \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.