LINUX.ORG.RU

spi устройство из модуля kernel

 , ,


0

1

Всем привет, пытаюсь из своего модуля заставить работать spi интерфейс для взаимодействия с устройством на шине с cs0. И при попытке обмена получаю дамп. Но дамп вываливается не всегда. Иногда обмен проходит.

Как я инициализирую устройство. Добавил описание в DTS (соответсвенно скомпилировал и указал при загрузке)

&spi1 {
        num-cs = <1>;
        cs-gpios = <&gpioa 25 0>;
        status = "okay";
        mptiospi: spi@0{
                compatible = "epm3128";
                spi-max-frequency = <100000>;
                reg=<0>;
        };

};

После загрузки устройство успешно отображается на sys_fs

# ls /sys/class/spi_master/spi1/
device      power       statistics  uevent
of_node     spi1.0      subsystem
В модуле ядра следующий код.
...
static struct spi_device * epm3128_spi_dev;
extern struct bus_type  spi_bus_type;
...
void
my_spi_init(void)
{
        struct spi_master *spi_1;
        struct spi_message	m;
        struct spi_transfer xfer  = {       
                        .tx_buf = &spi_tx_buf,
                        .rx_buf = &spi_rx_buf,
                        .len = 2, 
                        .bits_per_word = 16,
        };

        spi_1 = spi_busnum_to_master(1);
        epm3128_spi_dev = bus_find_device_by_name(&spi_bus_type,spi_1,"spi1.0");

        if(epm3128_spi_dev) {
                spi_tx_buf = 0xaaaa;
                spi_rx_buf = 0;
                spi_setup(epm3128_spi_dev);
                spi_message_init_with_transfers(&m,&xfer,1);
                spi_async(epm3128_spi_dev,&m);
        }
}

Есть идеи, что я мог упустить?

# [   44.065615] mmc0: Timeout waiting for hardware interrupt.
[   44.073009] ------------[ cуt here ]------------
[   44.077633] WARNING: CPU: 1 PID: 0 at drivers/mmc/host/sdhci.c:1026 sdhci_send_command+0x788/0xb70()
[   44.086750] Modules linked in: mpt_sys_driver(O)
[   44.091390] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G           O    4.4.111.8 #1
[   44.098774] Hardware name: ELVEES MCom-02 (Flattened Device Tree)
[   44.104856] Backtrace: 
[   44.107330] [<c0013a40>] (dump_backtrace) from [<c0013c5c>] (show_stack+0x18/0x1c)
[   44.114886]  r7:c03d920c r6:600b0193 r5:00000000 r4:c0724ca4
[   44.120594] [<c0013c44>] (show_stack) from [<c024456c>] (dump_stack+0x90/0xa4)
[   44.127819] [<c02444dc>] (dump_stack) from [<c0023f98>] (warn_slowpath_common+0x88/0xb8)
[   44.135894]  r7:c03d920c r6:00000402 r5:00000009 r4:00000000
[   44.141600] [<c0023f10>] (warn_slowpath_common) from [<c002406c>] (warn_slowpath_null+0x24/0x2c)
[   44.150369]  r8:eebd03a0 r7:c03da144 r6:ee68dcc4 r5:ee5d5b00 r4:ee5d5b00
[   44.157122] [<c0024048>] (warn_slowpath_null) from [<c03d920c>] (sdhci_send_command+0x788/0xb70)
[   44.165898] [<c03d8a84>] (sdhci_send_command) from [<c03d9d80>] (sdhci_finish_data+0xdc/0x354)
[   44.174493]  r10:eebd0380 r9:2e4c2000 r8:eebd03a0 r7:c03da144 r6:600b0113 r5:ee68dcf8
[   44.182369]  r4:ee5d5b00
[   44.184914] [<c03d9ca4>] (sdhci_finish_data) from [<c03da1bc>] (sdhci_timeout_timer+0x78/0xbc)
[   44.193509]  r10:eebd0380 r9:2e4c2000 r8:eebd03a0 r7:c03da144 r6:600b0113 r5:ee5d5c40
[   44.201383]  r4:ee5d5b00
[   44.203937] [<c03da144>] (sdhci_timeout_timer) from [<c0073980>] (call_timer_fn.constprop.4+0x30/0x9c)
[   44.213225]  r7:c03da144 r6:00000100 r5:00000200 r4:ffffe000
[   44.218928] [<c0073950>] (call_timer_fn.constprop.4) from [<c0073b88>] (run_timer_softirq+0x19c/0x214)
[   44.228217]  r7:c0716100 r6:c070e380 r5:00000200 r4:00000000
[   44.233921] [<c00739ec>] (run_timer_softirq) from [<c0027c74>] (__do_softirq+0xfc/0x258)
[   44.241996]  r10:00000100 r9:c0716084 r8:c0716080 r7:00000001 r6:ffffe000 r5:40000001
[   44.249872]  r4:00000020
[   44.252416] [<c0027b78>] (__do_softirq) from [<c002806c>] (irq_exit+0x80/0xb8)
[   44.259625]  r10:c064243c r9:f0803100 r8:ee408000 r7:00000001 r6:00000000 r5:00000000
[   44.267500]  r4:c070f2d4
[   44.270046] [<c0027fec>] (irq_exit) from [<c0063cd8>] (__handle_domain_irq+0x68/0xbc)
[   44.277862]  r5:00000000 r4:c070f2d4
[   44.281460] [<c0063c70>] (__handle_domain_irq) from [<c0009450>] (gic_handle_irq+0x50/0x94)
[   44.289796]  r9:f0803100 r8:ee483f58 r7:f0802100 r6:f080210c r5:c0724e00 r4:c0716760
[   44.297589] [<c0009400>] (gic_handle_irq) from [<c0014694>] (__irq_svc+0x54/0x70)
[   44.305060] Exception stack(0xee483f58 to 0xee483fa0)
[   44.310105] 3f40:                                                       00000000 00012090
[   44.318274] 3f60: eebd0340 c001fba0 ffffe000 c07164e8 c071649c c070e320 c05406f8 c073f4ad
[   44.326443] 3f80: c064243c ee483fb4 ee483fb8 ee483fa8 c00107a0 c00107a4 600b0013 ffffffff
[   44.334605]  r9:c073f4ad r8:c05406f8 r7:ee483f8c r6:ffffffff r5:600b0013 r4:c00107a4
[   44.342406] [<c0010764>] (arch_cpu_idle) from [<c005ad7c>] (default_idle_call+0x28/0x34)
[   44.350488] [<c005ad54>] (default_idle_call) from [<c005ae00>] (cpu_startup_entry+0x78/0x18c)
[   44.359005] [<c005ad88>] (cpu_startup_entry) from [<c0015ba0>] (secondary_start_kernel+0x14c/0x158)
[   44.368034]  r7:c0742260 r4:c071f4c8
[   44.371630] [<c0015a54>] (secondary_start_kernel) from [<4000952c>] (0x4000952c)
[   44.379013]  r5:00000051 r4:6e46c06a
[   44.382605] ---[ end trace 1fb70ea29a4ea63d ]---
[   51.755607] INFO: rcu_sched self-detected stall on CPU
[   51.760759] 	0-...: (1 GPs behind) idle=24d/140000000000002/0 softirq=1012/1014 fqs=2065 
[   51.768921] 	 (t=2100 jiffies g=169 c=168 q=49)
[   51.773457] Task dump for CPU 0:
[   51.776680] spi1            R running      0    54      2 0x00000002
[   51.783045] Backtrace: 
[   51.785511] [<c0013a40>] (dump_backtrace) from [<c0013c5c>] (show_stack+0x18/0x1c)
[   51.793068]  r7:00000140 r6:c0716518 r5:00000000 r4:ee61dc80
[   51.798779] [<c0013c44>] (show_stack) from [<c00495e4>] (sched_show_task+0xac/0xfc)
[   51.806429] [<c0049538>] (sched_show_task) from [<c004b4fc>] (dump_cpu_task+0x40/0x44)
[   51.814331]  r5:00000000 r4:00000000
[   51.817931] [<c004b4bc>] (dump_cpu_task) from [<c006d7bc>] (rcu_dump_cpu_stacks+0xb4/0xc0)
[   51.826180]  r5:00000000 r4:c071d380
[   51.829780] [<c006d708>] (rcu_dump_cpu_stacks) from [<c00715ec>] (rcu_check_callbacks+0x3d0/0x788)
[   51.838722]  r9:c0716518 r8:c071d380 r7:c071d380 r6:2e4b6000 r5:c0712080 r4:eebc8080
[   51.846519] [<c007121c>] (rcu_check_callbacks) from [<c0073c44>] (update_process_times+0x44/0x6c)
[   51.855375]  r10:000186a0 r9:0000000c r8:0b592880 r7:ee411280 r6:00000000 r5:ee61dc80
[   51.863251]  r4:ffffe000
[   51.865805] [<c0073c00>] (update_process_times) from [<c0081370>] (tick_periodic+0x44/0xbc)
[   51.874141]  r7:ee411280 r6:c0716140 r5:00000000 r4:00989680
[   51.879846] [<c008132c>] (tick_periodic) from [<c0081560>] (tick_handle_periodic+0x30/0x90)
[   51.888182]  r9:00000000 r8:00000010 r7:ee411280 r6:eebca5c0 r5:7fffffff r4:ffffffff
[   51.895980] [<c0081530>] (tick_handle_periodic) from [<c0016940>] (twd_handler+0x38/0x48)
[   51.904142]  r9:f0803100 r8:00000010 r7:ee411280 r6:c0724e04 r5:ee405c00 r4:00000001
[   51.911940] [<c0016908>] (twd_handler) from [<c0067f2c>] (handle_percpu_devid_irq+0x78/0x90)
[   51.920362]  r5:ee405c00 r4:eebca5c0
[   51.923961] [<c0067eb4>] (handle_percpu_devid_irq) from [<c0063a04>] (generic_handle_irq+0x2c/0x3c)
[   51.932989]  r9:f0803100 r8:ee408000 r7:00000001 r6:ee695e18 r5:00000000 r4:c070f2d4
[   51.940784] [<c00639d8>] (generic_handle_irq) from [<c0063cd4>] (__handle_domain_irq+0x64/0xbc)
[   51.949472] [<c0063c70>] (__handle_domain_irq) from [<c0009450>] (gic_handle_irq+0x50/0x94)
[   51.957808]  r9:f0803100 r8:ee695d00 r7:f0802100 r6:f080210c r5:c0724e00 r4:c0716760
[   51.965601] [<c0009400>] (gic_handle_irq) from [<c0014694>] (__irq_svc+0x54/0x70)
[   51.973071] Exception stack(0xee695d00 to 0xee695d48)
[   51.978120] 5d00: c0742a40 c0742a40 00000000 00000000 00000082 00000000 ffffe000 00000001
[   51.986289] 5d20: ee408000 f0803100 000186a0 ee695dac 00208040 ee695d50 c002806c c0027c18
[   51.994453] 5d40: 600d0113 ffffffff
[   51.997935]  r9:f0803100 r8:ee408000 r7:ee695d34 r6:ffffffff r5:600d0113 r4:c0027c18
[   52.005729] [<c0027b78>] (__do_softirq) from [<c002806c>] (irq_exit+0x80/0xb8)
[   52.012939]  r10:000186a0 r9:f0803100 r8:ee408000 r7:00000001 r6:00000000 r5:00000000
[   52.020815]  r4:c070f2d4
[   52.023360] [<c0027fec>] (irq_exit) from [<c0063cd8>] (__handle_domain_irq+0x68/0xbc)
[   52.031176]  r5:00000000 r4:c070f2d4
[   52.034773] [<c0063c70>] (__handle_domain_irq) from [<c0009450>] (gic_handle_irq+0x50/0x94)
[   52.043109]  r9:f0803100 r8:ee695e18 r7:f0802100 r6:f080210c r5:c0724e00 r4:c0716760
[   52.050903] [<c0009400>] (gic_handle_irq) from [<c0014694>] (__irq_svc+0x54/0x70)
[   52.058373] Exception stack(0xee695e18 to 0xee695e60)
[   52.063417] 5e00:                                                       00000001 00000002
[   52.071585] 5e20: 00000001 00000000 ee5f60d0 00000080 ee6830c0 f099202c ee68c400 f0992000
[   52.079753] 5e40: 000186a0 ee695e94 ee695e98 ee695e68 c0317a58 c0317a1c 600d0013 ffffffff
[   52.087915]  r9:f0992000 r8:ee68c400 r7:ee695e4c r6:ffffffff r5:600d0013 r4:c0317a1c
[   52.095713] [<c0317808>] (dw_spi_transfer_one) from [<c03169c0>] (spi_transfer_one_message+0xfc/0x36c)
[   52.105001]  r10:c0724c8c r9:ee600e40 r8:ee68c5b0 r7:ed87fd1c r6:ee600c00 r5:ed87fd4c
[   52.112877]  r4:ee600c00 r3:c0317808
[   52.116475] [<c03168c4>] (spi_transfer_one_message) from [<c0316fa0>] (__spi_pump_messages+0x370/0x4c8)
[   52.125851]  r10:00000000 r9:00000000 r8:00000000 r7:00000001 r6:ed87fd1c r5:ee600dec
[   52.133728]  r4:ee600c00
[   52.136273] [<c0316c30>] (__spi_pump_messages) from [<c0317110>] (spi_pump_messages+0x18/0x1c)
[   52.144869]  r10:00000000 r9:00000000 r8:00000000 r7:00000001 r6:c0786a44 r5:ffffe000
[   52.152744]  r4:ee600dc4
[   52.155292] [<c03170f8>] (spi_pump_messages) from [<c003fdb4>] (kthread_worker_fn+0xdc/0x1a0)
[   52.163806] [<c003fcd8>] (kthread_worker_fn) from [<c004000c>] (kthread+0x110/0x118)
[   52.171535]  r9:00000000 r8:c003fcd8 r7:ee600dc4 r6:ee694000 r5:ee5fa3c0 r4:00000000
[   52.179331] [<c003fefc>] (kthread) from [<c000fd30>] (ret_from_fork+0x14/0x24)
[   52.186540]  r8:00000000 r7:00000000 r6:00000000 r5:c003fefc r4:ee5fa3c0


Последнее исправление: Niore (всего исправлений: 3)

Ура, вопрос не про установку кали на флешку!!!

Жалко ответа у меня нет)) Но есть вопрос, чем обусловлен выбор подхода подсосаться к шине через bus_find_device_by_name? иии максимальная частота в dts не маловата?

sparks ★★★★
()

чем обусловлен выбор подхода подсосаться к шине через bus_find_device_by_name?

Это единственное, что я пока накопал в исходниках. Чем у меня вообще получилось захватить управление устройством.

А максимальную частоту в DTS ограничил для удобства наблюдения осциллографом.

Niore
() автор топика

А spidev не пробовал ?

https://elixir.bootlin.com/linux/v4.20.17/source/Documentation/spi/spidev

Нужно в конфиге ядра включить

CONFIG_SPI_SPIDEV=y

А dts в твоем случае будет наверное:

&spi1 {
        num-cs = <1>;
        cs-gpios = <&gpioa 25 0>;
        status = "okay";
        mptiospi: spidev@0{
                compatible = "rohm,dh2228fv";
                spi-max-frequency = <100000>;
                reg=<0>;
        };

};

Для тестирования есть https://tracker.debian.org/pkg/spi-tools

spi-config -d /dev/spidev32766.0 -q
echo -ne "\xA5\xA5\xA5\xA5\xA5\xA5\xA5\xA5" | spi-pipe -d /dev/spidev32766.0 | hexdump -C
alx777 ★★
()

Есть идеи, что я мог упустить?

использется spi_async (кстати с какой целью ?) а калбэк complete в spi_message не инициализирован

https://elixir.bootlin.com/linux/latest/source/include/linux/spi/spi.h#L868

если не используется - его надо _обязательно_ инициализировать в NULL иначе будет вызван рандомный код или использовать spi_sync.

anonymous
()
Ответ на: комментарий от anonymous

использется spi_async (кстати с какой целью ?) а калбэк complete в spi_message не инициализирован

Асинхронный вызов я уже в следствии всяческих экспериментов стал вызывать,а структуру сообщения объявляю как обычную переменную, собственно в этом случае m.complete == NULL по умолчанию.

Спасибоза наводку, не дочитал комменты на структуру. Попробую целиком инициализировать.

Niore
() автор топика
Ответ на: комментарий от Niore

Насколько я разобрался, это для работы из userspace

Да, зато свой драйвер не нужен, используется стандартный spidev

Для простых случаев и для проверки все ли в порядке с железом вполне может подойти

alx777 ★★
()
Ответ на: комментарий от alx777

Да с железом порядок, если убрать устройство из DTS, то я могу через память настроить регистры приемопередатчика и провести обмен(проверено). Мне достаточно и такого метода, но я пока не понимаю, как в этом варианте связать IRQ железа с ядром.

Niore
() автор топика
Ответ на: комментарий от Niore

объявляю как обычную переменную, собственно в этом случае m.complete == NULL по умолчанию

struct spi_message m;

объявлена на стеке так что по умолчанию там рандомное значение

anonymous
()
Ответ на: комментарий от Niore

но я пока не понимаю, как в этом варианте связать IRQ железа с ядром

Если нужно обрабатывать IRQ от железа то без собственного драйвера будет сложно обойтись и spidev тут не очень подходит

alx777 ★★
()
Ответ на: комментарий от Niore

bus_find_device_by_name?
Это единственное, что я пока накопал в исходниках. Чем у меня вообще получилось захватить управление устройством.

в ядре множество примеров используюших spi

https://elixir.bootlin.com/linux/latest/ident/ами

bus_find_device_by_name используется очень редко - даже не могу придумать для какого случая она может быть нужна

anonymous
()
Ответ на: комментарий от sparks

шут одно

несколько ядрёных модулей работают с одним девайсом на шине

это какой-то мрачный колхоз противоречащий идее ОС - с устройством должен работать один драйвер, для всех остальных он предоставляет API этой ОС. Такой колхоз еще допустим если нужно только читать регистры устройства, но как вы представляете запись а один и тот же регистр из нескольких независмых драйеров ? один записал 1, второй 2, первый ничего не знает о втором и думает что там 1.

anonymous
()
Ответ на: комментарий от sparks

это не драйвер, а просто модуль ядра

что же модуль делает с утройством на spi если это не драйвер, пустые сообщения шлёт ?

anonymous
()
Ответ на: комментарий от anonymous

У меня сложный модуль. Он использует uart, i2c, spi Именно модуль, а не драйвер для конкретного устройства. Все примеры с spi которые я пока успел пролистать, используют идею модуль = драйвер с использованием probe и своих init.

Niore
() автор топика
Ответ на: комментарий от Niore

Имхо подход с драйвером правильный, строчка compatible = «epm3128»; в dts указывает ядру, что для девайса на этой шине, использовать spi драйвер epm3128

sparks ★★★★
()
Ответ на: комментарий от Niore

Именно модуль, а не драйвер для конкретного устройства

не надо путать теплое с мягким

Он использует uart, i2c, spi

проще в этой ситуации зарегистрировать драйвер на шине i2c в DTS (i2c драйвер) и передать через его ноду в DTS номер spi-контроллера к которому устройство подключено. На нужный интерфейс spi подключать устройство динамически в probe i2c-драйвера, пример динамической регистрации на spi-мастере

https://elixir.bootlin.com/linux/latest/source/drivers/staging/fbtft/fbtft_de...

то как вы сделали - прописано устройство в DTS на spi-мастере без драйвера и потом ищете его - не у верен что так вообще может работать.

anonymous
()
Ответ на: комментарий от anonymous

не надо путать теплое с мягким

Если вся работа с железом происходит в модуле и никакого интерфейса больше никому не предоставляется, то драйвером такое тоже сложно назвать

то как вы сделали - прописано устройство в DTS на spi-мастере без драйвера и потом ищете его - не у верен что так вообще может работать.

Там устройство добавляется к уже существующему мастеру &spi1 с драйвером у которого должно быть все в порядке

alx777 ★★
()
Ответ на: комментарий от alx777

Если вся работа с железом происходит в модуле и никакого интерфейса больше никому не предоставляется

мне сложно представить зачем для такого тупого железа нужен модуль ядра

Там устройство добавляется к уже существующему мастеру &spi1

это очевидно из описания DTS

с драйвером у которого должно быть все в порядке

драйвер для него он и делает, просто не знает как ему совместить несколько интерфейсов в одном модуле

anonymous
()
Ответ на: комментарий от Niore

Все примеры с spi которые я пока успел пролистать, используют идею модуль = драйвер с использованием probe и своих init.

А что мешаeт для этого модуля сделать свой probe где будут инициализироваться uart, i2c, spi, irq ?

alx777 ★★
()
Ответ на: комментарий от alx777

А что мешаeт для этого модуля сделать свой probe где будут инициализироваться uart, i2c, spi, irq ?

то что в драйвере i2c на входе в probe приходит указатель на i2c-девайс, в драйвере spi на spi-девайс, а в своем модуле - абстрактный platform девайс и информацию об устройствах i2c и spi нужно разыскивать через анальное отверстие

anonymous
()
Ответ на: комментарий от anonymous

мне сложно представить зачем для такого тупого железа нужен модуль ядра

Например что-то вроде самопального ADC из-за realtime requirements

с драйвером у которого должно быть все в порядке

драйвер для него он и делает, просто не знает как ему совместить несколько интерфейсов в одном модуле

Я здесь имел ввиду драйвер самого SPI контроллера который работает напрямую с регистрами, DMA и т.п., типа этого

https://elixir.bootlin.com/linux/latest/source/drivers/spi/spi-imx.c

Потому что если его действительно придется писать самому то это уже несколько более интересная задача

alx777 ★★
()
Ответ на: комментарий от alx777

Например что-то вроде самопального ADC

это наверно инопланетный АЦП который измеряет но результаты измерений никому не отдает - тогда зачем для него вообще какой-то код писать

anonymous
()
Ответ на: комментарий от anonymous

тогда зачем для него вообще какой-то код писать

Как только считанное по spi значение синуса достигает четырёх (в военное время обычное дело) по i2c подается команда на подрыв боевой части торпеды

alx777 ★★
()
Ответ на: комментарий от alx777

Как только считанное по spi значение синуса достигает четырёх (в военное время обычное дело) по i2c подается команда на подрыв боевой части торпеды

для решения этой задачи нужен как минимум айфон

anonymous
()

Мое решение.

Из DTS убрал описания cs-gpios и устройсва

&spi1 {
        num-cs = <1>;
        status = "okay";
};

Рабочий вариант использования шины spi в модуле для ядра версии 4.4.111.8

void 
spi_1_init(void)
{
        struct spi_master       *master;
        struct spi_board_info   *spi_epm3128_info;
        uint16_t                tx;
        uint16_t                rx;
        int                     ret;    
        struct spi_transfer     *t;
	struct spi_message      *m; 
        
        
        spi_epm3128_info = kzalloc(sizeof(struct spi_board_info),GFP_KERNEL);
        if(!spi_epm3128_info)
                return -ENOMEM;

        *spi_epm3128_info = (struct spi_board_info){
                .modalias="epm3128",
                .platform_data = NULL,
                .controller_data = NULL,
                .irq = -1,
                .chip_select = 0,
                .mode = SPI_MODE_0,
                .max_speed_hz = 10*1000*1000,
                .bus_num = 1,
        };
        
        m = kzalloc(sizeof(struct spi_message),GFP_KERNEL);
	t = kzalloc(sizeof(struct spi_transfer),GFP_KERNEL);
        if(!t)
                return -ENOMEM;

        tx = spi_data;
        rx = 0;        
        t->len=2;
        t->tx_buf = &tx;
        t->rx_buf = &rx;
        t->bits_per_word = 16;
        t->speed_hz =  2*1000*1000;
        

        spi_message_init(m);
        spi_message_add_tail(t, m);


        if (0 != epm3128_request_gpios())
                pr_alert("gpio request err for epm3128\n");

        master = spi_busnum_to_master(spi_epm3128_info->bus_num);

        if (!master) {
		pr_err("No such spi bus\n", spi_epm3128_info->bus_num);
		return -EINVAL;
	}
        epm3128_dev = spi_new_device(master, spi_epm3128_info);
        
        
        if (!epm3128_dev) {
		dev_err(&master->dev, "spi_new_device() returned NULL\n");
		return -EPERM;
	}


        spi_setup(epm3128_dev);
        ret = spi_sync(epm3128_dev,m);
        pr_info("spi_sync: %d",ret);
        pr_info("rx: 0x%x\n",rx);
        pr_info("tx: 0x%x\n",tx);

        put_device(&master->dev);

        kfree(t);
        kfree(m);
        kfree(spi_epm3128_info);
}

Niore
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.