diff options
author | Alek Du <alek.du@intel.com> | 2011-03-30 11:09:54 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-03-30 23:31:48 -0400 |
commit | 2ff271bf6505038d8c937e73438ea3c80c387439 (patch) | |
tree | 082f4462c98661a6b4da3e924cafe20df9cf9218 /drivers/spi | |
parent | 8a33a373e5ffb6040c58ff41ea48ba21d5f8b5e9 (diff) |
spi/dw_spi: change poll mode transfer from byte ops to batch ops
Current poll transfer will read/write one word, then wait till the
hw is non-busy, it's not efficient. This patch will try to read/write
as many words as permitted by hardware FIFO depth.
Signed-off-by: Alek Du <alek.du@intel.com>
Signed-off-by: Feng Tang <feng.tang@intel.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/dw_spi.c | 71 |
1 files changed, 48 insertions, 23 deletions
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d3aaf8db86cc..7a2a72268f0a 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c | |||
@@ -160,6 +160,37 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) | |||
160 | } | 160 | } |
161 | #endif /* CONFIG_DEBUG_FS */ | 161 | #endif /* CONFIG_DEBUG_FS */ |
162 | 162 | ||
163 | /* Return the max entries we can fill into tx fifo */ | ||
164 | static inline u32 tx_max(struct dw_spi *dws) | ||
165 | { | ||
166 | u32 tx_left, tx_room, rxtx_gap; | ||
167 | |||
168 | tx_left = (dws->tx_end - dws->tx) / dws->n_bytes; | ||
169 | tx_room = dws->fifo_len - dw_readw(dws, txflr); | ||
170 | |||
171 | /* | ||
172 | * Another concern is about the tx/rx mismatch, we | ||
173 | * though to use (dws->fifo_len - rxflr - txflr) as | ||
174 | * one maximum value for tx, but it doesn't cover the | ||
175 | * data which is out of tx/rx fifo and inside the | ||
176 | * shift registers. So a control from sw point of | ||
177 | * view is taken. | ||
178 | */ | ||
179 | rxtx_gap = ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx)) | ||
180 | / dws->n_bytes; | ||
181 | |||
182 | return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap)); | ||
183 | } | ||
184 | |||
185 | /* Return the max entries we should read out of rx fifo */ | ||
186 | static inline u32 rx_max(struct dw_spi *dws) | ||
187 | { | ||
188 | u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes; | ||
189 | |||
190 | return min(rx_left, (u32)dw_readw(dws, rxflr)); | ||
191 | } | ||
192 | |||
193 | |||
163 | static void wait_till_not_busy(struct dw_spi *dws) | 194 | static void wait_till_not_busy(struct dw_spi *dws) |
164 | { | 195 | { |
165 | unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); | 196 | unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); |
@@ -175,33 +206,30 @@ static void wait_till_not_busy(struct dw_spi *dws) | |||
175 | 206 | ||
176 | static int dw_writer(struct dw_spi *dws) | 207 | static int dw_writer(struct dw_spi *dws) |
177 | { | 208 | { |
209 | u32 max = tx_max(dws); | ||
178 | u16 txw = 0; | 210 | u16 txw = 0; |
179 | 211 | ||
180 | if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) | 212 | while (max--) { |
181 | || (dws->tx == dws->tx_end)) | 213 | /* Set the tx word if the transfer's original "tx" is not null */ |
182 | return 0; | 214 | if (dws->tx_end - dws->len) { |
183 | 215 | if (dws->n_bytes == 1) | |
184 | /* Set the tx word if the transfer's original "tx" is not null */ | 216 | txw = *(u8 *)(dws->tx); |
185 | if (dws->tx_end - dws->len) { | 217 | else |
186 | if (dws->n_bytes == 1) | 218 | txw = *(u16 *)(dws->tx); |
187 | txw = *(u8 *)(dws->tx); | 219 | } |
188 | else | 220 | dw_writew(dws, dr, txw); |
189 | txw = *(u16 *)(dws->tx); | 221 | dws->tx += dws->n_bytes; |
190 | } | 222 | } |
191 | 223 | ||
192 | dw_writew(dws, dr, txw); | ||
193 | dws->tx += dws->n_bytes; | ||
194 | |||
195 | wait_till_not_busy(dws); | ||
196 | return 1; | 224 | return 1; |
197 | } | 225 | } |
198 | 226 | ||
199 | static int dw_reader(struct dw_spi *dws) | 227 | static int dw_reader(struct dw_spi *dws) |
200 | { | 228 | { |
229 | u32 max = rx_max(dws); | ||
201 | u16 rxw; | 230 | u16 rxw; |
202 | 231 | ||
203 | while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT) | 232 | while (max--) { |
204 | && (dws->rx < dws->rx_end)) { | ||
205 | rxw = dw_readw(dws, dr); | 233 | rxw = dw_readw(dws, dr); |
206 | /* Care rx only if the transfer's original "rx" is not null */ | 234 | /* Care rx only if the transfer's original "rx" is not null */ |
207 | if (dws->rx_end - dws->len) { | 235 | if (dws->rx_end - dws->len) { |
@@ -213,7 +241,6 @@ static int dw_reader(struct dw_spi *dws) | |||
213 | dws->rx += dws->n_bytes; | 241 | dws->rx += dws->n_bytes; |
214 | } | 242 | } |
215 | 243 | ||
216 | wait_till_not_busy(dws); | ||
217 | return dws->rx == dws->rx_end; | 244 | return dws->rx == dws->rx_end; |
218 | } | 245 | } |
219 | 246 | ||
@@ -368,13 +395,11 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id) | |||
368 | /* Must be called inside pump_transfers() */ | 395 | /* Must be called inside pump_transfers() */ |
369 | static void poll_transfer(struct dw_spi *dws) | 396 | static void poll_transfer(struct dw_spi *dws) |
370 | { | 397 | { |
371 | while (dw_writer(dws)) | 398 | do { |
399 | dw_writer(dws); | ||
372 | dw_reader(dws); | 400 | dw_reader(dws); |
373 | /* | 401 | cpu_relax(); |
374 | * There is a possibility that the last word of a transaction | 402 | } while (dws->rx_end > dws->rx); |
375 | * will be lost if data is not ready. Re-read to solve this issue. | ||
376 | */ | ||
377 | dw_reader(dws); | ||
378 | 403 | ||
379 | dw_spi_xfer_done(dws); | 404 | dw_spi_xfer_done(dws); |
380 | } | 405 | } |