📄 sata_sil.c
字号:
/* * sata_sil.c - Silicon Image SATA * * Maintained by: Jeff Garzik <jgarzik@pobox.com> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * * Copyright 2003-2005 Red Hat, Inc. * Copyright 2003 Benjamin Herrenschmidt * * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * * libata documentation is available via 'make {ps|pdf}docs', * as Documentation/DocBook/libata.* * * Documentation for SiI 3112: * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 * * Other errata and documentation available under NDA. * */#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 <linux/interrupt.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <linux/libata.h>#define DRV_NAME "sata_sil"#define DRV_VERSION "2.3"enum { SIL_MMIO_BAR = 5, /* * host flags */ SIL_FLAG_NO_SATA_IRQ = (1 << 28), SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29), SIL_FLAG_MOD15WRITE = (1 << 30), SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME, /* * Controller IDs */ sil_3112 = 0, sil_3112_no_sata_irq = 1, sil_3512 = 2, sil_3114 = 3, /* * Register offsets */ SIL_SYSCFG = 0x48, /* * Register bits */ /* SYSCFG */ SIL_MASK_IDE0_INT = (1 << 22), SIL_MASK_IDE1_INT = (1 << 23), SIL_MASK_IDE2_INT = (1 << 24), SIL_MASK_IDE3_INT = (1 << 25), SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT, SIL_MASK_4PORT = SIL_MASK_2PORT | SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT, /* BMDMA/BMDMA2 */ SIL_INTR_STEERING = (1 << 1), SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */ SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */ SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */ SIL_DMA_ACTIVE = (1 << 16), /* DMA running */ SIL_DMA_ERROR = (1 << 17), /* PCI bus error */ SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */ SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */ SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */ SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */ SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */ /* SIEN */ SIL_SIEN_N = (1 << 16), /* triggered by SError.N */ /* * Others */ SIL_QUIRK_MOD15WRITE = (1 << 0), SIL_QUIRK_UDMA5MAX = (1 << 1),};static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);#ifdef CONFIG_PMstatic int sil_pci_device_resume(struct pci_dev *pdev);#endifstatic void sil_dev_config(struct ata_device *dev);static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);static void sil_freeze(struct ata_port *ap);static void sil_thaw(struct ata_port *ap);static const struct pci_device_id sil_pci_tbl[] = { { PCI_VDEVICE(CMD, 0x3112), sil_3112 }, { PCI_VDEVICE(CMD, 0x0240), sil_3112 }, { PCI_VDEVICE(CMD, 0x3512), sil_3512 }, { PCI_VDEVICE(CMD, 0x3114), sil_3114 }, { PCI_VDEVICE(ATI, 0x436e), sil_3112 }, { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq }, { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq }, { } /* terminate list */};/* TODO firmware versions should be added - eric */static const struct sil_drivelist { const char *product; unsigned int quirk;} sil_blacklist [] = { { "ST320012AS", SIL_QUIRK_MOD15WRITE }, { "ST330013AS", SIL_QUIRK_MOD15WRITE }, { "ST340017AS", SIL_QUIRK_MOD15WRITE }, { "ST360015AS", SIL_QUIRK_MOD15WRITE }, { "ST380023AS", SIL_QUIRK_MOD15WRITE }, { "ST3120023AS", SIL_QUIRK_MOD15WRITE }, { "ST340014ASL", SIL_QUIRK_MOD15WRITE }, { "ST360014ASL", SIL_QUIRK_MOD15WRITE }, { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, { }};static struct pci_driver sil_pci_driver = { .name = DRV_NAME, .id_table = sil_pci_tbl, .probe = sil_init_one, .remove = ata_pci_remove_one,#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = sil_pci_device_resume,#endif};static struct scsi_host_template sil_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 = LIBATA_MAX_PRD, .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, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param,};static const struct ata_port_operations sil_ops = { .dev_config = sil_dev_config, .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, .set_mode = sil_set_mode, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, .freeze = sil_freeze, .thaw = sil_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, .scr_read = sil_scr_read, .scr_write = sil_scr_write, .port_start = ata_port_start,};static const struct ata_port_info sil_port_info[] = { /* sil_3112 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, .port_ops = &sil_ops, }, /* sil_3112_no_sata_irq */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | SIL_FLAG_NO_SATA_IRQ, .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, .port_ops = &sil_ops, }, /* sil_3512 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, .port_ops = &sil_ops, }, /* sil_3114 */ { .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, .link_flags = SIL_DFL_LINK_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA5, .port_ops = &sil_ops, },};/* per-port register offsets *//* TODO: we can probably calculate rather than use a table */static const struct { unsigned long tf; /* ATA taskfile register block */ unsigned long ctl; /* ATA control/altstatus register block */ unsigned long bmdma; /* DMA register block */ unsigned long bmdma2; /* DMA register block #2 */ unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */ unsigned long scr; /* SATA control register block */ unsigned long sien; /* SATA Interrupt Enable register */ unsigned long xfer_mode;/* data transfer mode register */ unsigned long sfis_cfg; /* SATA FIS reception config register */} sil_port[] = { /* port 0 ... */ /* tf ctl bmdma bmdma2 fifo scr sien mode sfis */ { 0x80, 0x8A, 0x0, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c }, { 0xC0, 0xCA, 0x8, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc }, { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c }, { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc }, /* ... port 3 */};MODULE_AUTHOR("Jeff Garzik");MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(pci, sil_pci_tbl);MODULE_VERSION(DRV_VERSION);static int slow_down;module_param(slow_down, int, 0444);MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");static unsigned char sil_get_device_cache_line(struct pci_dev *pdev){ u8 cache_line = 0; pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line); return cache_line;}/** * sil_set_mode - wrap set_mode functions * @link: link to set up * @r_failed: returned device when we fail * * Wrap the libata method for device setup as after the setup we need * to inspect the results and do some configuration work */static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed){ struct ata_port *ap = link->ap; void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; struct ata_device *dev; u32 tmp, dev_mode[2] = { }; int rc; rc = ata_do_set_mode(link, r_failed); if (rc) return rc; ata_link_for_each_dev(dev, link) { if (!ata_dev_enabled(dev)) dev_mode[dev->devno] = 0; /* PIO0/1/2 */ else if (dev->flags & ATA_DFLAG_PIO) dev_mode[dev->devno] = 1; /* PIO3/4 */ else dev_mode[dev->devno] = 3; /* UDMA */ /* value 2 indicates MDMA */ } tmp = readl(addr); tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0)); tmp |= dev_mode[0]; tmp |= (dev_mode[1] << 4); writel(tmp, addr); readl(addr); /* flush */ return 0;}static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg){ void __iomem *offset = ap->ioaddr.scr_addr; switch (sc_reg) { case SCR_STATUS: return offset + 4; case SCR_ERROR: return offset + 8; case SCR_CONTROL: return offset; default: /* do nothing */ break; } return NULL;}static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val){ void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) { *val = readl(mmio); return 0; } return -EINVAL;}static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val){ void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -