sgiioc4.c
来自「linux 内核源代码」· C语言 代码 · 共 743 行 · 第 1/2 页
C
743 行
printk(KERN_ERR "%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n", __FUNCTION__, hwif->name, dma_base, dma_base + num_ports - 1); goto dma_remap_failure; } hwif->dma_base = (unsigned long) virt_dma_base; hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, &hwif->dmatable_dma); if (!hwif->dmatable_cpu) goto dma_pci_alloc_failure; hwif->sg_max_nents = IOC4_PRD_ENTRIES; pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE, (dma_addr_t *) &(hwif->dma_status)); if (pad) { ide_set_hwifdata(hwif, pad); return 0; } pci_free_consistent(hwif->pci_dev, IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, hwif->dmatable_cpu, hwif->dmatable_dma); printk(KERN_INFO "%s() -- Error! Unable to allocate DMA Maps for drive %s\n", __FUNCTION__, hwif->name); printk(KERN_INFO "Changing from DMA to PIO mode for Drive %s\n", hwif->name);dma_pci_alloc_failure: iounmap(virt_dma_base);dma_remap_failure: release_mem_region(dma_base, num_ports); return -1;}/* Initializes the IOC4 DMA Engine */static voidsgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive){ u32 ioc4_dma; ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 dma_addr, ending_dma_addr; ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { printk(KERN_WARNING "%s(%s):Warning!! DMA from previous transfer was still active\n", __FUNCTION__, drive->name); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) printk(KERN_ERR "%s(%s) : IOC4 Dma STOP bit is still 1\n", __FUNCTION__, drive->name); } ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { printk(KERN_WARNING "%s(%s) : Warning!! - DMA Error during Previous" " transfer | status 0x%x\n", __FUNCTION__, drive->name, ioc4_dma); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) printk(KERN_ERR "%s(%s) : IOC4 DMA STOP bit is still 1\n", __FUNCTION__, drive->name); } /* Address of the Scatter Gather List */ dma_addr = cpu_to_le32(hwif->dmatable_dma); writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->dma_status); writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); writel(dma_direction, (void __iomem *)ioc4_dma_addr); drive->waiting_for_dma = 1;}/* IOC4 Scatter Gather list Format *//* 128 Bit entries to support 64 bit addresses in the future *//* The Scatter Gather list Entry should be in the BIG-ENDIAN Format *//* --------------------------------------------------------------------- *//* | Upper 32 bits - Zero | Lower 32 bits- address | *//* --------------------------------------------------------------------- *//* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| *//* --------------------------------------------------------------------- *//* Creates the scatter gather list, DMA Table */static unsigned intsgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir){ ide_hwif_t *hwif = HWIF(drive); unsigned int *table = hwif->dmatable_cpu; unsigned int count = 0, i = 1; struct scatterlist *sg; hwif->sg_nents = i = ide_build_sglist(drive, rq); if (!i) return 0; /* sglist of length Zero */ sg = hwif->sg_table; while (i && sg_dma_len(sg)) { dma_addr_t cur_addr; int cur_len; cur_addr = sg_dma_address(sg); cur_len = sg_dma_len(sg); while (cur_len) { if (count++ >= IOC4_PRD_ENTRIES) { printk(KERN_WARNING "%s: DMA table too small\n", drive->name); goto use_pio_instead; } else { u32 bcount = 0x10000 - (cur_addr & 0xffff); if (bcount > cur_len) bcount = cur_len; /* put the addr, length in * the IOC4 dma-table format */ *table = 0x0; table++; *table = cpu_to_be32(cur_addr); table++; *table = 0x0; table++; *table = cpu_to_be32(bcount); table++; cur_addr += bcount; cur_len -= bcount; } } sg = sg_next(sg); i--; } if (count) { table--; *table |= cpu_to_be32(0x80000000); return count; }use_pio_instead: pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, hwif->sg_dma_direction); return 0; /* revert to PIO for this request */}static int sgiioc4_ide_dma_setup(ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; unsigned int count = 0; int ddir; if (rq_data_dir(rq)) ddir = PCI_DMA_TODEVICE; else ddir = PCI_DMA_FROMDEVICE; if (!(count = sgiioc4_build_dma_table(drive, rq, ddir))) { /* try PIO instead of DMA */ ide_map_sg(drive, rq); return 1; } if (rq_data_dir(rq)) /* Writes TO the IOC4 FROM Main Memory */ ddir = IOC4_DMA_READ; else /* Writes FROM the IOC4 TO Main Memory */ ddir = IOC4_DMA_WRITE; sgiioc4_configure_for_dma(ddir, drive); return 0;}static void __devinitide_init_sgiioc4(ide_hwif_t * hwif){ hwif->mmio = 1; hwif->pio_mask = 0x00; hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */ hwif->set_dma_mode = &sgiioc4_set_dma_mode; hwif->selectproc = NULL;/* Use the default routine to select drive */ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine, clear interrupts */ hwif->intrproc = NULL; /* Enable or Disable interrupt from drive */ hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */ hwif->quirkproc = NULL; hwif->busproc = NULL; hwif->INB = &sgiioc4_INB; if (hwif->dma_base == 0) return; hwif->mwdma_mask = ATA_MWDMA2_ONLY; hwif->dma_setup = &sgiioc4_ide_dma_setup; hwif->dma_start = &sgiioc4_ide_dma_start; hwif->ide_dma_end = &sgiioc4_ide_dma_end; hwif->ide_dma_on = &sgiioc4_ide_dma_on; hwif->dma_off_quietly = &sgiioc4_dma_off_quietly; hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq; hwif->dma_host_on = &sgiioc4_dma_host_on; hwif->dma_host_off = &sgiioc4_dma_host_off; hwif->dma_lost_irq = &sgiioc4_dma_lost_irq; hwif->dma_timeout = &ide_dma_timeout;}static int __devinitsgiioc4_ide_setup_pci_device(struct pci_dev *dev){ unsigned long cmd_base, dma_base, irqport; unsigned long bar0, cmd_phys_base, ctl; void __iomem *virt_base; ide_hwif_t *hwif; int h; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; /* * Find an empty HWIF; if none available, return -ENOMEM. */ for (h = 0; h < MAX_HWIFS; ++h) { hwif = &ide_hwifs[h]; if (hwif->chipset == ide_unknown) break; } if (h == MAX_HWIFS) { printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", DRV_NAME); return -ENOMEM; } /* Get the CmdBlk and CtrlBlk Base Registers */ bar0 = pci_resource_start(dev, 0); virt_base = ioremap(bar0, pci_resource_len(dev, 0)); if (virt_base == NULL) { printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", DRV_NAME, bar0); return -ENOMEM; } cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET; irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET; dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; cmd_phys_base = bar0 + IOC4_CMD_OFFSET; if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, hwif->name)) { printk(KERN_ERR "%s : %s -- ERROR, Addresses " "0x%p to 0x%p ALREADY in use\n", __FUNCTION__, hwif->name, (void *) cmd_phys_base, (void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE); return -ENOMEM; } if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) { hw_regs_t hw; /* Initialize the IO registers */ memset(&hw, 0, sizeof(hw)); sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; } hwif->irq = dev->irq; hwif->chipset = ide_pci; hwif->pci_dev = dev; hwif->channel = 0; /* Single Channel chip */ hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */ /* The IOC4 uses MMIO rather than Port IO. */ default_hwif_mmiops(hwif); /* Initializing chipset IRQ Registers */ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base)) printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n", hwif->name, DRV_NAME); ide_init_sgiioc4(hwif); idx[0] = hwif->index; if (ide_device_add(idx)) return -EIO; return 0;}static unsigned int __devinitpci_init_sgiioc4(struct pci_dev *dev){ int ret; printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", DRV_NAME, pci_name(dev), dev->revision); if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) { printk(KERN_ERR "Skipping %s IDE controller in slot %s: " "firmware is obsolete - please upgrade to " "revision46 or higher\n", DRV_NAME, pci_name(dev)); ret = -EAGAIN; goto out; } ret = sgiioc4_ide_setup_pci_device(dev);out: return ret;}intioc4_ide_attach_one(struct ioc4_driver_data *idd){ /* PCI-RT does not bring out IDE connection. * Do not attach to this particular IOC4. */ if (idd->idd_variant == IOC4_VARIANT_PCI_RT) return 0; return pci_init_sgiioc4(idd->idd_pdev);}static struct ioc4_submodule ioc4_ide_submodule = { .is_name = "IOC4_ide", .is_owner = THIS_MODULE, .is_probe = ioc4_ide_attach_one,/* .is_remove = ioc4_ide_remove_one, */};static int __init ioc4_ide_init(void){ return ioc4_register_submodule(&ioc4_ide_submodule);}late_initcall(ioc4_ide_init); /* Call only after IDE init is done */MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?