pata_hpt{37x|3x2n}: SATA mode filtering

The Marvell bridge chips used on HighPoint SATA cards do not seem to support
the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes;  these cards are
based on HPT372/372A/372N/374 chips (judging from the vendor drivers), so
the Linux drivers need to have a mode_filter() method for these chips...

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
Sergei Shtylyov 2010-12-25 22:44:01 +03:00 committed by Jeff Garzik
parent b27dcfb067
commit 8e834c2e6d
2 changed files with 93 additions and 22 deletions

View file

@ -8,7 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc * Portions Copyright (C) 2003 Red Hat Inc
* Portions Copyright (C) 2005-2009 MontaVista Software, Inc. * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
* *
* TODO * TODO
* Look into engine reset on timeout errors. Should not be required. * Look into engine reset on timeout errors. Should not be required.
@ -24,7 +24,7 @@
#include <linux/libata.h> #include <linux/libata.h>
#define DRV_NAME "pata_hpt37x" #define DRV_NAME "pata_hpt37x"
#define DRV_VERSION "0.6.15" #define DRV_VERSION "0.6.16"
struct hpt_clock { struct hpt_clock {
u8 xfer_speed; u8 xfer_speed;
@ -301,6 +301,22 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
return mask; return mask;
} }
/**
* hpt372_filter - mode selection filter
* @adev: ATA device
* @mask: mode mask
*
* The Marvell bridge chips used on the HighPoint SATA cards do not seem
* to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
*/
static unsigned long hpt372_filter(struct ata_device *adev, unsigned long mask)
{
if (ata_id_is_sata(adev->id))
mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
return mask;
}
/** /**
* hpt37x_cable_detect - Detect the cable type * hpt37x_cable_detect - Detect the cable type
* @ap: ATA port to detect on * @ap: ATA port to detect on
@ -586,11 +602,11 @@ static struct ata_port_operations hpt370a_port_ops = {
}; };
/* /*
* Configuration for HPT372, HPT371, HPT302. Slightly different PIO * Configuration for HPT371 and HPT302. Slightly different PIO and DMA
* and DMA mode setting functionality. * mode setting functionality.
*/ */
static struct ata_port_operations hpt372_port_ops = { static struct ata_port_operations hpt302_port_ops = {
.inherits = &ata_bmdma_port_ops, .inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt37x_bmdma_stop, .bmdma_stop = hpt37x_bmdma_stop,
@ -602,7 +618,17 @@ static struct ata_port_operations hpt372_port_ops = {
}; };
/* /*
* Configuration for HPT374. Mode setting works like 372 and friends * Configuration for HPT372. Mode setting works like 371 and 302
* but we have a mode filter.
*/
static struct ata_port_operations hpt372_port_ops = {
.inherits = &hpt302_port_ops,
.mode_filter = hpt372_filter,
};
/*
* Configuration for HPT374. Mode setting and filtering works like 372
* but we have a different cable detection procedure for function 1. * but we have a different cable detection procedure for function 1.
*/ */
@ -753,7 +779,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA5, .udma_mask = ATA_UDMA5,
.port_ops = &hpt370a_port_ops .port_ops = &hpt370a_port_ops
}; };
/* HPT371, 372 and friends - UDMA133 */ /* HPT372 - UDMA133 */
static const struct ata_port_info info_hpt372 = { static const struct ata_port_info info_hpt372 = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
@ -761,6 +787,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &hpt372_port_ops .port_ops = &hpt372_port_ops
}; };
/* HPT371, 302 - UDMA133 */
static const struct ata_port_info info_hpt302 = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &hpt302_port_ops
};
/* HPT374 - UDMA100, function 1 uses different prereset method */ /* HPT374 - UDMA100, function 1 uses different prereset method */
static const struct ata_port_info info_hpt374_fn0 = { static const struct ata_port_info info_hpt374_fn0 = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
@ -828,7 +862,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
} else { } else {
switch(dev->device) { switch(dev->device) {
case PCI_DEVICE_ID_TTI_HPT372: case PCI_DEVICE_ID_TTI_HPT372:
/* 372N if rev >= 2*/ /* 372N if rev >= 2 */
if (rev >= 2) if (rev >= 2)
return -ENODEV; return -ENODEV;
ppi[0] = &info_hpt372; ppi[0] = &info_hpt372;
@ -838,14 +872,14 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* 302N if rev > 1 */ /* 302N if rev > 1 */
if (rev > 1) if (rev > 1)
return -ENODEV; return -ENODEV;
ppi[0] = &info_hpt372; ppi[0] = &info_hpt302;
/* Check this */ /* Check this */
chip_table = &hpt302; chip_table = &hpt302;
break; break;
case PCI_DEVICE_ID_TTI_HPT371: case PCI_DEVICE_ID_TTI_HPT371:
if (rev > 1) if (rev > 1)
return -ENODEV; return -ENODEV;
ppi[0] = &info_hpt372; ppi[0] = &info_hpt302;
chip_table = &hpt371; chip_table = &hpt371;
/* Single channel device, master is not present /* Single channel device, master is not present
but the BIOS (or us for non x86) must mark it but the BIOS (or us for non x86) must mark it

View file

@ -8,7 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc * Portions Copyright (C) 2003 Red Hat Inc
* Portions Copyright (C) 2005-2009 MontaVista Software, Inc. * Portions Copyright (C) 2005-2010 MontaVista Software, Inc.
* *
* *
* TODO * TODO
@ -25,7 +25,7 @@
#include <linux/libata.h> #include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n" #define DRV_NAME "pata_hpt3x2n"
#define DRV_VERSION "0.3.10" #define DRV_VERSION "0.3.11"
enum { enum {
HPT_PCI_FAST = (1 << 31), HPT_PCI_FAST = (1 << 31),
@ -112,6 +112,22 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
return 0xffffffffU; /* silence compiler warning */ return 0xffffffffU; /* silence compiler warning */
} }
/**
* hpt372n_filter - mode selection filter
* @adev: ATA device
* @mask: mode mask
*
* The Marvell bridge chips used on the HighPoint SATA cards do not seem
* to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
*/
static unsigned long hpt372n_filter(struct ata_device *adev, unsigned long mask)
{
if (ata_id_is_sata(adev->id))
mask &= ~((0xE << ATA_SHIFT_UDMA) | ATA_MASK_MWDMA);
return mask;
}
/** /**
* hpt3x2n_cable_detect - Detect the cable type * hpt3x2n_cable_detect - Detect the cable type
* @ap: ATA port to detect on * @ap: ATA port to detect on
@ -328,10 +344,10 @@ static struct scsi_host_template hpt3x2n_sht = {
}; };
/* /*
* Configuration for HPT3x2n. * Configuration for HPT302N/371N.
*/ */
static struct ata_port_operations hpt3x2n_port_ops = { static struct ata_port_operations hpt3xxn_port_ops = {
.inherits = &ata_bmdma_port_ops, .inherits = &ata_bmdma_port_ops,
.bmdma_stop = hpt3x2n_bmdma_stop, .bmdma_stop = hpt3x2n_bmdma_stop,
@ -345,6 +361,15 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.prereset = hpt3x2n_pre_reset, .prereset = hpt3x2n_pre_reset,
}; };
/*
* Configuration for HPT372N. Same as 302N/371N but we have a mode filter.
*/
static struct ata_port_operations hpt372n_port_ops = {
.inherits = &hpt3xxn_port_ops,
.mode_filter = &hpt372n_filter,
};
/** /**
* hpt3xn_calibrate_dpll - Calibrate the DPLL loop * hpt3xn_calibrate_dpll - Calibrate the DPLL loop
* @dev: PCI device * @dev: PCI device
@ -437,15 +462,23 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id) static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{ {
/* HPT372N and friends - UDMA133 */ /* HPT372N - UDMA133 */
static const struct ata_port_info info = { static const struct ata_port_info info_hpt372n = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2, .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &hpt3x2n_port_ops .port_ops = &hpt372n_port_ops
}; };
const struct ata_port_info *ppi[] = { &info, NULL }; /* HPT302N and HPT371N - UDMA133 */
static const struct ata_port_info info_hpt3xxn = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &hpt3xxn_port_ops
};
const struct ata_port_info *ppi[] = { &info_hpt3xxn, NULL };
u8 rev = dev->revision; u8 rev = dev->revision;
u8 irqmask; u8 irqmask;
unsigned int pci_mhz; unsigned int pci_mhz;
@ -461,24 +494,28 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
switch(dev->device) { switch(dev->device) {
case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_TTI_HPT366:
/* 372N if rev >= 6 */
if (rev < 6) if (rev < 6)
return -ENODEV; return -ENODEV;
break; goto hpt372n;
case PCI_DEVICE_ID_TTI_HPT371: case PCI_DEVICE_ID_TTI_HPT371:
/* 371N if rev >= 2 */
if (rev < 2) if (rev < 2)
return -ENODEV; return -ENODEV;
/* 371N if rev > 1 */
break; break;
case PCI_DEVICE_ID_TTI_HPT372: case PCI_DEVICE_ID_TTI_HPT372:
/* 372N if rev >= 2*/ /* 372N if rev >= 2 */
if (rev < 2) if (rev < 2)
return -ENODEV; return -ENODEV;
break; goto hpt372n;
case PCI_DEVICE_ID_TTI_HPT302: case PCI_DEVICE_ID_TTI_HPT302:
/* 302N if rev >= 2 */
if (rev < 2) if (rev < 2)
return -ENODEV; return -ENODEV;
break; break;
case PCI_DEVICE_ID_TTI_HPT372N: case PCI_DEVICE_ID_TTI_HPT372N:
hpt372n:
ppi[0] = &info_hpt372n;
break; break;
default: default:
printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device); printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);