aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2015-12-14 10:20:20 -0500
committerMark Brown <broonie@kernel.org>2016-02-09 14:32:07 -0500
commitd9f1212272818420fcde611a940c1ad611a8b785 (patch)
tree0799bc9b7950503331bfbb384fbda85a427b9eeb
parent523baf5a0609690cb742b3662b7ccac0ea0b2ef2 (diff)
spi: core: add spi_split_transfers_maxsize
Add spi_split_transfers_maxsize method that splits spi_transfers transparently into multiple transfers that are below the given max-size. This makes use of the spi_res framework via spi_replace_transfers to allocate/free the extra transfers as well as reverting back the changes applied while processing the spi_message. Signed-off-by: Martin Sperl <kernel@martin.sperl.org> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi.c111
-rw-r--r--include/linux/spi/spi.h15
2 files changed, 126 insertions, 0 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 2ec8e66a8098..34e3741504f9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -144,6 +144,8 @@ SPI_STATISTICS_TRANSFER_BYTES_HISTO(14, "16384-32767");
144SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535"); 144SPI_STATISTICS_TRANSFER_BYTES_HISTO(15, "32768-65535");
145SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+"); 145SPI_STATISTICS_TRANSFER_BYTES_HISTO(16, "65536+");
146 146
147SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
148
147static struct attribute *spi_dev_attrs[] = { 149static struct attribute *spi_dev_attrs[] = {
148 &dev_attr_modalias.attr, 150 &dev_attr_modalias.attr,
149 NULL, 151 NULL,
@@ -181,6 +183,7 @@ static struct attribute *spi_device_statistics_attrs[] = {
181 &dev_attr_spi_device_transfer_bytes_histo14.attr, 183 &dev_attr_spi_device_transfer_bytes_histo14.attr,
182 &dev_attr_spi_device_transfer_bytes_histo15.attr, 184 &dev_attr_spi_device_transfer_bytes_histo15.attr,
183 &dev_attr_spi_device_transfer_bytes_histo16.attr, 185 &dev_attr_spi_device_transfer_bytes_histo16.attr,
186 &dev_attr_spi_device_transfers_split_maxsize.attr,
184 NULL, 187 NULL,
185}; 188};
186 189
@@ -223,6 +226,7 @@ static struct attribute *spi_master_statistics_attrs[] = {
223 &dev_attr_spi_master_transfer_bytes_histo14.attr, 226 &dev_attr_spi_master_transfer_bytes_histo14.attr,
224 &dev_attr_spi_master_transfer_bytes_histo15.attr, 227 &dev_attr_spi_master_transfer_bytes_histo15.attr,
225 &dev_attr_spi_master_transfer_bytes_histo16.attr, 228 &dev_attr_spi_master_transfer_bytes_histo16.attr,
229 &dev_attr_spi_master_transfers_split_maxsize.attr,
226 NULL, 230 NULL,
227}; 231};
228 232
@@ -2237,6 +2241,113 @@ struct spi_replaced_transfers *spi_replace_transfers(
2237} 2241}
2238EXPORT_SYMBOL_GPL(spi_replace_transfers); 2242EXPORT_SYMBOL_GPL(spi_replace_transfers);
2239 2243
2244int __spi_split_transfer_maxsize(struct spi_master *master,
2245 struct spi_message *msg,
2246 struct spi_transfer **xferp,
2247 size_t maxsize,
2248 gfp_t gfp)
2249{
2250 struct spi_transfer *xfer = *xferp, *xfers;
2251 struct spi_replaced_transfers *srt;
2252 size_t offset;
2253 size_t count, i;
2254
2255 /* warn once about this fact that we are splitting a transfer */
2256 dev_warn_once(&msg->spi->dev,
2257 "spi_transfer of length %i exceed max length of %i - needed to split transfers\n",
2258 xfer->len, maxsize);
2259
2260 /* calculate how many we have to replace */
2261 count = DIV_ROUND_UP(xfer->len, maxsize);
2262
2263 /* create replacement */
2264 srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, gfp);
2265 if (!srt)
2266 return -ENOMEM;
2267 xfers = srt->inserted_transfers;
2268
2269 /* now handle each of those newly inserted spi_transfers
2270 * note that the replacements spi_transfers all are preset
2271 * to the same values as *xferp, so tx_buf, rx_buf and len
2272 * are all identical (as well as most others)
2273 * so we just have to fix up len and the pointers.
2274 *
2275 * this also includes support for the depreciated
2276 * spi_message.is_dma_mapped interface
2277 */
2278
2279 /* the first transfer just needs the length modified, so we
2280 * run it outside the loop
2281 */
2282 xfers[0].len = min(maxsize, xfer[0].len);
2283
2284 /* all the others need rx_buf/tx_buf also set */
2285 for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
2286 /* update rx_buf, tx_buf and dma */
2287 if (xfers[i].rx_buf)
2288 xfers[i].rx_buf += offset;
2289 if (xfers[i].rx_dma)
2290 xfers[i].rx_dma += offset;
2291 if (xfers[i].tx_buf)
2292 xfers[i].tx_buf += offset;
2293 if (xfers[i].tx_dma)
2294 xfers[i].tx_dma += offset;
2295
2296 /* update length */
2297 xfers[i].len = min(maxsize, xfers[i].len - offset);
2298 }
2299
2300 /* we set up xferp to the last entry we have inserted,
2301 * so that we skip those already split transfers
2302 */
2303 *xferp = &xfers[count - 1];
2304
2305 /* increment statistics counters */
2306 SPI_STATISTICS_INCREMENT_FIELD(&master->statistics,
2307 transfers_split_maxsize);
2308 SPI_STATISTICS_INCREMENT_FIELD(&msg->spi->statistics,
2309 transfers_split_maxsize);
2310
2311 return 0;
2312}
2313
2314/**
2315 * spi_split_tranfers_maxsize - split spi transfers into multiple transfers
2316 * when an individual transfer exceeds a
2317 * certain size
2318 * @master: the @spi_master for this transfer
2319 * @message: the @spi_message to transform
2320 * @max_size: the maximum when to apply this
2321 *
2322 * Return: status of transformation
2323 */
2324int spi_split_transfers_maxsize(struct spi_master *master,
2325 struct spi_message *msg,
2326 size_t maxsize,
2327 gfp_t gfp)
2328{
2329 struct spi_transfer *xfer;
2330 int ret;
2331
2332 /* iterate over the transfer_list,
2333 * but note that xfer is advanced to the last transfer inserted
2334 * to avoid checking sizes again unnecessarily (also xfer does
2335 * potentiall belong to a different list by the time the
2336 * replacement has happened
2337 */
2338 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
2339 if (xfer->len > maxsize) {
2340 ret = __spi_split_transfer_maxsize(
2341 master, msg, &xfer, maxsize, gfp);
2342 if (ret)
2343 return ret;
2344 }
2345 }
2346
2347 return 0;
2348}
2349EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
2350
2240/*-------------------------------------------------------------------------*/ 2351/*-------------------------------------------------------------------------*/
2241 2352
2242/* Core methods for SPI master protocol drivers. Some of the 2353/* Core methods for SPI master protocol drivers. Some of the
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index d71385756fee..3c02b4d06268 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -53,6 +53,10 @@ extern struct bus_type spi_bus_type;
53 * 53 *
54 * @transfer_bytes_histo: 54 * @transfer_bytes_histo:
55 * transfer bytes histogramm 55 * transfer bytes histogramm
56 *
57 * @transfers_split_maxsize:
58 * number of transfers that have been split because of
59 * maxsize limit
56 */ 60 */
57struct spi_statistics { 61struct spi_statistics {
58 spinlock_t lock; /* lock for the whole structure */ 62 spinlock_t lock; /* lock for the whole structure */
@@ -72,6 +76,8 @@ struct spi_statistics {
72 76
73#define SPI_STATISTICS_HISTO_SIZE 17 77#define SPI_STATISTICS_HISTO_SIZE 17
74 unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE]; 78 unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];
79
80 unsigned long transfers_split_maxsize;
75}; 81};
76 82
77void spi_statistics_add_transfer_stats(struct spi_statistics *stats, 83void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
@@ -935,6 +941,15 @@ extern struct spi_replaced_transfers *spi_replace_transfers(
935 941
936/*---------------------------------------------------------------------------*/ 942/*---------------------------------------------------------------------------*/
937 943
944/* SPI transfer transformation methods */
945
946extern int spi_split_transfers_maxsize(struct spi_master *master,
947 struct spi_message *msg,
948 size_t maxsize,
949 gfp_t gfp);
950
951/*---------------------------------------------------------------------------*/
952
938/* All these synchronous SPI transfer routines are utilities layered 953/* All these synchronous SPI transfer routines are utilities layered
939 * over the core async transfer primitive. Here, "synchronous" means 954 * over the core async transfer primitive. Here, "synchronous" means
940 * they will sleep uninterruptibly until the async transfer completes. 955 * they will sleep uninterruptibly until the async transfer completes.