Загрузка данных


#include <linux/slab.h>
#include <linux/delay.h>

static int sysconfig_i2c_bitstream_burst_write(struct sysconfig_priv *priv, const char *buf, size_t len)
{
    struct i2c_client *client = to_i2c_client(priv->dev);
    struct i2c_msg msgs[2];
    const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7A, 0x00, 0x00, 0x00}
    size_t offset = 0;
    int ret;

    /* Оптимальный размер блока для баланса DMA процессора и декомпрессора ПЛИС */
    const size_t BLOCK_SIZE = 65536; 

    if (len == 0)
        return 0;

    size_t aligned_len = (len + 3) & ~3;
    size_t total_padding = aligned_len - len;

    printk("%s(%d) Paced Block Mode (400kHz): len = %zu, Aligned = %zu\n", 
            __FUNCTION__, __LINE__, len, aligned_len);

    while (offset < len) {
        size_t chunk_size = min(BLOCK_SIZE, len - offset);
        u8 *padded_buf = NULL;

        /* Сообщение 0: Всегда отправляем команду 0x7A перед каждым блоком данных */
        msgs[0].addr = client->addr;
        msgs[0].flags = client->flags & I2C_M_TEN;
        msgs[0].len = sizeof(lsc_bitstream_burst);
        msgs[0].buf = (u8 *)lsc_bitstream_burst;

        /* Сообщение 1: Сам блок данных (удерживаем шину через NOSTART) */
        msgs[1].addr = client->addr;
        msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;

        /* Если это самый финальный кусок и для него требуется Padding до 4 байт */
        if (offset + chunk_size == len && total_padding > 0) {
            size_t padded_chunk_size = chunk_size + total_padding;
            padded_buf = kmalloc(padded_chunk_size, GFP_KERNEL);
            if (!padded_buf)
                return -ENOMEM;

            memcpy(padded_buf, buf + offset, chunk_size);
            memset(padded_buf + chunk_size, 0xFF, total_padding);

            msgs[1].len = padded_chunk_size;
            msgs[1].buf = padded_buf;
            
            printk("%s(%d) Sending final padded block: %zu bytes\n", __FUNCTION__, __LINE__, padded_chunk_size);
        } else {
            /* Обычный промежуточный блок прошивки размером 64 КБ */
            msgs[1].len = chunk_size;
            msgs[1].buf = (u8 *)(buf + offset);
        }

        /* Отправляем пару (Команда 0x7A + Блок данных) без STOP-бита между ними */
        ret = i2c_transfer(client->adapter, msgs, 2);
        
        if (padded_buf)
            kfree(padded_buf);

        if (ret != 2) {
            dev_err(priv->dev, "I2C block transfer failed at offset %zu: %d\n", offset, ret);
            return (ret < 0) ? ret : -EIO;
        }

        offset += chunk_size;

        /* ВАЖНО: Даем ПЛИС 2 миллисекунды на распаковку блока перед подачей следующего */
        /* Это полностью разгрузит FIFO ПЛИС и уберет ошибку переполнения/четности */
        usleep_range(2000, 2500);
    }

    printk("%s(%d) Paced stream successfully transmitted!\n", __FUNCTION__, __LINE__);
    return 0;
}