int pasemi_dma_stop_chan(const struct pasemi_dmachan *chan) { int reg, retries; u32 sta; if (chan->chan_type == RXCHAN) { reg = PAS_DMA_RXCHAN_CCMDSTA(chan->chno); pasemi_write_dma_reg(reg, PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { sta = pasemi_read_dma_reg(reg); if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) { pasemi_write_dma_reg(reg, 0); return 1; } cond_resched(); } } else { reg = PAS_DMA_TXCHAN_TCMDSTA(chan->chno); pasemi_write_dma_reg(reg, PAS_DMA_TXCHAN_TCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { sta = pasemi_read_dma_reg(reg); if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) { pasemi_write_dma_reg(reg, 0); return 1; } cond_resched(); } } return 0; }
/* pasemi_dma_start_chan - Start a DMA channel * @chan: Channel to start * @cmdsta: Additional CCMDSTA/TCMDSTA bits to write * * Enables (starts) a DMA channel with optional additional arguments. */ void pasemi_dma_start_chan(const struct pasemi_dmachan *chan, const u32 cmdsta) { if (chan->chan_type == RXCHAN) pasemi_write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(chan->chno), cmdsta | PAS_DMA_RXCHAN_CCMDSTA_EN); else pasemi_write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(chan->chno), cmdsta | PAS_DMA_TXCHAN_TCMDSTA_EN); }
static void pasemi_free_tx_resources(struct pasemi_softc *sc, int chan) { struct pasemi_fnu_txring *ring = &sc->tx[chan]; int chan_index = chan + sc->base_chan; int retries; u32 stat; /* Stop the channel */ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_TCMDSTA(chan_index), PAS_DMA_TXCHAN_TCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { stat = in_le32(sc->dma_regs + PAS_DMA_TXCHAN_TCMDSTA(chan_index)); if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); } if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) dev_err(&sc->dma_pdev->dev, "Failed to stop tx channel %d\n", chan_index); /* Disable the channel */ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_TCMDSTA(chan_index), 0); if (ring->desc_info) kfree((void *) ring->desc_info); if (ring->desc) dma_free_coherent(&sc->dma_pdev->dev, TX_RING_SIZE * 2 * sizeof(u64), (void *) ring->desc, ring->dma); if (ring->irq != -1) free_irq(ring->irq, sc); del_timer(&ring->crypto_timer); }
static int pasemi_dma_setup_tx_resources(struct pasemi_softc *sc, int chan) { u32 val; int chan_index = chan + sc->base_chan; int ret; struct pasemi_fnu_txring *ring; ring = &sc->tx[chan]; spin_lock_init(&ring->fill_lock); spin_lock_init(&ring->clean_lock); ring->desc_info = kzalloc(sizeof(struct pasemi_desc_info) * TX_RING_SIZE, GFP_KERNEL); if (!ring->desc_info) return -ENOMEM; /* Allocate descriptors */ ring->desc = dma_alloc_coherent(&sc->dma_pdev->dev, TX_RING_SIZE * 2 * sizeof(u64), &ring->dma, GFP_KERNEL); if (!ring->desc) return -ENOMEM; memset((void *) ring->desc, 0, TX_RING_SIZE * 2 * sizeof(u64)); out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_RESET(chan_index), 0x30); ring->total_pktcnt = 0; out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEL(chan_index), PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2); out_le32(sc->dma_regs + PAS_DMA_TXCHAN_BASEU(chan_index), val); out_le32(sc->dma_regs + PAS_DMA_TXCHAN_CFG(chan_index), PAS_DMA_TXCHAN_CFG_TY_FUNC | PAS_DMA_TXCHAN_CFG_TATTR(chan) | PAS_DMA_TXCHAN_CFG_WT(2)); /* enable tx channel */ out_le32(sc->dma_regs + PAS_DMA_TXCHAN_TCMDSTA(chan_index), PAS_DMA_TXCHAN_TCMDSTA_EN); out_le32(sc->iob_regs + PAS_IOB_DMA_TXCH_CFG(chan_index), PAS_IOB_DMA_TXCH_CFG_CNTTH(1000)); ring->next_to_fill = 0; ring->next_to_clean = 0; snprintf(ring->irq_name, sizeof(ring->irq_name), "%s%d", "crypto", chan); ring->irq = irq_create_mapping(NULL, sc->base_irq + chan); ret = request_irq(ring->irq, (irq_handler_t) pasemi_intr, IRQF_DISABLED, ring->irq_name, sc); if (ret) { printk(KERN_ERR DRV_NAME ": failed to hook irq %d ret %d\n", ring->irq, ret); ring->irq = -1; return ret; } setup_timer(&ring->crypto_timer, (void *) sweepup_tx, (unsigned long) sc); return 0; }