* NV-specific details such as register offsets, SATA phy location,
* hotplug info, etc.
*
+ * 0.10
+ * - Fixed spurious interrupts issue seen with the Maxtor 6H500F0 500GB
+ * drive. Also made the check_hotplug() callbacks return whether there
+ * was a hotplug interrupt or not. This was not the source of the
+ * spurious interrupts, but is the right thing to do anyway.
+ *
+ * 0.09
+ * - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
+ *
+ * 0.08
+ * - Added support for MCP51 and MCP55.
+ *
+ * 0.07
+ * - Added support for RAID class code.
+ *
+ * 0.06
+ * - Added generic SATA support by using a pci_device_id that filters on
+ * the IDE storage class code.
+ *
+ * 0.03
+ * - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using
+ * mmio_base, which is only set for the CK804/MCP04 case.
+ *
+ * 0.02
+ * - Added support for CK804 SATA controller.
+ *
+ * 0.01
+ * - Initial revision.
*/
#include <linux/config.h>
#define DRV_NAME "sata_nv"
#define DRV_VERSION "0.8"
-enum {
- NV_PORTS = 2,
- NV_PIO_MASK = 0x1f,
- NV_MWDMA_MASK = 0x07,
- NV_UDMA_MASK = 0x7f,
- NV_PORT0_SCR_REG_OFFSET = 0x00,
- NV_PORT1_SCR_REG_OFFSET = 0x40,
-
- NV_INT_STATUS = 0x10,
- NV_INT_STATUS_CK804 = 0x440,
- NV_INT_STATUS_PDEV_INT = 0x01,
- NV_INT_STATUS_PDEV_PM = 0x02,
- NV_INT_STATUS_PDEV_ADDED = 0x04,
- NV_INT_STATUS_PDEV_REMOVED = 0x08,
- NV_INT_STATUS_SDEV_INT = 0x10,
- NV_INT_STATUS_SDEV_PM = 0x20,
- NV_INT_STATUS_SDEV_ADDED = 0x40,
- NV_INT_STATUS_SDEV_REMOVED = 0x80,
- NV_INT_STATUS_PDEV_HOTPLUG = (NV_INT_STATUS_PDEV_ADDED |
- NV_INT_STATUS_PDEV_REMOVED),
- NV_INT_STATUS_SDEV_HOTPLUG = (NV_INT_STATUS_SDEV_ADDED |
- NV_INT_STATUS_SDEV_REMOVED),
- NV_INT_STATUS_HOTPLUG = (NV_INT_STATUS_PDEV_HOTPLUG |
- NV_INT_STATUS_SDEV_HOTPLUG),
-
- NV_INT_ENABLE = 0x11,
- NV_INT_ENABLE_CK804 = 0x441,
- NV_INT_ENABLE_PDEV_MASK = 0x01,
- NV_INT_ENABLE_PDEV_PM = 0x02,
- NV_INT_ENABLE_PDEV_ADDED = 0x04,
- NV_INT_ENABLE_PDEV_REMOVED = 0x08,
- NV_INT_ENABLE_SDEV_MASK = 0x10,
- NV_INT_ENABLE_SDEV_PM = 0x20,
- NV_INT_ENABLE_SDEV_ADDED = 0x40,
- NV_INT_ENABLE_SDEV_REMOVED = 0x80,
- NV_INT_ENABLE_PDEV_HOTPLUG = (NV_INT_ENABLE_PDEV_ADDED |
- NV_INT_ENABLE_PDEV_REMOVED),
- NV_INT_ENABLE_SDEV_HOTPLUG = (NV_INT_ENABLE_SDEV_ADDED |
- NV_INT_ENABLE_SDEV_REMOVED),
- NV_INT_ENABLE_HOTPLUG = (NV_INT_ENABLE_PDEV_HOTPLUG |
- NV_INT_ENABLE_SDEV_HOTPLUG),
-
- NV_INT_CONFIG = 0x12,
- NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
-
- // For PCI config register 20
- NV_MCP_SATA_CFG_20 = 0x50,
- NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04,
-};
+#define NV_PORTS 2
+#define NV_PIO_MASK 0x1f
+#define NV_MWDMA_MASK 0x07
+#define NV_UDMA_MASK 0x7f
+#define NV_PORT0_SCR_REG_OFFSET 0x00
+#define NV_PORT1_SCR_REG_OFFSET 0x40
+
+#define NV_INT_STATUS 0x10
+#define NV_INT_STATUS_CK804 0x440
+#define NV_INT_STATUS_PDEV_INT 0x01
+#define NV_INT_STATUS_PDEV_PM 0x02
+#define NV_INT_STATUS_PDEV_ADDED 0x04
+#define NV_INT_STATUS_PDEV_REMOVED 0x08
+#define NV_INT_STATUS_SDEV_INT 0x10
+#define NV_INT_STATUS_SDEV_PM 0x20
+#define NV_INT_STATUS_SDEV_ADDED 0x40
+#define NV_INT_STATUS_SDEV_REMOVED 0x80
+#define NV_INT_STATUS_PDEV_HOTPLUG (NV_INT_STATUS_PDEV_ADDED | \
+ NV_INT_STATUS_PDEV_REMOVED)
+#define NV_INT_STATUS_SDEV_HOTPLUG (NV_INT_STATUS_SDEV_ADDED | \
+ NV_INT_STATUS_SDEV_REMOVED)
+#define NV_INT_STATUS_HOTPLUG (NV_INT_STATUS_PDEV_HOTPLUG | \
+ NV_INT_STATUS_SDEV_HOTPLUG)
+
+#define NV_INT_ENABLE 0x11
+#define NV_INT_ENABLE_CK804 0x441
+#define NV_INT_ENABLE_PDEV_MASK 0x01
+#define NV_INT_ENABLE_PDEV_PM 0x02
+#define NV_INT_ENABLE_PDEV_ADDED 0x04
+#define NV_INT_ENABLE_PDEV_REMOVED 0x08
+#define NV_INT_ENABLE_SDEV_MASK 0x10
+#define NV_INT_ENABLE_SDEV_PM 0x20
+#define NV_INT_ENABLE_SDEV_ADDED 0x40
+#define NV_INT_ENABLE_SDEV_REMOVED 0x80
+#define NV_INT_ENABLE_PDEV_HOTPLUG (NV_INT_ENABLE_PDEV_ADDED | \
+ NV_INT_ENABLE_PDEV_REMOVED)
+#define NV_INT_ENABLE_SDEV_HOTPLUG (NV_INT_ENABLE_SDEV_ADDED | \
+ NV_INT_ENABLE_SDEV_REMOVED)
+#define NV_INT_ENABLE_HOTPLUG (NV_INT_ENABLE_PDEV_HOTPLUG | \
+ NV_INT_ENABLE_SDEV_HOTPLUG)
+
+#define NV_INT_CONFIG 0x12
+#define NV_INT_CONFIG_METHD 0x01 // 0 = INT, 1 = SMI
+
+// For PCI config register 20
+#define NV_MCP_SATA_CFG_20 0x50
+#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN 0x04
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static irqreturn_t nv_interrupt (int irq, void *dev_instance,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
{ 0, } /* terminate list */
};
+#define NV_HOST_FLAGS_SCR_MMIO 0x00000001
+
struct nv_host_desc
{
enum nv_host_type host_type;
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.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,
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+ return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ else
+ return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
+ struct ata_host_set *host_set = ap->host_set;
+ struct nv_host *host = host_set->private_data;
+
if (sc_reg > SCR_CONTROL)
return;
- iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+ writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ else
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_host_stop (struct ata_host_set *host_set)
{
struct nv_host *host = host_set->private_data;
+ struct pci_dev *pdev = to_pci_dev(host_set->dev);
// Disable hotplug event interrupts.
if (host->host_desc->disable_hotplug)
kfree(host);
- ata_pci_host_stop(host_set);
+ if (host_set->mmio_base)
+ pci_iounmap(pdev, host_set->mmio_base);
}
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int pci_dev_busy = 0;
int rc;
u32 bar;
- unsigned long base;
// Make sure this is a SATA controller by counting the number of bars
// (NVIDIA SATA controllers will always have six bars). Otherwise,
probe_ent->private_data = host;
- probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
- if (!probe_ent->mmio_base) {
- rc = -EIO;
- goto err_out_free_host;
- }
+ if (pci_resource_flags(pdev, 5) & IORESOURCE_MEM)
+ host->host_flags |= NV_HOST_FLAGS_SCR_MMIO;
- base = (unsigned long)probe_ent->mmio_base;
+ if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
+ unsigned long base;
- probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
- probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+ probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
+ if (probe_ent->mmio_base == NULL) {
+ rc = -EIO;
+ goto err_out_free_host;
+ }
+
+ base = (unsigned long)probe_ent->mmio_base;
+
+ probe_ent->port[0].scr_addr =
+ base + NV_PORT0_SCR_REG_OFFSET;
+ probe_ent->port[1].scr_addr =
+ base + NV_PORT1_SCR_REG_OFFSET;
+ } else {
+
+ probe_ent->port[0].scr_addr =
+ pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET;
+ probe_ent->port[1].scr_addr =
+ pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET;
+ }
pci_set_master(pdev);
return 0;
err_out_iounmap:
- pci_iounmap(pdev, probe_ent->mmio_base);
+ if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+ pci_iounmap(pdev, probe_ent->mmio_base);
err_out_free_host:
kfree(host);
err_out_free_ent: