aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuah, Kim Tatt <kim.tatt.chuah@intel.com>2016-06-15 01:44:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-25 17:30:42 -0400
commitc6f82787a5a193a5c4c49ddaeb362d320efa5fba (patch)
tree55da1b24d1b63bcb073e11ae49249887e297006e
parentd03516df837587368fc6e75591f6329c072b9eb5 (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>
-rw-r--r--drivers/dma/hsu/hsu.c90
-rw-r--r--drivers/dma/hsu/pci.c11
-rw-r--r--drivers/tty/serial/8250/8250_mid.c22
-rw-r--r--include/linux/dma/hsu.h14
4 files changed, 106 insertions, 31 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
129static 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.
141irqreturn_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 */
146int 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}
189EXPORT_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 */
205irqreturn_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}
187EXPORT_SYMBOL_GPL(hsu_dma_irq); 235EXPORT_SYMBOL_GPL(hsu_dma_do_irq);
188 236
189static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) 237static 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
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
index 86379a79a6a3..b218ff528df7 100644
--- a/drivers/tty/serial/8250/8250_mid.c
+++ b/drivers/tty/serial/8250/8250_mid.c
@@ -97,12 +97,24 @@ static int dnv_handle_irq(struct uart_port *p)
97{ 97{
98 struct mid8250 *mid = p->private_data; 98 struct mid8250 *mid = p->private_data;
99 unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); 99 unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
100 u32 status;
100 int ret = IRQ_NONE; 101 int ret = IRQ_NONE;
101 102 int err;
102 if (fisr & BIT(2)) 103
103 ret |= hsu_dma_irq(&mid->dma_chip, 1); 104 if (fisr & BIT(2)) {
104 if (fisr & BIT(1)) 105 err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
105 ret |= hsu_dma_irq(&mid->dma_chip, 0); 106 if (err > 0)
107 ret |= IRQ_HANDLED;
108 else if (err == 0)
109 ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
110 }
111 if (fisr & BIT(1)) {
112 err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
113 if (err > 0)
114 ret |= IRQ_HANDLED;
115 else if (err == 0)
116 ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
117 }
106 if (fisr & BIT(0)) 118 if (fisr & BIT(0))
107 ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); 119 ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
108 return ret; 120 return ret;
diff --git a/include/linux/dma/hsu.h b/include/linux/dma/hsu.h
index 79df69dc629c..aaff68efba5d 100644
--- a/include/linux/dma/hsu.h
+++ b/include/linux/dma/hsu.h
@@ -39,14 +39,22 @@ struct hsu_dma_chip {
39 39
40#if IS_ENABLED(CONFIG_HSU_DMA) 40#if IS_ENABLED(CONFIG_HSU_DMA)
41/* Export to the internal users */ 41/* Export to the internal users */
42irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); 42int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
43 u32 *status);
44irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
45 u32 status);
43 46
44/* Export to the platform drivers */ 47/* Export to the platform drivers */
45int hsu_dma_probe(struct hsu_dma_chip *chip); 48int hsu_dma_probe(struct hsu_dma_chip *chip);
46int hsu_dma_remove(struct hsu_dma_chip *chip); 49int hsu_dma_remove(struct hsu_dma_chip *chip);
47#else 50#else
48static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, 51static inline int hsu_dma_get_status(struct hsu_dma_chip *chip,
49 unsigned short nr) 52 unsigned short nr, u32 *status)
53{
54 return 0;
55}
56static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip,
57 unsigned short nr, u32 status)
50{ 58{
51 return IRQ_NONE; 59 return IRQ_NONE;
52} 60}