Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6f82787 authored by Chuah, Kim Tatt's avatar Chuah, Kim Tatt Committed by Greg Kroah-Hartman
Browse files

dmaengine: hsu: Export hsu_dma_get_status()



To allow other code to safely read DMA Channel Status Register (where
the register attribute for Channel Error, Descriptor Time Out &
Descriptor Done fields are read-clear), export hsu_dma_get_status().
hsu_dma_irq() is renamed to hsu_dma_do_irq() and requires Status
Register value to be passed in.

Signed-off-by: default avatarChuah, Kim Tatt <kim.tatt.chuah@intel.com>
Acked-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d03516df
Loading
Loading
Loading
Loading
+69 −21
Original line number Diff line number Diff line
@@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc)
	hsu_dma_start_channel(hsuc);
}

static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc)
{
	unsigned long flags;
	u32 sr;

	spin_lock_irqsave(&hsuc->vchan.lock, flags);
	sr = hsu_chan_readl(hsuc, HSU_CH_SR);
	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);

	return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
}

irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
/*
 *      hsu_dma_get_status() - get DMA channel status
 *      @chip: HSUART DMA chip
 *      @nr: DMA channel number
 *      @status: pointer for DMA Channel Status Register value
 *
 *      Description:
 *      The function reads and clears the DMA Channel Status Register, checks
 *      if it was a timeout interrupt and returns a corresponding value.
 *
 *      Caller should provide a valid pointer for the DMA Channel Status
 *      Register value that will be returned in @status.
 *
 *      Return:
 *      1 for DMA timeout status, 0 for other DMA status, or error code for
 *      invalid parameters or no interrupt pending.
 */
int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
		       u32 *status)
{
	struct hsu_dma_chan *hsuc;
	struct hsu_dma_desc *desc;
	unsigned long flags;
	u32 sr;

	/* Sanity check */
	if (nr >= chip->hsu->nr_channels)
		return IRQ_NONE;
		return -EINVAL;

	hsuc = &chip->hsu->chan[nr];

@@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
	 * No matter what situation, need read clear the IRQ status
	 * There is a bug, see Errata 5, HSD 2900918
	 */
	sr = hsu_dma_chan_get_sr(hsuc);
	spin_lock_irqsave(&hsuc->vchan.lock, flags);
	sr = hsu_chan_readl(hsuc, HSU_CH_SR);
	spin_unlock_irqrestore(&hsuc->vchan.lock, flags);

	/* Check if any interrupt is pending */
	sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
	if (!sr)
		return IRQ_NONE;
		return -EIO;

	/* Timeout IRQ, need wait some time, see Errata 2 */
	if (sr & HSU_CH_SR_DESCTO_ANY)
		udelay(2);

	/*
	 * At this point, at least one of Descriptor Time Out, Channel Error
	 * or Descriptor Done bits must be set. Clear the Descriptor Time Out
	 * bits and if sr is still non-zero, it must be channel error or
	 * descriptor done which are higher priority than timeout and handled
	 * in hsu_dma_do_irq(). Else, it must be a timeout.
	 */
	sr &= ~HSU_CH_SR_DESCTO_ANY;
	if (!sr)
		return IRQ_HANDLED;

	*status = sr;

	return sr ? 0 : 1;
}
EXPORT_SYMBOL_GPL(hsu_dma_get_status);

/*
 *      hsu_dma_do_irq() - DMA interrupt handler
 *      @chip: HSUART DMA chip
 *      @nr: DMA channel number
 *      @status: Channel Status Register value
 *
 *      Description:
 *      This function handles Channel Error and Descriptor Done interrupts.
 *      This function should be called after determining that the DMA interrupt
 *      is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0.
 *
 *      Return:
 *      IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise.
 */
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
			   u32 status)
{
	struct hsu_dma_chan *hsuc;
	struct hsu_dma_desc *desc;
	unsigned long flags;

	/* Sanity check */
	if (nr >= chip->hsu->nr_channels)
		return IRQ_NONE;

	hsuc = &chip->hsu->chan[nr];

	spin_lock_irqsave(&hsuc->vchan.lock, flags);
	desc = hsuc->desc;
	if (desc) {
		if (sr & HSU_CH_SR_CHE) {
		if (status & HSU_CH_SR_CHE) {
			desc->status = DMA_ERROR;
		} else if (desc->active < desc->nents) {
			hsu_dma_start_channel(hsuc);
@@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)

	return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(hsu_dma_irq);
EXPORT_SYMBOL_GPL(hsu_dma_do_irq);

static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents)
{
+9 −2
Original line number Diff line number Diff line
@@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
{
	struct hsu_dma_chip *chip = dev;
	u32 dmaisr;
	u32 status;
	unsigned short i;
	irqreturn_t ret = IRQ_NONE;
	int err;

	dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
	for (i = 0; i < chip->hsu->nr_channels; i++) {
		if (dmaisr & 0x1)
			ret |= hsu_dma_irq(chip, i);
		if (dmaisr & 0x1) {
			err = hsu_dma_get_status(chip, i, &status);
			if (err > 0)
				ret |= IRQ_HANDLED;
			else if (err == 0)
				ret |= hsu_dma_do_irq(chip, i, status);
		}
		dmaisr >>= 1;
	}

+17 −5
Original line number Diff line number Diff line
@@ -97,12 +97,24 @@ static int dnv_handle_irq(struct uart_port *p)
{
	struct mid8250 *mid = p->private_data;
	unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
	u32 status;
	int ret = IRQ_NONE;

	if (fisr & BIT(2))
		ret |= hsu_dma_irq(&mid->dma_chip, 1);
	if (fisr & BIT(1))
		ret |= hsu_dma_irq(&mid->dma_chip, 0);
	int err;

	if (fisr & BIT(2)) {
		err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
		if (err > 0)
			ret |= IRQ_HANDLED;
		else if (err == 0)
			ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
	}
	if (fisr & BIT(1)) {
		err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
		if (err > 0)
			ret |= IRQ_HANDLED;
		else if (err == 0)
			ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
	}
	if (fisr & BIT(0))
		ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
	return ret;
+11 −3
Original line number Diff line number Diff line
@@ -39,14 +39,22 @@ struct hsu_dma_chip {

#if IS_ENABLED(CONFIG_HSU_DMA)
/* Export to the internal users */
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr);
int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
		       u32 *status);
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
			   u32 status);

/* Export to the platform drivers */
int hsu_dma_probe(struct hsu_dma_chip *chip);
int hsu_dma_remove(struct hsu_dma_chip *chip);
#else
static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip,
				      unsigned short nr)
static inline int hsu_dma_get_status(struct hsu_dma_chip *chip,
				     unsigned short nr, u32 *status)
{
	return 0;
}
static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip,
					 unsigned short nr, u32 status)
{
	return IRQ_NONE;
}