[PATCH] [POWERPC] 8xx: PQ SoC IRDA support
Samuel Ortiz
samuel at sortiz.org
Wed May 9 18:42:44 EST 2007
Hi Vitaly,
On 5/8/2007, "Vitaly Bordug" <vitb at kernel.crashing.org> wrote:
>
>Adds support of IRDA transceiver residing on PowerQUICC processors and
>enabling such on mpc885ads reference board. The driver is implemented
>using of_device concept, hereby implies arch/powerpc support of the target.
>
>Signed-off-by: Vitaly Bordug <vitb at kernel.crashing.org>
I'd really prefer this patch to be splitted in 2 parts: The PPC specific
bits, and the IrDA driver that would apply on top of it.
Meanwhile, I can comment on the IrDA driver code:
>diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
>index 7c8ccc0..b3681e7 100644
>--- a/drivers/net/irda/Kconfig
>+++ b/drivers/net/irda/Kconfig
>@@ -17,6 +17,10 @@ config IRTTY_SIR
>
> If unsure, say Y.
>
>+config 8XX_SIR
>+ tristate "mpc8xx SIR"
>+ depends on 8xx && IRDA
>+
Some "help" field here wouldn't hurt.
>+static void mpc8xx_irda_rx(struct net_device *dev)
>+{
>+ struct mpc8xx_irda *si = dev->priv;
>+ cbd_t *bdp;
>+ struct sk_buff *skb;
>+ int len;
>+ ushort status;
>+
>+ bdp = si->cur_rx;
>+
>+ for (;;) {
>+ if (bdp->cbd_sc & BD_AHDLC_RX_EMPTY)
>+ break;
>+ status = bdp->cbd_sc;
>+
>+ if (status & BD_AHDLC_RX_STATS) {
>+ /* process errors
>+ */
>+ if (bdp->cbd_sc & BD_AHDLC_RX_AB)
>+ si->stats.rx_length_errors++;
>+ if (bdp->cbd_sc & BD_AHDLC_RX_CR) /* CRC Error */
>+ si->stats.rx_crc_errors++;
>+ if (bdp->cbd_sc & BD_AHDLC_RX_OV) /* FIFO overrun */
>+ si->stats.rx_over_errors++;
>+ } else {
>+ /* Process the incoming frame.
>+ */
>+ len = bdp->cbd_datlen;
>+
>+ skb = dev_alloc_skb(len + 1);
>+ if (skb == NULL) {
>+ printk(KERN_INFO
>+ "%s: Memory squeeze, dropping packet.\n",
>+ dev->name);
>+ si->stats.rx_dropped++;
>+ } else {
>+ skb->dev = dev;
>+ skb_reserve(skb, 1);
>+ memcpy(skb_put(skb, len),
>+ si->rx_vaddr[bdp - si->rx_bd_base], len);
>+ skb_trim(skb, skb->len - 2);
>+
>+ si->stats.rx_packets++;
>+ si->stats.rx_bytes += len;
>+
>+ skb->mac.raw = skb->data;
This should be
+ skb_reset_mac_header(skb);
>+static irqreturn_t mpc8xx_irda_irq(int irq, void *dev_id)
>+{
>+ struct net_device *dev = dev_id;
>+ struct mpc8xx_irda *si = dev->priv;
>+ scc_t *sccp = si->sccp;
>+ cbd_t *bdp;
>+ ushort int_events;
>+ int must_restart = 0;
>+
>+ /* Get the interrupt events that caused us to be here.
>+ */
>+ int_events = in_be16(&sccp->scc_scce);
>+ out_be16(&sccp->scc_scce, int_events);
>+
>+ /* Handle receive event in its own function.
>+ */
>+ if (int_events & SCC_AHDLC_RXF)
>+ mpc8xx_irda_rx(dev);
>+
>+ spin_lock(&si->lock);
>+
>+ /* Transmit OK, or non-fatal error. Update the buffer descriptors.
>+ */
>+ if (int_events & (SCC_AHDLC_TXE | SCC_AHDLC_TXB)) {
>+ bdp = si->dirty_tx;
>+
>+ while ((bdp->cbd_sc & BD_AHDLC_TX_READY) == 0) {
>+ if (si->tx_free == TX_RING_SIZE)
>+ break;
>+
>+ if (bdp->cbd_sc & BD_AHDLC_TX_CTS)
>+ must_restart = 1;
>+
>+ si->stats.tx_packets++;
>+
>+ /* Free the sk buffer associated with this last transmit.
>+ */
>+ dev_kfree_skb_irq(si->tx_skbuff[si->skb_dirty]);
>+ si->skb_dirty = (si->skb_dirty + 1) & TX_RING_MOD_MASK;
>+
>+ /* Update pointer to next buffer descriptor to be transmitted.
>+ */
>+ if (bdp->cbd_sc & BD_AHDLC_TX_WRAP)
>+ bdp = si->tx_bd_base;
>+ else
>+ bdp++;
>+
>+ /* Since we have freed up a buffer, the ring is no longer full.
>+ */
>+ if (!si->tx_free++) {
>+ if (netif_queue_stopped(dev))
>+ netif_wake_queue(dev);
>+ }
>+
>+ si->dirty_tx = (cbd_t *) bdp;
>+
>+ if (si->newspeed) {
>+ mpc8xx_irda_set_speed(dev, si->newspeed);
>+ si->speed = si->newspeed;
>+ si->newspeed = 0;
>+ }
>+ }
>+
>+ if (must_restart) {
>+ cpm8xx_t *cp = immr_map(im_cpm);
>+ printk(KERN_INFO "restart TX\n");
>+
>+ /* Some transmit errors cause the transmitter to shut
>+ * down. We now issue a restart transmit. Since the
>+ * errors close the BD and update the pointers, the restart
>+ * _should_ pick up without having to reset any of our
>+ * pointers either.
>+ */
>+ out_be16(&cp->cp_cpcr,
>+ mk_cr_cmd(CPM_CR_CH_SCC2,
>+ CPM_CR_RESTART_TX) | CPM_CR_FLG);
>+ while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) ;
You're busy looping in an interrupt handler, that's not really nice.
In general, I think this interrupt handler would deserve a bottom half
split since it looks quite busy.
>+static struct device_driver m8xxir_driver = {
>+ .name = "fsl-cpm-scc:irda",
>+ .bus = &platform_bus_type,
>+ .probe = mpc8xx_irda_probe,
>+ .remove = mpc8xx_irda_remove,
>+};
Why not a platform driver ?
Cheers,
Samuel.
More information about the Linuxppc-dev
mailing list