diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 21:47:46 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-06 21:47:46 +0300 |
commit | 2dd550b90b03d5f236a18ae491bf6e70798469a8 (patch) | |
tree | 5cc20d0c9f732b06aea788a78a6da9e02be5e41b /drivers | |
parent | 8755e568250ecd3149ecd3495d8070f3a5384f73 (diff) | |
parent | bc5468f52b785ffa1fe0ea289baec2c51384d436 (diff) | |
download | linux-2dd550b90b03d5f236a18ae491bf6e70798469a8.tar.xz |
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
ata_piix.c:piix_init_one() must be __devinit
sata_via.c: Remove missleading comment.
libata-core: unblacklist HITACHI drives
sata_nv: fix ATAPI issues with memory over 4GB (v7)
ata: drivers/ata/sata_mv.c needs dmapool.h
libata: kill now unused n_iter and fix sata_fsl
ahci: fix CAP.NP and PI handling
sata_mv: Support SoC controllers
Rename: linux/pata_platform.h to linux/ata_platform.h
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.c | 35 | ||||
-rw-r--r-- | drivers/ata/ata_piix.c | 3 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 2 | ||||
-rw-r--r-- | drivers/ata/pata_of_platform.c | 2 | ||||
-rw-r--r-- | drivers/ata/pata_platform.c | 2 | ||||
-rw-r--r-- | drivers/ata/sata_fsl.c | 4 | ||||
-rw-r--r-- | drivers/ata/sata_mv.c | 366 | ||||
-rw-r--r-- | drivers/ata/sata_nv.c | 78 | ||||
-rw-r--r-- | drivers/ata/sata_via.c | 2 | ||||
-rw-r--r-- | drivers/ide/legacy/ide_platform.c | 2 |
10 files changed, 412 insertions, 84 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 27c8d56111c2..29e71bddd6ff 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -679,24 +679,20 @@ static void ahci_save_initial_config(struct pci_dev *pdev, /* cross check port_map and cap.n_ports */ if (port_map) { - u32 tmp_port_map = port_map; - int n_ports = ahci_nr_ports(cap); + int map_ports = 0; - for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) { - if (tmp_port_map & (1 << i)) { - n_ports--; - tmp_port_map &= ~(1 << i); - } - } + for (i = 0; i < AHCI_MAX_PORTS; i++) + if (port_map & (1 << i)) + map_ports++; - /* If n_ports and port_map are inconsistent, whine and - * clear port_map and let it be generated from n_ports. + /* If PI has more ports than n_ports, whine, clear + * port_map and let it be generated from n_ports. */ - if (n_ports || tmp_port_map) { + if (map_ports > ahci_nr_ports(cap)) { dev_printk(KERN_WARNING, &pdev->dev, - "nr_ports (%u) and implemented port map " - "(0x%x) don't match, using nr_ports\n", - ahci_nr_ports(cap), port_map); + "implemented port map (0x%x) contains more " + "ports than nr_ports (%u), using nr_ports\n", + port_map, ahci_nr_ports(cap)); port_map = 0; } } @@ -2201,7 +2197,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct ata_host *host; - int i, rc; + int n_ports, i, rc; VPRINTK("ENTER\n"); @@ -2255,7 +2251,14 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (hpriv->cap & HOST_CAP_PMP) pi.flags |= ATA_FLAG_PMP; - host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map)); + /* CAP.NP sometimes indicate the index of the last enabled + * port, at other times, that of the last possible port, so + * determining the maximum port number requires looking at + * both CAP.NP and port_map. + */ + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); + + host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); if (!host) return -ENOMEM; host->iomap = pcim_iomap_table(pdev); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 4b99ed0c59bb..9c2515f67de5 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1603,7 +1603,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) * Zero on success, or -ERRNO value. */ -static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit piix_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { static int printed_version; struct device *dev = &pdev->dev; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 361cf50cbdea..3011919f3ec8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4154,8 +4154,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* NCQ is broken */ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ }, { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, - { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ }, - { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ }, { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ }, { "ST3160023AS", "3.42", ATA_HORKAGE_NONCQ }, diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 938f48a807eb..408da30594c4 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -12,7 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_platform.h> -#include <linux/pata_platform.h> +#include <linux/ata_platform.h> static int __devinit pata_of_platform_probe(struct of_device *ofdev, const struct of_device_id *match) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 224bb6c2030a..aad7adc6ea56 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -19,7 +19,7 @@ #include <linux/ata.h> #include <linux/libata.h> #include <linux/platform_device.h> -#include <linux/pata_platform.h> +#include <linux/ata_platform.h> #define DRV_NAME "pata_platform" #define DRV_VERSION "1.2" diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 922d7b2efba8..efcb66b6ccef 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -355,8 +355,8 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, ata_port_printk(qc->ap, KERN_ERR, "s/g len unaligned : 0x%x\n", sg_len); - if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) && - (qc->n_iter + 1 != qc->n_elem)) { + if (num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1) && + sg_next(sg) != NULL) { VPRINTK("setting indirect prde\n"); prd_ptr_to_indirect_ext = prd; prd->dba = cpu_to_le32(indirect_ext_segment_paddr); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 3c1b5c9027db..080b8362f8d6 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -69,8 +69,11 @@ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/dmapool.h> #include <linux/dma-mapping.h> #include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/ata_platform.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -179,6 +182,8 @@ enum { HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, HC_MAIN_IRQ_MASK_OFS = 0x1d64, + HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020, + HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024, PORT0_ERR = (1 << 0), /* shift by port # */ PORT0_DONE = (1 << 1), /* shift by port # */ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */ @@ -194,11 +199,13 @@ enum { TWSI_INT = (1 << 24), HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */ HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */ + HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */ HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT | HC_MAIN_RSVD), HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE | HC_MAIN_RSVD_5), + HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC), /* SATAHC registers */ HC_CFG_OFS = 0, @@ -368,6 +375,7 @@ enum chip_type { chip_608x, chip_6042, chip_7042, + chip_soc, }; /* Command ReQuest Block: 32B */ @@ -424,6 +432,10 @@ struct mv_host_priv { u32 hp_flags; struct mv_port_signal signal[8]; const struct mv_hw_ops *ops; + int n_ports; + void __iomem *base; + void __iomem *main_cause_reg_addr; + void __iomem *main_mask_reg_addr; u32 irq_cause_ofs; u32 irq_mask_ofs; u32 unmask_all_irqs; @@ -482,6 +494,15 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx, static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int n_hc); static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio); +static void mv_soc_enable_leds(struct mv_host_priv *hpriv, + void __iomem *mmio); +static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio); +static int mv_soc_reset_hc(struct mv_host_priv *hpriv, + void __iomem *mmio, unsigned int n_hc); +static void mv_soc_reset_flash(struct mv_host_priv *hpriv, + void __iomem *mmio); +static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio); static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio); static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port_no); @@ -661,6 +682,12 @@ static const struct ata_port_info mv_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &mv_iie_ops, }, + { /* chip_soc */ + .flags = MV_COMMON_FLAGS | MV_FLAG_SOC, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &mv_iie_ops, + }, }; static const struct pci_device_id mv_pci_tbl[] = { @@ -711,6 +738,15 @@ static const struct mv_hw_ops mv6xxx_ops = { .reset_bus = mv_reset_pci_bus, }; +static const struct mv_hw_ops mv_soc_ops = { + .phy_errata = mv6_phy_errata, + .enable_leds = mv_soc_enable_leds, + .read_preamp = mv_soc_read_preamp, + .reset_hc = mv_soc_reset_hc, + .reset_flash = mv_soc_reset_flash, + .reset_bus = mv_soc_reset_bus, +}; + /* * Functions */ @@ -749,9 +785,15 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port) (mv_hardport_from_port(port) * MV_PORT_REG_SZ); } +static inline void __iomem *mv_host_base(struct ata_host *host) +{ + struct mv_host_priv *hpriv = host->private_data; + return hpriv->base; +} + static inline void __iomem *mv_ap_base(struct ata_port *ap) { - return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no); + return mv_port_base(mv_host_base(ap->host), ap->port_no); } static inline int mv_get_hc_count(unsigned long port_flags) @@ -1649,16 +1691,21 @@ static void mv_intr_edma(struct ata_port *ap) */ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) { - void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = host->private_data; + void __iomem *mmio = hpriv->base; void __iomem *hc_mmio = mv_hc_base(mmio, hc); u32 hc_irq_cause; - int port, port0; + int port, port0, last_port; if (hc == 0) port0 = 0; else port0 = MV_PORTS_PER_HC; + if (HAS_PCI(host)) + last_port = port0 + MV_PORTS_PER_HC; + else + last_port = port0 + hpriv->n_ports; /* we'll need the HC success int register in most cases */ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS); if (!hc_irq_cause) @@ -1669,7 +1716,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n", hc, relevant, hc_irq_cause); - for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { + for (port = port0; port < port0 + last_port; port++) { struct ata_port *ap = host->ports[port]; struct mv_port_priv *pp = ap->private_data; int have_err_bits, hard_port, shift; @@ -1764,13 +1811,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio) static irqreturn_t mv_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; + struct mv_host_priv *hpriv = host->private_data; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; + void __iomem *mmio = hpriv->base; u32 irq_stat, irq_mask; spin_lock(&host->lock); - irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS); - irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS); + + irq_stat = readl(hpriv->main_cause_reg_addr); + irq_mask = readl(hpriv->main_mask_reg_addr); /* check the cases where we either have nothing pending or have read * a bogus register value which can indicate HW removal or PCI fault @@ -1827,7 +1876,8 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in) static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) { - void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->base; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); @@ -1840,7 +1890,8 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { - void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->base; void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); @@ -2178,6 +2229,93 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio, writel(m2, port_mmio + PHY_MODE2); } +/* TODO: use the generic LED interface to configure the SATA Presence */ +/* & Acitivy LEDs on the board */ +static void mv_soc_enable_leds(struct mv_host_priv *hpriv, + void __iomem *mmio) +{ + return; +} + +static void mv_soc_read_preamp(struct mv_host_priv *hpriv, int idx, + void __iomem *mmio) +{ + void __iomem *port_mmio; + u32 tmp; + + port_mmio = mv_port_base(mmio, idx); + tmp = readl(port_mmio + PHY_MODE2); + + hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */ + hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */ +} + +#undef ZERO +#define ZERO(reg) writel(0, port_mmio + (reg)) +static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv, + void __iomem *mmio, unsigned int port) +{ + void __iomem *port_mmio = mv_port_base(mmio, port); + + writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS); + + mv_channel_reset(hpriv, mmio, port); + + ZERO(0x028); /* command */ + writel(0x101f, port_mmio + EDMA_CFG_OFS); + ZERO(0x004); /* timer */ + ZERO(0x008); /* irq err cause */ + ZERO(0x00c); /* irq err mask */ + ZERO(0x010); /* rq bah */ + ZERO(0x014); /* rq inp */ + ZERO(0x018); /* rq outp */ + ZERO(0x01c); /* respq bah */ + ZERO(0x024); /* respq outp */ + ZERO(0x020); /* respq inp */ + ZERO(0x02c); /* test control */ + writel(0xbc, port_mmio + EDMA_IORDY_TMOUT); +} + +#undef ZERO + +#define ZERO(reg) writel(0, hc_mmio + (reg)) +static void mv_soc_reset_one_hc(struct mv_host_priv *hpriv, + void __iomem *mmio) +{ + void __iomem *hc_mmio = mv_hc_base(mmio, 0); + + ZERO(0x00c); + ZERO(0x010); + ZERO(0x014); + +} + +#undef ZERO + +static int mv_soc_reset_hc(struct mv_host_priv *hpriv, + void __iomem *mmio, unsigned int n_hc) +{ + unsigned int port; + + for (port = 0; port < hpriv->n_ports; port++) + mv_soc_reset_hc_port(hpriv, mmio, port); + + mv_soc_reset_one_hc(hpriv, mmio); + + return 0; +} + +static void mv_soc_reset_flash(struct mv_host_priv *hpriv, + void __iomem *mmio) +{ + return; +} + +static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio) +{ + return; +} + static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, unsigned int port_no) { @@ -2342,7 +2480,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class, { struct ata_port *ap = link->ap; struct mv_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + void __iomem *mmio = hpriv->base; mv_stop_dma(ap); @@ -2383,7 +2521,7 @@ static void mv_error_handler(struct ata_port *ap) static void mv_eh_freeze(struct ata_port *ap) { - void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = ap->host->private_data; unsigned int hc = (ap->port_no > 3) ? 1 : 0; u32 tmp, mask; unsigned int shift; @@ -2397,13 +2535,14 @@ static void mv_eh_freeze(struct ata_port *ap) mask = 0x3 << shift; /* disable assertion of portN err, done events */ - tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS); - writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS); + tmp = readl(hpriv->main_mask_reg_addr); + writelfl(tmp & ~mask, hpriv->main_mask_reg_addr); } static void mv_eh_thaw(struct ata_port *ap) { - void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + struct mv_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->base; unsigned int hc = (ap->port_no > 3) ? 1 : 0; void __iomem *hc_mmio = mv_hc_base(mmio, hc); void __iomem *port_mmio = mv_ap_base(ap); @@ -2430,8 +2569,8 @@ static void mv_eh_thaw(struct ata_port *ap) writel(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); /* enable assertion of portN err, done events */ - tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS); - writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS); + tmp = readl(hpriv->main_mask_reg_addr); + writelfl(tmp | mask, hpriv->main_mask_reg_addr); } /** @@ -2598,9 +2737,13 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) break; } break; + case chip_soc: + hpriv->ops = &mv_soc_ops; + hp_flags |= MV_HP_ERRATA_60X1C0; + break; default: - dev_printk(KERN_ERR, &pdev->dev, + dev_printk(KERN_ERR, host->dev, "BUG: invalid board index %u\n", board_idx); return 1; } @@ -2633,15 +2776,25 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx) static int mv_init_host(struct ata_host *host, unsigned int board_idx) { int rc = 0, n_hc, port, hc; - void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv = host->private_data; - - /* global interrupt mask */ - writel(0, mmio + HC_MAIN_IRQ_MASK_OFS); + void __iomem *mmio = hpriv->base; rc = mv_chip_id(host, board_idx); if (rc) - goto done; + goto done; + + if (HAS_PCI(host)) { + hpriv->main_cause_reg_addr = hpriv->base + + HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_mask_reg_addr = hpriv->base + HC_MAIN_IRQ_MASK_OFS; + } else { + hpriv->main_cause_reg_addr = hpriv->base + + HC_SOC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_mask_reg_addr = hpriv->base + + HC_SOC_MAIN_IRQ_MASK_OFS; + } + /* global interrupt mask */ + writel(0, hpriv->main_mask_reg_addr); n_hc = mv_get_hc_count(host->ports[0]->flags); @@ -2672,13 +2825,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) for (port = 0; port < host->n_ports; port++) { struct ata_port *ap = host->ports[port]; void __iomem *port_mmio = mv_port_base(mmio, port); - unsigned int offset = port_mmio - mmio; mv_port_init(&ap->ioaddr, port_mmio); #ifdef CONFIG_PCI - ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); - ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); + if (HAS_PCI(host)) { + unsigned int offset = port_mmio - mmio; + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio"); + ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port"); + } #endif } @@ -2694,35 +2849,141 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS); } - /* Clear any currently outstanding host interrupt conditions */ - writelfl(0, mmio + hpriv->irq_cause_ofs); + if (HAS_PCI(host)) { + /* Clear any currently outstanding host interrupt conditions */ + writelfl(0, mmio + hpriv->irq_cause_ofs); - /* and unmask interrupt generation for host regs */ - writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); + /* and unmask interrupt generation for host regs */ + writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); + if (IS_GEN_I(hpriv)) + writelfl(~HC_MAIN_MASKED_IRQS_5, + hpriv->main_mask_reg_addr); + else + writelfl(~HC_MAIN_MASKED_IRQS, + hpriv->main_mask_reg_addr); + + VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " + "PCI int cause/mask=0x%08x/0x%08x\n", + readl(hpriv->main_cause_reg_addr), + readl(hpriv->main_mask_reg_addr), + readl(mmio + hpriv->irq_cause_ofs), + readl(mmio + hpriv->irq_mask_ofs)); + } else { + writelfl(~HC_MAIN_MASKED_IRQS_SOC, + hpriv->main_mask_reg_addr); + VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n", + readl(hpriv->main_cause_reg_addr), + readl(hpriv->main_mask_reg_addr)); + } +done: + return rc; +} - if (IS_GEN_I(hpriv)) - writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); - else - writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); +/** + * mv_platform_probe - handle a positive probe of an soc Marvell + * host + * @pdev: platform device found + * + * LOCKING: + * Inherited from caller. + */ +static int mv_platform_probe(struct platform_device *pdev) +{ + static int printed_version; + const struct mv_sata_platform_data *mv_platform_data; + const struct ata_port_info *ppi[] = + { &mv_port_info[chip_soc], NULL }; + struct ata_host *host; + struct mv_host_priv *hpriv; + struct resource *res; + int n_ports, rc; - VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " - "PCI int cause/mask=0x%08x/0x%08x\n", - readl(mmio + HC_MAIN_IRQ_CAUSE_OFS), - readl(mmio + HC_MAIN_IRQ_MASK_OFS), - readl(mmio + hpriv->irq_cause_ofs), - readl(mmio + hpriv->irq_mask_ofs)); + if (!printed_version++) + dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); -done: - return rc; + /* + * Simple resource validation .. + */ + if (unlikely(pdev->num_resources != 2)) { + dev_err(&pdev->dev, "invalid number of resources\n"); + return -EINVAL; + } + + /* + * Get the register base first + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + return -EINVAL; + + /* allocate host */ + mv_platform_data = pdev->dev.platform_data; + n_ports = mv_platform_data->n_ports; + + host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); + hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); + + if (!host || !hpriv) + return -ENOMEM; + host->private_data = hpriv; + hpriv->n_ports = n_ports; + + host->iomap = NULL; + hpriv->base = ioremap(res->start, res->end - res->start + 1); + hpriv->base -= MV_SATAHC0_REG_BASE; + + /* initialize adapter */ + rc = mv_init_host(host, chip_soc); + if (rc) + return rc; + + dev_printk(KERN_INFO, &pdev->dev, + "slots %u ports %d\n", (unsigned)MV_MAX_Q_DEPTH, + host->n_ports); + + return ata_host_activate(host, platform_get_irq(pdev, 0), mv_interrupt, + IRQF_SHARED, &mv6_sht); +} + +/* + * + * mv_platform_remove - unplug a platform interface + * @pdev: platform device + * + * A platform bus SATA device has been unplugged. Perform the needed + * cleanup. Also called on module unload for any active devices. + */ +static int __devexit mv_platform_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + struct mv_host_priv *hpriv = host->private_data; + void __iomem *base = hpriv->base; + + ata_host_detach(host); + iounmap(base); + return 0; } +static struct platform_driver mv_platform_driver = { + .probe = mv_platform_probe, + .remove = __devexit_p(mv_platform_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + + #ifdef CONFIG_PCI -static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static int mv_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent); + static struct pci_driver mv_pci_driver = { .name = DRV_NAME, .id_table = mv_pci_tbl, - .probe = mv_init_one, + .probe = mv_pci_init_one, .remove = ata_pci_remove_one, }; @@ -2828,14 +3089,15 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev) } /** - * mv_init_one - handle a positive probe of a Marvell host + * mv_pci_init_one - handle a positive probe of a PCI Marvell host * @pdev: PCI device found * @ent: PCI device ID entry for the matched host * * LOCKING: * Inherited from caller. */ -static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +static int mv_pci_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; @@ -2855,6 +3117,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!host || !hpriv) return -ENOMEM; host->private_data = hpriv; + hpriv->n_ports = n_ports; /* acquire resources */ rc = pcim_enable_device(pdev); @@ -2867,6 +3130,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; host->iomap = pcim_iomap_table(pdev); + hpriv->base = host->iomap[MV_PRIMARY_BAR]; rc = pci_go_64(pdev); if (rc) @@ -2895,11 +3159,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } #endif +static int mv_platform_probe(struct platform_device *pdev); +static int __devexit mv_platform_remove(struct platform_device *pdev); + static int __init mv_init(void) { int rc = -ENODEV; #ifdef CONFIG_PCI rc = pci_register_driver(&mv_pci_driver); + if (rc < 0) + return rc; +#endif + rc = platform_driver_register(&mv_platform_driver); + +#ifdef CONFIG_PCI + if (rc < 0) + pci_unregister_driver(&mv_pci_driver); #endif return rc; } @@ -2909,6 +3184,7 @@ static void __exit mv_exit(void) #ifdef CONFIG_PCI pci_unregister_driver(&mv_pci_driver); #endif + platform_driver_unregister(&mv_platform_driver); } MODULE_AUTHOR("Brett Russ"); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index bfe92a43cf89..ed5473bf7a0a 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -247,6 +247,7 @@ struct nv_adma_port_priv { void __iomem *ctl_block; void __iomem *gen_block; void __iomem *notifier_clear_block; + u64 adma_dma_mask; u8 flags; int last_issue_ncq; }; @@ -715,9 +716,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); struct nv_adma_port_priv *pp = ap->private_data; + struct nv_adma_port_priv *port0, *port1; + struct scsi_device *sdev0, *sdev1; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u64 bounce_limit; - unsigned long segment_boundary; + unsigned long segment_boundary, flags; unsigned short sg_tablesize; int rc; int adma_enable; @@ -729,6 +731,8 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Not a proper libata device, ignore */ return rc; + spin_lock_irqsave(ap->lock, flags); + if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) { /* * NVIDIA reports that ADMA mode does not support ATAPI commands. @@ -737,7 +741,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev) * Restrict DMA parameters as required by the legacy interface * when an ATAPI device is connected. */ - bounce_limit = ATA_DMA_MASK; segment_boundary = ATA_DMA_BOUNDARY; /* Subtract 1 since an extra entry may be needed for padding, see libata-scsi.c */ @@ -748,7 +751,6 @@ static int nv_adma_slave_config(struct scsi_device *sdev) adma_enable = 0; nv_adma_register_mode(ap); } else { - bounce_limit = *ap->dev->dma_mask; segment_boundary = NV_ADMA_DMA_BOUNDARY; sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; adma_enable = 1; @@ -774,12 +776,49 @@ static int nv_adma_slave_config(struct scsi_device *sdev) if (current_reg != new_reg) pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg); - blk_queue_bounce_limit(sdev->request_queue, bounce_limit); + port0 = ap->host->ports[0]->private_data; + port1 = ap->host->ports[1]->private_data; + sdev0 = ap->host->ports[0]->link.device[0].sdev; + sdev1 = ap->host->ports[1]->link.device[0].sdev; + if ((port0->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) || + (port1->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) { + /** We have to set the DMA mask to 32-bit if either port is in + ATAPI mode, since they are on the same PCI device which is + used for DMA mapping. If we set the mask we also need to set + the bounce limit on both ports to ensure that the block + layer doesn't feed addresses that cause DMA mapping to + choke. If either SCSI device is not allocated yet, it's OK + since that port will discover its correct setting when it + does get allocated. + Note: Setting 32-bit mask should not fail. */ + if (sdev0) + blk_queue_bounce_limit(sdev0->request_queue, + ATA_DMA_MASK); + if (sdev1) + blk_queue_bounce_limit(sdev1->request_queue, + ATA_DMA_MASK); + + pci_set_dma_mask(pdev, ATA_DMA_MASK); + } else { + /** This shouldn't fail as it was set to this value before */ + pci_set_dma_mask(pdev, pp->adma_dma_mask); + if (sdev0) + blk_queue_bounce_limit(sdev0->request_queue, + pp->adma_dma_mask); + if (sdev1) + blk_queue_bounce_limit(sdev1->request_queue, + pp->adma_dma_mask); + } + blk_queue_segment_boundary(sdev->request_queue, segment_boundary); blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); ata_port_printk(ap, KERN_INFO, - "bounce limit 0x%llX, segment boundary 0x%lX, hw segs %hu\n", - (unsigned long long)bounce_limit, segment_boundary, sg_tablesize); + "DMA mask 0x%llX, segment boundary 0x%lX, hw segs %hu\n", + (unsigned long long)*ap->host->dev->dma_mask, + segment_boundary, sg_tablesize); + + spin_unlock_irqrestore(ap->lock, flags); + return rc; } @@ -1140,10 +1179,20 @@ static int nv_adma_port_start(struct ata_port *ap) void *mem; dma_addr_t mem_dma; void __iomem *mmio; + struct pci_dev *pdev = to_pci_dev(dev); u16 tmp; VPRINTK("ENTER\n"); + /* Ensure DMA mask is set to 32-bit before allocating legacy PRD and + pad buffers */ + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + return rc; + rc = ata_port_start(ap); if (rc) return rc; @@ -1159,6 +1208,15 @@ static int nv_adma_port_start(struct ata_port *ap) pp->notifier_clear_block = pp->gen_block + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no); + /* Now that the legacy PRD and padding buffer are allocated we can + safely raise the DMA mask to allocate the CPB/APRD table. + These are allowed to fail since we store the value that ends up + being used to set as the bounce limit in slave_config later if + needed. */ + pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + pp->adma_dma_mask = *dev->dma_mask; + mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) @@ -2417,12 +2475,6 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) hpriv->type = type; host->private_data = hpriv; - /* set 64bit dma masks, may fail */ - if (type == ADMA) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) - pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - } - /* request and iomap NV_MMIO_BAR */ rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME); if (rc) diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 3ef072ff319d..30caa0337190 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -30,8 +30,6 @@ * Hardware documentation available under NDA. * * - * To-do list: - * - VT6421 PATA support * */ diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 26c82ce602de..688fcae17488 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -17,7 +17,7 @@ #include <linux/ide.h> #include <linux/ioport.h> #include <linux/module.h> -#include <linux/pata_platform.h> +#include <linux/ata_platform.h> #include <linux/platform_device.h> #include <linux/io.h> |