Changeset 14839


Ignore:
Timestamp:
2009-03-10T12:54:04+01:00 (8 years ago)
Author:
mb
Message:

ucmb: Allow chunk-ing big transfers to reduce latency issues.

Location:
packages/utils/ucmb/driver
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • packages/utils/ucmb/driver/ucmb.c

    r14838 r14839  
    2929#include <linux/delay.h> 
    3030#include <linux/crc16.h> 
     31#include <linux/sched.h> 
    3132 
    3233#include <asm/uaccess.h> 
     
    4849        bool is_open; 
    4950 
     51        unsigned int chunk_size; 
    5052        unsigned int msg_delay_usec; 
    5153        unsigned int gpio_reset; 
     
    229231} 
    230232 
     233static int ucmb_spi_write(struct ucmb *ucmb, const void *_buf, size_t size) 
     234{ 
     235        const u8 *buf = _buf; 
     236        size_t i, chunk_size, current_size; 
     237        int err = 0; 
     238 
     239        chunk_size = ucmb->chunk_size ? : size; 
     240        for (i = 0; i < size; i += chunk_size) { 
     241                current_size = chunk_size; 
     242                if (i + current_size > size) 
     243                        current_size = size - i; 
     244                err = spi_write(ucmb->sdev, buf + i, current_size); 
     245                if (err) 
     246                        goto out; 
     247                if (ucmb->chunk_size && need_resched()) 
     248                        msleep(1); 
     249        } 
     250out: 
     251        return err; 
     252} 
     253 
     254static int ucmb_spi_read(struct ucmb *ucmb, void *_buf, size_t size) 
     255{ 
     256        u8 *buf = _buf; 
     257        size_t i, chunk_size, current_size; 
     258        int err = 0; 
     259 
     260        chunk_size = ucmb->chunk_size ? : size; 
     261        for (i = 0; i < size; i += chunk_size) { 
     262                current_size = chunk_size; 
     263                if (i + current_size > size) 
     264                        current_size = size - i; 
     265                err = spi_read(ucmb->sdev, buf + i, current_size); 
     266                if (err) 
     267                        goto out; 
     268                if (ucmb->chunk_size && need_resched()) 
     269                        msleep(1); 
     270        } 
     271out: 
     272        return err; 
     273} 
     274 
    231275static ssize_t ucmb_read(struct file *filp, char __user *user_buf, 
    232276                         size_t size, loff_t *offp) 
     
    249293                goto out; 
    250294 
    251         err = spi_read(ucmb->sdev, (u8 *)&hdr, sizeof(hdr)); 
     295        err = ucmb_spi_read(ucmb, &hdr, sizeof(hdr)); 
    252296        if (err) 
    253297                goto out_free; 
     
    263307                goto out_free; 
    264308        size = le16_to_cpu(hdr.len); 
    265         err = spi_read(ucmb->sdev, buf, size); 
    266         if (err) 
    267                 goto out_free; 
    268         err = spi_read(ucmb->sdev, (u8 *)&footer, sizeof(footer)); 
     309        err = ucmb_spi_read(ucmb, buf, size); 
     310        if (err) 
     311                goto out_free; 
     312        err = ucmb_spi_read(ucmb, &footer, sizeof(footer)); 
    269313        if (err) 
    270314                goto out_free; 
     
    289333 
    290334out_send_status: 
    291         res = spi_write(ucmb->sdev, (u8 *)&status, sizeof(status)); 
     335        res = ucmb_spi_write(ucmb, &status, sizeof(status)); 
    292336        if (res && !err) 
    293337                err = res; 
     
    309353        struct ucmb_message_footer footer = { .crc = 0xFFFF, }; 
    310354        struct ucmb_status status; 
    311         struct spi_transfer spi_hdr_xfer; 
    312         struct spi_transfer spi_footer_xfer; 
    313         struct spi_transfer spi_data_xfer; 
    314         struct spi_message spi_msg; 
     355        size_t i, current_size, chunk_size; 
    315356 
    316357        mutex_lock(&ucmb->mutex); 
     
    331372        footer.crc ^= 0xFFFF; 
    332373 
    333         spi_message_init(&spi_msg); 
    334  
    335         memset(&spi_hdr_xfer, 0, sizeof(spi_hdr_xfer)); 
    336         spi_hdr_xfer.tx_buf = &hdr; 
    337         spi_hdr_xfer.len = sizeof(hdr); 
    338         spi_message_add_tail(&spi_hdr_xfer, &spi_msg); 
    339  
    340         memset(&spi_data_xfer, 0, sizeof(spi_data_xfer)); 
    341         spi_data_xfer.tx_buf = buf; 
    342         spi_data_xfer.len = size; 
    343         spi_message_add_tail(&spi_data_xfer, &spi_msg); 
    344  
    345         memset(&spi_footer_xfer, 0, sizeof(spi_footer_xfer)); 
    346         spi_footer_xfer.tx_buf = &footer; 
    347         spi_footer_xfer.len = sizeof(footer); 
    348         spi_message_add_tail(&spi_footer_xfer, &spi_msg); 
    349  
    350         /* Send the message, including header. */ 
    351         err = spi_sync(ucmb->sdev, &spi_msg); 
     374        err = ucmb_spi_write(ucmb, &hdr, sizeof(hdr)); 
     375        if (err) 
     376                goto out_free; 
     377        err = ucmb_spi_write(ucmb, buf, size); 
     378        if (err) 
     379                goto out_free; 
     380        err = ucmb_spi_write(ucmb, &footer, sizeof(footer)); 
    352381        if (err) 
    353382                goto out_free; 
     
    365394 
    366395        /* Get the status code. */ 
    367         err = spi_read(ucmb->sdev, (u8 *)&status, sizeof(status)); 
     396        err = ucmb_spi_read(ucmb, &status, sizeof(status)); 
    368397        if (err) 
    369398                goto out_free; 
     
    405434        ucmb->gpio_reset = pdata->gpio_reset; 
    406435        ucmb->reset_activelow = pdata->reset_activelow; 
     436        ucmb->chunk_size = pdata->chunk_size; 
     437 
     438#ifdef CONFIG_PREEMPT 
     439        /* A preemptible kernel does not need to sleep between 
     440         * chunks, because it can sleep at desire (if IRQs are enabled). 
     441         * So transmit/receive it all in one go. */ 
     442        ucmb->chunk_size = 0; 
     443#endif 
    407444 
    408445        /* Create the SPI GPIO bus master. */ 
  • packages/utils/ucmb/driver/ucmb.h

    r14769 r14839  
    4242 * @mode:               The SPI bus mode. SPI_MODE_* 
    4343 * @max_speed_hz:       The bus speed, in Hz. If zero the speed is not limited. 
     44 * @chunk_size:         The maximum chunk size to transmit/receive in one go 
     45 *                      without sleeping. The kernel will be allowed to sleep 
     46 *                      after each chunk. 
     47 *                      If set to 0, the whole data will be transmitted/received 
     48 *                      in one big rush without sleeping. Note that this might hurt 
     49 *                      system responsiveness, if the kernel is not preemptible. 
     50 *                      If CONFIG_PREEMPT is enabled, chunk_size will be forced to 0. 
    4451 */ 
    4552struct ucmb_platform_data { 
     
    5663        u8 mode; 
    5764        u32 max_speed_hz; 
     65        unsigned int chunk_size; 
    5866 
    5967        struct platform_device *pdev; /* internal */ 
Note: See TracChangeset for help on using the changeset viewer.