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 | |
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>
-rw-r--r-- | drivers/dma/hsu/hsu.c | 90 | ||||
-rw-r--r-- | drivers/dma/hsu/pci.c | 11 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_mid.c | 22 | ||||
-rw-r--r-- | include/linux/dma/hsu.h | 14 |
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 | ||
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 | ||
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 */ |
42 | irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); | 42 | int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, |
43 | u32 *status); | ||
44 | irqreturn_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 */ |
45 | int hsu_dma_probe(struct hsu_dma_chip *chip); | 48 | int hsu_dma_probe(struct hsu_dma_chip *chip); |
46 | int hsu_dma_remove(struct hsu_dma_chip *chip); | 49 | int hsu_dma_remove(struct hsu_dma_chip *chip); |
47 | #else | 50 | #else |
48 | static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, | 51 | static 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 | } | ||
56 | static 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 | } |