/* XXX Need to check/dispatch until queue empty */ if (isr & RIO_MSG_ISR_DIQI) { /* * Can receive messages for any mailbox/letter to that * mailbox destination. So, make the callback with an * unknown/invalid mailbox number argument.
*/ if (port->inb_msg[0].mcback != NULL)
port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id,
-1,
-1);
/* Ack the queueing interrupt */
out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI);
}
out: return IRQ_HANDLED;
}
/** * fsl_rio_dbell_handler - MPC85xx doorbell interrupt handler * @irq: Linux interrupt number * @dev_instance: Pointer to interrupt-specific data * * Handles doorbell interrupts. Parses a list of registered * doorbell event handlers and executes a matching event handler.
*/ static irqreturn_t
fsl_rio_dbell_handler(int irq, void *dev_instance)
{ int dsr; struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance; int i;
/* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { struct rio_dbell_msg *dmsg =
fsl_dbell->dbell_ring.virt +
(in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0;
pr_debug
("RIO: processing doorbell," " sid %2.2x tid %2.2x info %4.4x\n",
dmsg->sid, dmsg->tid, dmsg->info);
for (i = 0; i < MAX_PORT_NUM; i++) { if (fsl_dbell->mport[i]) {
list_for_each_entry(dbell,
&fsl_dbell->mport[i]->dbells, node) { if ((dbell->res->start
<= dmsg->info)
&& (dbell->res->end
>= dmsg->info)) {
found = 1; break;
}
} if (found && dbell->dinb) {
dbell->dinb(fsl_dbell->mport[i],
dbell->dev_id, dmsg->sid,
dmsg->tid,
dmsg->info); break;
}
}
}
if (!found) {
pr_debug
("RIO: spurious doorbell," " sid %2.2x tid %2.2x info %4.4x\n",
dmsg->sid, dmsg->tid,
dmsg->info);
}
setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI);
out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI);
}
out: return IRQ_HANDLED;
}
staticvoid msg_unit_error_handler(void)
{
/*XXX: Error recovery is not implemented, we just clear errors */
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
staticvoid fsl_pw_dpc(struct work_struct *work)
{ struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work); union rio_pw_msg msg_buffer; int i;
/* * Process port-write messages
*/ while (kfifo_out_spinlocked(&pw->pw_fifo, (unsignedchar *)&msg_buffer,
RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) { #ifdef DEBUG_PW
{
u32 i;
pr_debug("%s : Port-Write Message:", __func__); for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) { if ((i%4) == 0)
pr_debug("\n0x%02x: 0x%08x", i*4,
msg_buffer.raw[i]); else
pr_debug(" 0x%08x", msg_buffer.raw[i]);
}
pr_debug("\n");
} #endif /* Pass the port-write message to RIO core for processing */ for (i = 0; i < MAX_PORT_NUM; i++) { if (pw->mport[i])
rio_inb_pwrite_handler(pw->mport[i],
&msg_buffer);
}
}
}
/** * fsl_rio_pw_enable - enable/disable port-write interface init * @mport: Master port implementing the port write unit * @enable: 1=enable; 0=disable port-write message handling
*/ int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
{
u32 rval;
rval = in_be32(&pw->pw_regs->pwmr);
if (enable)
rval |= RIO_IPWMR_PWE; else
rval &= ~RIO_IPWMR_PWE;
out_be32(&pw->pw_regs->pwmr, rval);
return 0;
}
/** * fsl_rio_port_write_init - MPC85xx port write interface init * @mport: Master port implementing the port write unit * * Initializes port write unit hardware and DMA buffer * ring. Called from fsl_rio_setup(). Returns %0 on success * or %-ENOMEM on failure.
*/
int fsl_rio_port_write_init(struct fsl_rio_pw *pw)
{ int rc = 0;
/* Following configurations require a disabled port write controller */
out_be32(&pw->pw_regs->pwmr,
in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE);
/* Initialize port write */
pw->port_write_msg.virt = dma_alloc_coherent(pw->dev,
RIO_PW_MSG_SIZE,
&pw->port_write_msg.phys, GFP_KERNEL); if (!pw->port_write_msg.virt) {
pr_err("RIO: unable allocate port write queue\n"); return -ENOMEM;
}
/** * fsl_rio_doorbell_send - Send a MPC85xx doorbell message * @mport: RapidIO master port info * @index: ID of RapidIO interface * @destid: Destination ID of target device * @data: 16-bit info field of RapidIO doorbell message * * Sends a MPC85xx doorbell message. Returns %0 on success or * %-EINVAL on failure.
*/ int fsl_rio_doorbell_send(struct rio_mport *mport, int index, u16 destid, u16 data)
{ unsignedlong flags;
pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n",
index, destid, data);
spin_lock_irqsave(&fsl_rio_doorbell_lock, flags);
/* In the serial version silicons, such as MPC8548, MPC8641, * below operations is must be.
*/
out_be32(&dbell->dbell_regs->odmr, 0x00000000);
out_be32(&dbell->dbell_regs->odretcr, 0x00000004);
out_be32(&dbell->dbell_regs->oddpr, destid << 16);
out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data);
out_be32(&dbell->dbell_regs->odmr, 0x00000001);
/* Go to next descriptor */ if (++rmu->msg_tx_ring.tx_slot == rmu->msg_tx_ring.size)
rmu->msg_tx_ring.tx_slot = 0;
out: return ret;
}
/** * fsl_open_outb_mbox - Initialize MPC85xx outbound mailbox * @mport: Master port implementing the outbound message unit * @dev_id: Device specific pointer to pass on event * @mbox: Mailbox to open * @entries: Number of entries in the outbound mailbox ring * * Initializes buffer ring, request the outbound message interrupt, * and enables the outbound message unit. Returns %0 on success and * %-EINVAL or %-ENOMEM on failure.
*/ int
fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{ int i, j, rc = 0; struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
/* Point dequeue/enqueue pointers at first entry in ring */
out_be32(&rmu->msg_regs->odqdpar, rmu->msg_tx_ring.phys);
out_be32(&rmu->msg_regs->odqepar, rmu->msg_tx_ring.phys);
/* Configure for snooping */
out_be32(&rmu->msg_regs->osar, 0x00000004);
/* Clear interrupt status */
out_be32(&rmu->msg_regs->osr, 0x000000b3);
out_dma: for (i = 0; i < rmu->msg_tx_ring.size; i++)
dma_free_coherent(priv->dev, RIO_MSG_BUFFER_SIZE,
rmu->msg_tx_ring.virt_buffer[i],
rmu->msg_tx_ring.phys_buffer[i]);
return rc;
}
/** * fsl_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 fsl_close_outb_mbox(struct rio_mport *mport, int mbox)
{ struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
/* Disable inbound message unit */
out_be32(&rmu->msg_regs->omr, 0);
/* Free ring */
dma_free_coherent(priv->dev,
rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE,
rmu->msg_tx_ring.virt, rmu->msg_tx_ring.phys);
/** * fsl_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
fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
{ int i, rc = 0; struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
/* Point dequeue/enqueue pointers at first entry in ring */
out_be32(&rmu->msg_regs->ifqdpar, (u32) rmu->msg_rx_ring.phys);
out_be32(&rmu->msg_regs->ifqepar, (u32) rmu->msg_rx_ring.phys);
/* Clear interrupt status */
out_be32(&rmu->msg_regs->isr, 0x00000091);
/* Set number of queue entries */
setbits32(&rmu->msg_regs->imr, (get_bitmask_order(entries) - 2) << 12);
/* Now enable the unit */
setbits32(&rmu->msg_regs->imr, 0x1);
out: return rc;
}
/** * fsl_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 fsl_close_inb_mbox(struct rio_mport *mport, int mbox)
{ struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
/* Disable inbound message unit */
out_be32(&rmu->msg_regs->imr, 0);
/* Free ring */
dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE,
rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys);
/** * fsl_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 fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
{ int rc = 0; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
rmu->msg_rx_ring.virt_buffer[rmu->msg_rx_ring.rx_slot] = buf; if (++rmu->msg_rx_ring.rx_slot == rmu->msg_rx_ring.size)
rmu->msg_rx_ring.rx_slot = 0;
out: return rc;
}
/** * fsl_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 *fsl_get_inb_message(struct rio_mport *mport, int mbox)
{ struct fsl_rmu *rmu = GET_RMM_HANDLE(mport);
u32 phys_buf; void *virt_buf; void *buf = NULL; int buf_idx;
phys_buf = in_be32(&rmu->msg_regs->ifqdpar);
/* If no more messages, then bail out */ if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) goto out2;
/** * fsl_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 fsl_rio_setup(). Returns %0 on success * or %-ENOMEM on failure.
*/ int fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell)
{ int rc = 0;
/* Point dequeue/enqueue pointers at first entry in ring */
out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys);
out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys);
/* Clear interrupt status */
out_be32(&dbell->dbell_regs->dsr, 0x00000091);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.