mbcs.c

来自「linux 内核源代码」· C语言 代码 · 共 846 行 · 第 1/2 页

C
846
字号
	struct mbcs_soft *soft = cx_dev->soft;	uint64_t hostAddr;	int rv = 0;	hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));	if (hostAddr == 0)		return -ENOMEM;	if (copy_from_user((void *)hostAddr, buf, len)) {		rv = -EFAULT;		goto exit;	}	rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off);      exit:	free_pages(hostAddr, get_order(len));	return rv;}static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence){	loff_t newpos;	switch (whence) {	case SEEK_SET:		newpos = off;		break;	case SEEK_CUR:		newpos = filp->f_pos + off;		break;	case SEEK_END:		newpos = MBCS_SRAM_SIZE + off;		break;	default:		/* can't happen */		return -EINVAL;	}	if (newpos < 0)		return -EINVAL;	filp->f_pos = newpos;	return newpos;}static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset){	uint64_t mmr_base;	mmr_base = (uint64_t) (soft->mmr_base + offset);	return mmr_base;}static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft){	soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START);}static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft){	soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);}static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma){	struct cx_dev *cx_dev = fp->private_data;	struct mbcs_soft *soft = cx_dev->soft;	if (vma->vm_pgoff != 0)		return -EINVAL;	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */	if (remap_pfn_range(vma,			    vma->vm_start,			    __pa(soft->gscr_addr) >> PAGE_SHIFT,			    PAGE_SIZE,			    vma->vm_page_prot))		return -EAGAIN;	return 0;}/** * mbcs_completion_intr_handler - Primary completion handler. * @irq: irq * @arg: soft struct for device * */static irqreturn_tmbcs_completion_intr_handler(int irq, void *arg){	struct mbcs_soft *soft = (struct mbcs_soft *)arg;	void *mmr_base;	union cm_status cm_status;	union cm_control cm_control;	mmr_base = soft->mmr_base;	cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS);	if (cm_status.rd_dma_done) {		/* stop dma-read engine, clear status */		cm_control.cm_control_reg =		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);		cm_control.rd_dma_clr = 1;		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,			     cm_control.cm_control_reg);		atomic_set(&soft->dmaread_done, 1);		wake_up(&soft->dmaread_queue);	}	if (cm_status.wr_dma_done) {		/* stop dma-write engine, clear status */		cm_control.cm_control_reg =		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);		cm_control.wr_dma_clr = 1;		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,			     cm_control.cm_control_reg);		atomic_set(&soft->dmawrite_done, 1);		wake_up(&soft->dmawrite_queue);	}	if (cm_status.alg_done) {		/* clear status */		cm_control.cm_control_reg =		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);		cm_control.alg_done_clr = 1;		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,			     cm_control.cm_control_reg);		atomic_set(&soft->algo_done, 1);		wake_up(&soft->algo_queue);	}	return IRQ_HANDLED;}/** * mbcs_intr_alloc - Allocate interrupts. * @dev: device pointer * */static int mbcs_intr_alloc(struct cx_dev *dev){	struct sn_irq_info *sn_irq;	struct mbcs_soft *soft;	struct getdma *getdma;	struct putdma *putdma;	struct algoblock *algo;	soft = dev->soft;	getdma = &soft->getdma;	putdma = &soft->putdma;	algo = &soft->algo;	soft->get_sn_irq = NULL;	soft->put_sn_irq = NULL;	soft->algo_sn_irq = NULL;	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);	if (sn_irq == NULL)		return -EAGAIN;	soft->get_sn_irq = sn_irq;	getdma->intrHostDest = sn_irq->irq_xtalkaddr;	getdma->intrVector = sn_irq->irq_irq;	if (request_irq(sn_irq->irq_irq,			(void *)mbcs_completion_intr_handler, IRQF_SHARED,			"MBCS get intr", (void *)soft)) {		tiocx_irq_free(soft->get_sn_irq);		return -EAGAIN;	}	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);	if (sn_irq == NULL) {		free_irq(soft->get_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->get_sn_irq);		return -EAGAIN;	}	soft->put_sn_irq = sn_irq;	putdma->intrHostDest = sn_irq->irq_xtalkaddr;	putdma->intrVector = sn_irq->irq_irq;	if (request_irq(sn_irq->irq_irq,			(void *)mbcs_completion_intr_handler, IRQF_SHARED,			"MBCS put intr", (void *)soft)) {		tiocx_irq_free(soft->put_sn_irq);		free_irq(soft->get_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->get_sn_irq);		return -EAGAIN;	}	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);	if (sn_irq == NULL) {		free_irq(soft->put_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->put_sn_irq);		free_irq(soft->get_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->get_sn_irq);		return -EAGAIN;	}	soft->algo_sn_irq = sn_irq;	algo->intrHostDest = sn_irq->irq_xtalkaddr;	algo->intrVector = sn_irq->irq_irq;	if (request_irq(sn_irq->irq_irq,			(void *)mbcs_completion_intr_handler, IRQF_SHARED,			"MBCS algo intr", (void *)soft)) {		tiocx_irq_free(soft->algo_sn_irq);		free_irq(soft->put_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->put_sn_irq);		free_irq(soft->get_sn_irq->irq_irq, soft);		tiocx_irq_free(soft->get_sn_irq);		return -EAGAIN;	}	return 0;}/** * mbcs_intr_dealloc - Remove interrupts. * @dev: device pointer * */static void mbcs_intr_dealloc(struct cx_dev *dev){	struct mbcs_soft *soft;	soft = dev->soft;	free_irq(soft->get_sn_irq->irq_irq, soft);	tiocx_irq_free(soft->get_sn_irq);	free_irq(soft->put_sn_irq->irq_irq, soft);	tiocx_irq_free(soft->put_sn_irq);	free_irq(soft->algo_sn_irq->irq_irq, soft);	tiocx_irq_free(soft->algo_sn_irq);}static inline int mbcs_hw_init(struct mbcs_soft *soft){	void *mmr_base = soft->mmr_base;	union cm_control cm_control;	union cm_req_timeout cm_req_timeout;	uint64_t err_stat;	cm_req_timeout.cm_req_timeout_reg =	    MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT);	cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK;	MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT,		     cm_req_timeout.cm_req_timeout_reg);	mbcs_gscr_pioaddr_set(soft);	mbcs_debug_pioaddr_set(soft);	/* clear errors */	err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT);	MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat);	MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1);	/* enable interrupts */	/* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */	MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL);	/* arm status regs and clear engines */	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);	cm_control.rearm_stat_regs = 1;	cm_control.alg_clr = 1;	cm_control.wr_dma_clr = 1;	cm_control.rd_dma_clr = 1;	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);	return 0;}static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf){	struct cx_dev *cx_dev = to_cx_dev(dev);	struct mbcs_soft *soft = cx_dev->soft;	uint64_t debug0;	/*	 * By convention, the first debug register contains the	 * algorithm number and revision.	 */	debug0 = *(uint64_t *) soft->debug_addr;	return sprintf(buf, "0x%lx 0x%lx\n",		       (debug0 >> 32), (debug0 & 0xffffffff));}static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	int n;	struct cx_dev *cx_dev = to_cx_dev(dev);	struct mbcs_soft *soft = cx_dev->soft;	if (count <= 0)		return 0;	n = simple_strtoul(buf, NULL, 0);	if (n == 1) {		mbcs_algo_start(soft);		if (wait_event_interruptible(soft->algo_queue,					atomic_read(&soft->algo_done)))			return -ERESTARTSYS;	}	return count;}DEVICE_ATTR(algo, 0644, show_algo, store_algo);/** * mbcs_probe - Initialize for device * @dev: device pointer * @device_id: id table pointer * */static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id){	struct mbcs_soft *soft;	dev->soft = NULL;	soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);	if (soft == NULL)		return -ENOMEM;	soft->nasid = dev->cx_id.nasid;	list_add(&soft->list, &soft_list);	soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid);	dev->soft = soft;	soft->cxdev = dev;	init_waitqueue_head(&soft->dmawrite_queue);	init_waitqueue_head(&soft->dmaread_queue);	init_waitqueue_head(&soft->algo_queue);	init_MUTEX(&soft->dmawritelock);	init_MUTEX(&soft->dmareadlock);	init_MUTEX(&soft->algolock);	mbcs_getdma_init(&soft->getdma);	mbcs_putdma_init(&soft->putdma);	mbcs_algo_init(&soft->algo);	mbcs_hw_init(soft);	/* Allocate interrupts */	mbcs_intr_alloc(dev);	device_create_file(&dev->dev, &dev_attr_algo);	return 0;}static int mbcs_remove(struct cx_dev *dev){	if (dev->soft) {		mbcs_intr_dealloc(dev);		kfree(dev->soft);	}	device_remove_file(&dev->dev, &dev_attr_algo);	return 0;}static const struct cx_device_id __devinitdata mbcs_id_table[] = {	{	 .part_num = MBCS_PART_NUM,	 .mfg_num = MBCS_MFG_NUM,	 },	{	 .part_num = MBCS_PART_NUM_ALG0,	 .mfg_num = MBCS_MFG_NUM,	 },	{0, 0}};MODULE_DEVICE_TABLE(cx, mbcs_id_table);static struct cx_drv mbcs_driver = {	.name = DEVICE_NAME,	.id_table = mbcs_id_table,	.probe = mbcs_probe,	.remove = mbcs_remove,};static void __exit mbcs_exit(void){	unregister_chrdev(mbcs_major, DEVICE_NAME);	cx_driver_unregister(&mbcs_driver);}static int __init mbcs_init(void){	int rv;	if (!ia64_platform_is("sn2"))		return -ENODEV;	// Put driver into chrdevs[].  Get major number.	rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops);	if (rv < 0) {		DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv);		return rv;	}	mbcs_major = rv;	return cx_driver_register(&mbcs_driver);}module_init(mbcs_init);module_exit(mbcs_exit);MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");MODULE_DESCRIPTION("Driver for MOATB Core Services");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?