diff options
| author | Chuah, Kim Tatt <kim.tatt.chuah@intel.com> | 2016-06-15 01:44:11 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-25 17:30:42 -0400 |
| commit | c6f82787a5a193a5c4c49ddaeb362d320efa5fba (patch) | |
| tree | 55da1b24d1b63bcb073e11ae49249887e297006e /drivers/dma/hsu | |
| parent | d03516df837587368fc6e75591f6329c072b9eb5 (diff) | |
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: Chuah, Kim Tatt <kim.tatt.chuah@intel.com>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/dma/hsu')
| -rw-r--r-- | drivers/dma/hsu/hsu.c | 90 | ||||
| -rw-r--r-- | drivers/dma/hsu/pci.c | 11 |
2 files changed, 78 insertions, 23 deletions
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f8c5cd53307c..c5f21efd6090 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c | |||
| @@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) | |||
| 126 | hsu_dma_start_channel(hsuc); | 126 | hsu_dma_start_channel(hsuc); |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) | 129 | /* |
| 130 | { | 130 | * hsu_dma_get_status() - get DMA channel status |
| 131 | unsigned long flags; | 131 | * @chip: HSUART DMA chip |
| 132 | u32 sr; | 132 | * @nr: DMA channel number |
| 133 | 133 | * @status: pointer for DMA Channel Status Register value | |
| 134 | spin_lock_irqsave(&hsuc->vchan.lock, flags); | 134 | * |
| 135 | sr = hsu_chan_readl(hsuc, HSU_CH_SR); | 135 | * Description: |
| 136 | spin_unlock_irqrestore(&hsuc->vchan.lock, flags); | 136 | * The function reads and clears the DMA Channel Status Register, checks |
| 137 | 137 | * if it was a timeout interrupt and returns a corresponding value. | |
| 138 | return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); | 138 | * |
| 139 | } | 139 | * Caller should provide a valid pointer for the DMA Channel Status |
| 140 | 140 | * Register value that will be returned in @status. | |
| 141 | irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) | 141 | * |
| 142 | * Return: | ||
| 143 | * 1 for DMA timeout status, 0 for other DMA status, or error code for | ||
| 144 | * invalid parameters or no interrupt pending. | ||
| 145 | */ | ||
| 146 | int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, | ||
| 147 | u32 *status) | ||
| 142 | { | 148 | { |
| 143 | struct hsu_dma_chan *hsuc; | 149 | struct hsu_dma_chan *hsuc; |
| 144 | struct hsu_dma_desc *desc; | ||
| 145 | unsigned long flags; | 150 | unsigned long flags; |
| 146 | u32 sr; | 151 | u32 sr; |
| 147 | 152 | ||
| 148 | /* Sanity check */ | 153 | /* Sanity check */ |
| 149 | if (nr >= chip->hsu->nr_channels) | 154 | if (nr >= chip->hsu->nr_channels) |
| 150 | return IRQ_NONE; | 155 | return -EINVAL; |
| 151 | 156 | ||
| 152 | hsuc = &chip->hsu->chan[nr]; | 157 | hsuc = &chip->hsu->chan[nr]; |
| 153 | 158 | ||
| @@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) | |||
| 155 | * No matter what situation, need read clear the IRQ status | 160 | * No matter what situation, need read clear the IRQ status |
| 156 | * There is a bug, see Errata 5, HSD 2900918 | 161 | * There is a bug, see Errata 5, HSD 2900918 |
| 157 | */ | 162 | */ |
| 158 | sr = hsu_dma_chan_get_sr(hsuc); | 163 | spin_lock_irqsave(&hsuc->vchan.lock, flags); |
| 164 | sr = hsu_chan_readl(hsuc, HSU_CH_SR); | ||
| 165 | spin_unlock_irqrestore(&hsuc->vchan.lock, flags); | ||
| 166 | |||
| 167 | /* Check if any interrupt is pending */ | ||
| 168 | sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); | ||
| 159 | if (!sr) | 169 | if (!sr) |
| 160 | return IRQ_NONE; | 170 | return -EIO; |
| 161 | 171 | ||
| 162 | /* Timeout IRQ, need wait some time, see Errata 2 */ | 172 | /* Timeout IRQ, need wait some time, see Errata 2 */ |
| 163 | if (sr & HSU_CH_SR_DESCTO_ANY) | 173 | if (sr & HSU_CH_SR_DESCTO_ANY) |
| 164 | udelay(2); | 174 | udelay(2); |
| 165 | 175 | ||
| 176 | /* | ||
| 177 | * At this point, at least one of Descriptor Time Out, Channel Error | ||
| 178 | * or Descriptor Done bits must be set. Clear the Descriptor Time Out | ||
| 179 | * bits and if sr is still non-zero, it must be channel error or | ||
| 180 | * descriptor done which are higher priority than timeout and handled | ||
| 181 | * in hsu_dma_do_irq(). Else, it must be a timeout. | ||
| 182 | */ | ||
| 166 | sr &= ~HSU_CH_SR_DESCTO_ANY; | 183 | sr &= ~HSU_CH_SR_DESCTO_ANY; |
| 167 | if (!sr) | 184 | |
| 168 | return IRQ_HANDLED; | 185 | *status = sr; |
| 186 | |||
| 187 | return sr ? 0 : 1; | ||
| 188 | } | ||
| 189 | EXPORT_SYMBOL_GPL(hsu_dma_get_status); | ||
| 190 | |||
| 191 | /* | ||
| 192 | * hsu_dma_do_irq() - DMA interrupt handler | ||
| 193 | * @chip: HSUART DMA chip | ||
| 194 | * @nr: DMA channel number | ||
| 195 | * @status: Channel Status Register value | ||
| 196 | * | ||
| 197 | * Description: | ||
| 198 | * This function handles Channel Error and Descriptor Done interrupts. | ||
| 199 | * This function should be called after determining that the DMA interrupt | ||
| 200 | * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. | ||
| 201 | * | ||
| 202 | * Return: | ||
| 203 | * IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. | ||
| 204 | */ | ||
| 205 | irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, | ||
| 206 | u32 status) | ||
| 207 | { | ||
| 208 | struct hsu_dma_chan *hsuc; | ||
| 209 | struct hsu_dma_desc *desc; | ||
| 210 | unsigned long flags; | ||
| 211 | |||
| 212 | /* Sanity check */ | ||
| 213 | if (nr >= chip->hsu->nr_channels) | ||
| 214 | return IRQ_NONE; | ||
| 215 | |||
| 216 | hsuc = &chip->hsu->chan[nr]; | ||
| 169 | 217 | ||
| 170 | spin_lock_irqsave(&hsuc->vchan.lock, flags); | 218 | spin_lock_irqsave(&hsuc->vchan.lock, flags); |
| 171 | desc = hsuc->desc; | 219 | desc = hsuc->desc; |
| 172 | if (desc) { | 220 | if (desc) { |
| 173 | if (sr & HSU_CH_SR_CHE) { | 221 | if (status & HSU_CH_SR_CHE) { |
| 174 | desc->status = DMA_ERROR; | 222 | desc->status = DMA_ERROR; |
| 175 | } else if (desc->active < desc->nents) { | 223 | } else if (desc->active < desc->nents) { |
| 176 | hsu_dma_start_channel(hsuc); | 224 | hsu_dma_start_channel(hsuc); |
| @@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) | |||
| 184 | 232 | ||
| 185 | return IRQ_HANDLED; | 233 | return IRQ_HANDLED; |
| 186 | } | 234 | } |
| 187 | EXPORT_SYMBOL_GPL(hsu_dma_irq); | 235 | EXPORT_SYMBOL_GPL(hsu_dma_do_irq); |
| 188 | 236 | ||
| 189 | static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) | 237 | static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) |
| 190 | { | 238 | { |
diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index e2db76bd56d8..9916058531d9 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c | |||
| @@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev) | |||
| 27 | { | 27 | { |
| 28 | struct hsu_dma_chip *chip = dev; | 28 | struct hsu_dma_chip *chip = dev; |
| 29 | u32 dmaisr; | 29 | u32 dmaisr; |
| 30 | u32 status; | ||
| 30 | unsigned short i; | 31 | unsigned short i; |
| 31 | irqreturn_t ret = IRQ_NONE; | 32 | irqreturn_t ret = IRQ_NONE; |
| 33 | int err; | ||
| 32 | 34 | ||
| 33 | dmaisr = readl(chip->regs + HSU_PCI_DMAISR); | 35 | dmaisr = readl(chip->regs + HSU_PCI_DMAISR); |
| 34 | for (i = 0; i < chip->hsu->nr_channels; i++) { | 36 | for (i = 0; i < chip->hsu->nr_channels; i++) { |
| 35 | if (dmaisr & 0x1) | 37 | if (dmaisr & 0x1) { |
| 36 | ret |= hsu_dma_irq(chip, i); | 38 | err = hsu_dma_get_status(chip, i, &status); |
| 39 | if (err > 0) | ||
| 40 | ret |= IRQ_HANDLED; | ||
| 41 | else if (err == 0) | ||
| 42 | ret |= hsu_dma_do_irq(chip, i, status); | ||
| 43 | } | ||
| 37 | dmaisr >>= 1; | 44 | dmaisr >>= 1; |
| 38 | } | 45 | } |
| 39 | 46 | ||
