Hi GenodeOS and L4-Hackers community
I'm trying to use DWC_OTG USB Driver for RaspberryPI, using Fiasco.OC as microkernel with Genode. I have tested the USB driver using Genode bare metal hardware on RaspberryPI and works fine. I have reviewed the post published by Simon Arlott about the FIQ and Bell IRQ:
http://permalink.gmane.org/gmane.linux.kernel.rpi/438
Also I have reviewed the correction implemented by Norman Feske in the IRQ controller for Genode bare metal hardware:
repos/base-hw/src/core/include/spec/rpi/pic.h
To use Fiasco.OC as microkernel in Genode I have adapted the patch published in:
http://sourceforge.net/p/genode/mailman/message/33071769/
Based on it, i have tried to use the same idea of Norman Feske, modifying the Fiasco.OC's IRQ's controller as shown below:
------ kernel/fiasco/src/kern/arm/bsp/bcm2835/mem_layout-arm-bcm2835.cpp ------ index aab5906..4385ebe 100644 @@ -8,5 +8,6 @@ public: Pic_phys_base = 0x2000b200, Watchdog_phys_base = 0x20100000, Uart_phys_base = 0x20201000, + Usb_dwc_otg_base = 0x20980000, }; };
---------- kernel/fiasco/src/kern/arm/bsp/bcm2835/pic-arm-bcm2835.cpp ---------- index 20ed280..13fa623 100644 @@ -7,6 +7,83 @@ IMPLEMENTATION [arm && bcm2835]: #include "irq_mgr.h" #include "mmio_register_block.h" #include "kmem.h" +#include "warn.h" + +class Usb_dwc_otg : Mmio_register_block{ +private: + enum{ + Core_irq_status_reg = 0x14, + Guid_reg = 0x3c, + Host_frame_number_reg = 0x408, + }; + bool is_sof() const { return read<Mword>(Core_irq_status_reg)&0x8; } +}; + +PUBLIC +Usb_dwc_otg::Usb_dwc_otg() +: Mmio_register_block(Kmem::mmio_remap(Mem_layout::Usb_dwc_otg_base)) +{ + + write<Mword>(read<Mword>(Guid_reg)&0x3FFFC000, Guid_reg); +} + +PRIVATE +static bool +Usb_dwc_otg::need_trigger_sof(Mword host_frame, Mword scheduled_frame) +{ + Mword const max_frame = 0x3fff; + + if (host_frame < scheduled_frame) { + if (scheduled_frame - host_frame < max_frame / 2) + return false; /* scheduled frame not reached yet */ + else + return true; /* scheduled frame passed, host frame wrapped */ + } else { + if (host_frame - scheduled_frame < max_frame / 2) + return true; /* scheduled frame passed */ + else + return false; /* scheduled frame wrapped, not reached */ + } +} + +PUBLIC +bool +Usb_dwc_otg::handle_sof() +{ + if (!is_sof()) + return false; + + static Mword cnt, stat_cnt, filter_cnt, kick_cnt, trigger_cnt; + + stat_cnt++; + if (stat_cnt == 8000) { + WARN("kicked: %d filtered: %d triggered: %d", kick_cnt, filter_cnt, trigger_cnt); + stat_cnt = 0; + } + + cnt++; + if (cnt == 8*20) { + cnt = 0; + return false; + } + + if (read<Mword>(Guid_reg)&0x40000000) + kick_cnt++; + + if ((!read<Mword>(Guid_reg)&0x80000000) || (read<Mword>(Guid_reg)&0x40000000)) + return false; + + if (Usb_dwc_otg::need_trigger_sof(read<Mword>(Host_frame_number_reg)&0x3fff, read<Mword>(Guid_reg)&0x3fff)) { + trigger_cnt++; + return false; + } + + filter_cnt++; + + write<Mword>(read<Mword>(Core_irq_status_reg)|0x8, Core_irq_status_reg); + + return true; +}
class Irq_chip_bcm : public Irq_chip_gen, Mmio_register_block { @@ -29,6 +106,9 @@ public: bool is_edge_triggered(Mword) const { return false; } void set_cpu(Mword, Cpu_number) {} void ack(Mword) { /* ack is empty */ } + +private: + Usb_dwc_otg _usb; };
PUBLIC @@ -97,6 +177,11 @@ Irq_chip_bcm::irq_handler() { b = 0; p = read<Mword>(Irq_pending_1); + if(p==8){ + if(_usb.handle_sof()){ + return; + } + } } else if (p & 0x200) {
I have tried to test the *usb_hid *example on Genode using Fiasco.OC as microkernel
make run/usb_hid
The example compiles fine. When I test it in the emulator QEMU get the following output
KERNEL: Warning: kicked: 0 filtered: 0 triggered: 7950 KERNEL: Warning: kicked: 0 filtered: 0 triggered: 15900 KERNEL: Warning: kicked: 0 filtered: 0 triggered: 23850 KERNEL: Warning: kicked: 0 filtered: 0 triggered: 31800
When have tested it on real hardware never get the kernel warning. It seems that the *Kick* and *Num_valid* bits are not modified by the USB driver. After that, I have tried to log the USB driver IRQ, setting
#define DEBUG_IRQ 1
in the file
repos/dde_linux/src/lib/usb/include/lx_emul.h
Setting this value, the USB driver will log every IRQ handled by the function *_handle()* and *_handle_one()***in the USB driver. In the Genode bare metal hardware it works fine, but when tried it with Fiasco.OC, the IRQ handler *_handle()* and *_handle_one()* are never logged. There's something wrong in my implementation? Someone has tested the USB driver using Fiasco.OC and Genode together? Why Fiasco.OC's IRQ's controller is not calling the IRQ's handler defined in the USB driver? I'm using Genode commit 63293950261bfb17497433c36a3d62e6e1d813b3, Fiasco.OC r56 and DWC_OTG commit d08b205cfe01925667f3591117b6d3e1087b4e19.
Best regards
Hello Reinier,
After that, I have tried to log the USB driver IRQ, setting
#define DEBUG_IRQ 1
in the file
repos/dde_linux/src/lib/usb/include/lx_emul.h
Setting this value, the USB driver will log every IRQ handled by the function *_handle()* and *_handle_one()***in the USB driver. In the Genode bare metal hardware it works fine, but when tried it with Fiasco.OC, the IRQ handler *_handle()* and *_handle_one()* are never logged.
apparently, the USB driver initializes the USB controller (so the SoF interrupts start appearing at the kernel) but it never receives any interrupt. The issue could be the way of how IRQs are named by Fiasco.OC and base-hw. Because of the hierarchic way of how the BCM's IRQ controller works, the OS kernel developer has to come up with an enumeration scheme. The scheme I introduced for the base-hw kernel is defined at repos/base/include/platform/rpi/drivers/board_base.h:
https://github.com/genodelabs/genode/blob/master/repos/base/include/platform...
/* * IRQ numbers 0..7 refer to the basic IRQs. * IRQ numbers 8..39 refer to GPU IRQs 0..31. * IRQ numbers 40..71 refer to GPU IRQs 32..63. */
The DWC-OTG controller uses IRQ 17. So it is not a basic IRQ. Hence, its number is subjected to the enumeration scheme above. I do not know how Fiasco.OC's naming scheme for IRQs on the Raspberry Pi looks like but it may be different. To investigate, I'd recommend you to instrument both kernels to log the accesses to the interrupt-controller registers. Look if each of them touch the same bits once the USB driver is started.
Cheers Norman
l4-hackers@os.inf.tu-dresden.de