⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppc85xx_rio.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Set number of entries */	out_be32((void *)&msg_regs->omr,		 in_be32((void *)&msg_regs->omr) |		 ((get_bitmask_order(entries) - 2) << 12));	/* Now enable the unit */	out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1);      out:	return rc;      out_irq:	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,			  msg_tx_ring.virt, msg_tx_ring.phys);      out_dma:	for (i = 0; i < msg_tx_ring.size; i++)		dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,				  msg_tx_ring.virt_buffer[i],				  msg_tx_ring.phys_buffer[i]);	return rc;}/** * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox * @mport: Master port implementing the outbound message unit * @mbox: Mailbox to close * * Disables the outbound message unit, free all buffers, and * frees the outbound message interrupt. */void rio_close_outb_mbox(struct rio_mport *mport, int mbox){	/* Disable inbound message unit */	out_be32((void *)&msg_regs->omr, 0);	/* Free ring */	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,			  msg_tx_ring.virt, msg_tx_ring.phys);	/* Free interrupt */	free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);}/** * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data * @regs: Register context * * Handles inbound message interrupts. Executes a registered inbound * mailbox event handler and acks the interrupt occurence. */static irqreturn_tmpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs){	int isr;	struct rio_mport *port = (struct rio_mport *)dev_instance;	isr = in_be32((void *)&msg_regs->isr);	if (isr & RIO_MSG_ISR_TE) {		pr_info("RIO: inbound message reception error\n");		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);		goto out;	}	/* XXX Need to check/dispatch until queue empty */	if (isr & RIO_MSG_ISR_DIQI) {		/*		 * We implement *only* mailbox 0, but can receive messages		 * for any mailbox/letter to that mailbox destination. So,		 * make the callback with an unknown/invalid mailbox number		 * argument.		 */		port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1);		/* Ack the queueing interrupt */		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);	}      out:	return IRQ_HANDLED;}/** * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox * @mport: Master port implementing the inbound message unit * @dev_id: Device specific pointer to pass on event * @mbox: Mailbox to open * @entries: Number of entries in the inbound mailbox ring * * Initializes buffer ring, request the inbound message interrupt, * and enables the inbound message unit. Returns %0 on success * and %-EINVAL or %-ENOMEM on failure. */int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries){	int i, rc = 0;	if ((entries < RIO_MIN_RX_RING_SIZE) ||	    (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {		rc = -EINVAL;		goto out;	}	/* Initialize client buffer ring */	msg_rx_ring.dev_id = dev_id;	msg_rx_ring.size = entries;	msg_rx_ring.rx_slot = 0;	for (i = 0; i < msg_rx_ring.size; i++)		msg_rx_ring.virt_buffer[i] = NULL;	/* Initialize inbound message ring */	if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL,						    msg_rx_ring.size *						    RIO_MAX_MSG_SIZE,						    &msg_rx_ring.phys,						    GFP_KERNEL))) {		rc = -ENOMEM;		goto out;	}	/* Point dequeue/enqueue pointers at first entry in ring */	out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);	out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);	/* Clear interrupt status */	out_be32((void *)&msg_regs->isr, 0x00000091);	/* Hook up inbound message handler */	if ((rc =	     request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0,			 "msg_rx", (void *)mport)) < 0) {		dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,				  msg_tx_ring.virt_buffer[i],				  msg_tx_ring.phys_buffer[i]);		goto out;	}	/*	 * Configure inbound message unit:	 *      Snooping	 *      4KB max message size	 *      Unmask all interrupt sources	 *      Disable	 */	out_be32((void *)&msg_regs->imr, 0x001b0060);	/* Set number of queue entries */	out_be32((void *)&msg_regs->imr,		 in_be32((void *)&msg_regs->imr) |		 ((get_bitmask_order(entries) - 2) << 12));	/* Now enable the unit */	out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1);      out:	return rc;}/** * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox * @mport: Master port implementing the inbound message unit * @mbox: Mailbox to close * * Disables the inbound message unit, free all buffers, and * frees the inbound message interrupt. */void rio_close_inb_mbox(struct rio_mport *mport, int mbox){	/* Disable inbound message unit */	out_be32((void *)&msg_regs->imr, 0);	/* Free ring */	dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,			  msg_rx_ring.virt, msg_rx_ring.phys);	/* Free interrupt */	free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);}/** * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue * @mport: Master port implementing the inbound message unit * @mbox: Inbound mailbox number * @buf: Buffer to add to inbound queue * * Adds the @buf buffer to the MPC85xx inbound message queue. Returns * %0 on success or %-EINVAL on failure. */int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf){	int rc = 0;	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",		 msg_rx_ring.rx_slot);	if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {		printk(KERN_ERR		       "RIO: error adding inbound buffer %d, buffer exists\n",		       msg_rx_ring.rx_slot);		rc = -EINVAL;		goto out;	}	msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf;	if (++msg_rx_ring.rx_slot == msg_rx_ring.size)		msg_rx_ring.rx_slot = 0;      out:	return rc;}EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);/** * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit * @mport: Master port implementing the inbound message unit * @mbox: Inbound mailbox number * * Gets the next available inbound message from the inbound message queue. * A pointer to the message is returned on success or NULL on failure. */void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox){	u32 imr;	u32 phys_buf, virt_buf;	void *buf = NULL;	int buf_idx;	phys_buf = in_be32((void *)&msg_regs->ifqdpar);	/* If no more messages, then bail out */	if (phys_buf == in_be32((void *)&msg_regs->ifqepar))		goto out2;	virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);	buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;	buf = msg_rx_ring.virt_buffer[buf_idx];	if (!buf) {		printk(KERN_ERR		       "RIO: inbound message copy failed, no buffers\n");		goto out1;	}	/* Copy max message size, caller is expected to allocate that big */	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);	/* Clear the available buffer */	msg_rx_ring.virt_buffer[buf_idx] = NULL;      out1:	imr = in_be32((void *)&msg_regs->imr);	out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);      out2:	return buf;}EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);/** * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data * @regs: Register context * * Handles doorbell interrupts. Parses a list of registered * doorbell event handlers and executes a matching event handler. */static irqreturn_tmpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs){	int dsr;	struct rio_mport *port = (struct rio_mport *)dev_instance;	dsr = in_be32((void *)&msg_regs->dsr);	if (dsr & DOORBELL_DSR_TE) {		pr_info("RIO: doorbell reception error\n");		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);		goto out;	}	if (dsr & DOORBELL_DSR_QFI) {		pr_info("RIO: doorbell queue full\n");		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);		goto out;	}	/* XXX Need to check/dispatch until queue empty */	if (dsr & DOORBELL_DSR_DIQI) {		u32 dmsg =		    (u32) dbell_ring.virt +		    (in_be32((void *)&msg_regs->dqdpar) & 0xfff);		u32 dmr;		struct rio_dbell *dbell;		int found = 0;		pr_debug		    ("RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",		     DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));		list_for_each_entry(dbell, &port->dbells, node) {			if ((dbell->res->start <= DBELL_INF(dmsg)) &&			    (dbell->res->end >= DBELL_INF(dmsg))) {				found = 1;				break;			}		}		if (found) {			dbell->dinb(port, dbell->dev_id, DBELL_SID(dmsg), DBELL_TID(dmsg),				    DBELL_INF(dmsg));		} else {			pr_debug			    ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",			     DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));		}		dmr = in_be32((void *)&msg_regs->dmr);		out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);	}      out:	return IRQ_HANDLED;}/** * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init * @mport: Master port implementing the inbound doorbell unit * * Initializes doorbell unit hardware and inbound DMA buffer * ring. Called from mpc85xx_rio_setup(). Returns %0 on success * or %-ENOMEM on failure. */static int mpc85xx_rio_doorbell_init(struct rio_mport *mport){	int rc = 0;	/* Map outbound doorbell window immediately after maintenance window */	if (!(dbell_win =	      (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,			    RIO_DBELL_WIN_SIZE))) {		printk(KERN_ERR		       "RIO: unable to map outbound doorbell window\n");		rc = -ENOMEM;		goto out;	}	/* Initialize inbound doorbells */	if (!(dbell_ring.virt = dma_alloc_coherent(NULL,						   512 * DOORBELL_MESSAGE_SIZE,						   &dbell_ring.phys,						   GFP_KERNEL))) {		printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");		rc = -ENOMEM;		iounmap((void *)dbell_win);		goto out;	}	/* Point dequeue/enqueue pointers at first entry in ring */	out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);	out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);	/* Clear interrupt status */	out_be32((void *)&msg_regs->dsr, 0x00000091);	/* Hook up doorbell handler */	if ((rc =	     request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,			 "dbell_rx", (void *)mport) < 0)) {		iounmap((void *)dbell_win);		dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE,				  dbell_ring.virt, dbell_ring.phys);		printk(KERN_ERR		       "MPC85xx RIO: unable to request inbound doorbell irq");		goto out;	}	/* Configure doorbells for snooping, 512 entries, and enable */	out_be32((void *)&msg_regs->dmr, 0x00108161);      out:	return rc;}static char *cmdline = NULL;static int mpc85xx_rio_get_hdid(int index){	/* XXX Need to parse multiple entries in some format */	if (!cmdline)		return -1;	return simple_strtol(cmdline, NULL, 0);}static int mpc85xx_rio_get_cmdline(char *s){	if (!s)		return 0;	cmdline = s;	return 1;}__setup("riohdid=", mpc85xx_rio_get_cmdline);/** * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface * @law_start: Starting physical address of RapidIO LAW * @law_size: Size of RapidIO LAW * * Initializes MPC85xx RapidIO hardware interface, configures * master port with system-specific info, and registers the * master port with the RapidIO subsystem. */void mpc85xx_rio_setup(int law_start, int law_size){	struct rio_ops *ops;	struct rio_mport *port;	ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);	ops->lcread = mpc85xx_local_config_read;	ops->lcwrite = mpc85xx_local_config_write;	ops->cread = mpc85xx_rio_config_read;	ops->cwrite = mpc85xx_rio_config_write;	ops->dsend = mpc85xx_rio_doorbell_send;	port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL);	port->id = 0;	port->index = 0;	INIT_LIST_HEAD(&port->dbells);	port->iores.start = law_start;	port->iores.end = law_start + law_size;	port->iores.flags = IORESOURCE_MEM;	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);	rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);	strcpy(port->name, "RIO0 mport");	port->ops = ops;	port->host_deviceid = mpc85xx_rio_get_hdid(port->id);	rio_register_mport(port);	regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000);	atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET);	maint_atmu_regs = atmu_regs + 1;	dbell_atmu_regs = atmu_regs + 2;	msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);	/* Configure maintenance transaction window */	out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);	out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);	maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);	/* Configure outbound doorbell window */	out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);	out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);	mpc85xx_rio_doorbell_init(port);}

⌨️ 快捷键说明

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