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 + -
显示快捷键?