Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TASK08: IRQ handling #147

Open
wants to merge 7 commits into
base: Sergey.Dubyna
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions 04_basic_struct/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Basic structure homework
Implement object with name “MyObject” which is parent of kernel_kobj.
Object should include linked_list structure.
This object should contain sysfs attribute with name “list”.
On read form attribute “list” it should show content of the objects linked list.
On write to attribute “list” it should add new string to the objects linked list.
!! Do not forget properly free all the resources during rmmod.
10 changes: 10 additions & 0 deletions 05_timers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Homework: Linux Kernel Time Management

1. Implement program which return absolute time in user space.
Use clock_gettime() from time.h. Try different clock id.
Find the difference. Show possible clock resolution provided by clock_getres().

2. Implement kernel module with API in sysfs, which returns relative
time in maximum possible resolution passed since previous read of it.
Implement kernel module with API in sysfs which returns absolute time
of previous reading with maximum resolution like ‘400.123567’ seconds.
22 changes: 22 additions & 0 deletions 06_memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Memory management

## Homework
1. Create user-space C or C++ program which tries to allocate buffers
with sizes 2^x for x in range from 0 to maximium possible value
using functions:
**malloc, calloc, alloca, (optional for C++) new **.
Measure time of each allocation/freeing.
2^x means x power of 2 in this task.
Pull request should contains program source code and program output
in text format.

2. Create kernel module and test allocation/freeing time for functions:
**kmalloc, kzmalloc, vmalloc, get_free_pages,
(optional and only for drivers integrated to kernel)alloc_bootmem**.
Measure the time of each allocation/freeing except alloc_bootmem.
The results should be presented in text file table with followed columns:
Buffer size, allocation time, freeing time.
Size unit is 1 byte, time unit is 1 ns.

Pull request should contains source code of developed driver, Makefile
and program output from system log in text format.
10 changes: 10 additions & 0 deletions 07_procfs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Lesson 07 - ProcFS interface and orange pi bootup

* Update your existing sysfs kernel module with procfs API:
* Create folder in procfs file system;
* Create entry that returns module author name;
* Create entry that returns amount of "store" callback calls;
* Create entry that returns amount of "show" callback calls.
* Build image for orange pi zero
* Attach console output from your development board

12 changes: 12 additions & 0 deletions 08_irq_handling/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
KERNELDIR ?= ../../output/build/linux-5.10.10/ #WARNING relative path

TARGET = led_mod_irq

obj-m := $(TARGET).o
CFLAGS_$(TARGET).o := -std=gnu11 -DDEBUG -Wno-declaration-after-statement

all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
5 changes: 5 additions & 0 deletions 08_irq_handling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Lesson 08 - IRQ handling

Run polling example on your board.
Modify you driver to enable irq handling instead of polling mechanism

45 changes: 45 additions & 0 deletions 08_irq_handling/irq_list.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
25: 0 0 0 0 GICv2 50 Level timer@1c20c00
26: 0 0 0 0 GICv2 29 Level arch_timer
27: 59053 9053 4143 4952 GICv2 30 Level arch_timer
30: 0 0 0 0 GICv2 82 Level 1c02000.dma-controller
32: 9407 0 0 0 GICv2 92 Level sunxi-mmc
33: 37027 0 0 0 GICv2 93 Level sunxi-mmc
34: 0 0 0 0 GICv2 81 Level 1c17000.mailbox
35: 0 0 0 0 GICv2 103 Level musb-hdrc.2.auto
36: 0 0 0 0 GICv2 104 Level ehci_hcd:usb1
37: 0 0 0 0 GICv2 105 Level ohci_hcd:usb2
38: 0 0 0 0 GICv2 106 Level ehci_hcd:usb3
39: 0 0 0 0 GICv2 107 Level ohci_hcd:usb4
43: 0 0 0 0 GICv2 114 Level eth0
44: 2 0 0 0 GICv2 97 Level sun6i-spi
45: 0 0 0 0 GICv2 98 Level sun6i-spi
47: 1199 0 0 0 GICv2 32 Level ttyS0
48: 0 0 0 0 GICv2 72 Level 1f00000.rtc
51: 0 0 0 0 GICv2 125 Level 1400000.deinterlace
52: 0 0 0 0 GICv2 90 Level 1c0e000.video-codec
53: 0 0 0 0 GICv2 126 Level sun8i-ce-ns
54: 0 0 0 0 GICv2 129 Level gp
55: 0 0 0 0 GICv2 130 Level gpmmu
56: 0 0 0 0 GICv2 131 Level pp0
57: 0 0 0 0 GICv2 132 Level ppmmu0
58: 0 0 0 0 GICv2 134 Level pp1
59: 0 0 0 0 GICv2 135 Level ppmmu1
61: 5134 0 0 0 GICv2 63 Level ths
62: 0 0 0 0 GICv2 152 Level arm-pmu
63: 0 0 0 0 GICv2 153 Level arm-pmu
64: 0 0 0 0 GICv2 154 Level arm-pmu
65: 0 0 0 0 GICv2 155 Level arm-pmu
105: 34 0 0 0 sunxi_pio_edge 39 Edge my_button_irq
108: 383 0 0 0 sunxi_pio_edge 42 Edge xradio
110: 1 0 0 0 sunxi_pio_edge 44 Edge usb0-id-det
IPI0: 0 0 0 0 CPU wakeup interrupts
IPI1: 0 0 0 0 Timer broadcast interrupts
IPI2: 45 47 69 98 Rescheduling interrupts
IPI3: 942 6812 4574 4547 Function call interrupts
IPI4: 0 0 0 0 CPU stop interrupts
IPI5: 25233 3185 1603 3654 IRQ work interrupts
IPI6: 0 0 0 0 completion interrupts
Err: 0

154 changes: 154 additions & 0 deletions 08_irq_handling/led_mod.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/ktime.h>
#include <linux/interrupt.h>

#define GPIO_NUMBER(port, bit) (32 * (port) + (bit))

/* https://linux-sunxi.org/Xunlong_Orange_Pi_PC#LEDs
* Board config for OPI-PC:
* LED GREEN (PL10): GPIO_11_10
* LED RED (PA15): GPIO_0_15
* BUTTON (PG7) : GPIO_6_7
*
* https://linux-sunxi.org/Xunlong_Orange_Pi_Zero#LEDs
* Board config for OPI-Zero:
* LED GREEN (PL10): GPIO_11_10
* LED RED (PA17): GPIO_0_17
* BUTTON (PG7) : GPIO_6_7
*
*/

#define LED_GREEN GPIO_NUMBER(11, 10)
#define LED_RED GPIO_NUMBER(0, 17)
#define BUTTON GPIO_NUMBER(6, 7)

#define TIMER_ENABLE 1

static int ledg_gpio = -1;
static int ledr_gpio = -1;
static int button_gpio = -1;
static int button_state = -1;
static int button_cnt = -1;

#ifdef TIMER_ENABLE
static ktime_t timer_period;
struct hrtimer button_timer;

static enum hrtimer_restart timer_callback(struct hrtimer *timer)
{
int cur_button_state;

cur_button_state = gpio_get_value(button_gpio);
button_cnt = (cur_button_state == button_state) ? (button_cnt + 1) : 0;
button_state = cur_button_state;
gpio_set_value(ledr_gpio, ((button_cnt == 20) ? 1 : 0));
if (button_cnt >= 20)
gpio_set_value(ledg_gpio, !button_state);
hrtimer_forward(timer, timer->base->get_time(), timer_period);
return HRTIMER_RESTART; //restart timer
}
#endif

static int led_gpio_init(int gpio, int *led_gpio)
{
int res;

res = gpio_direction_output(gpio, 0);
if (res != 0)
return res;

*led_gpio = gpio;
return 0;
}

static int button_gpio_init(int gpio)
{
int res;

res = gpio_request(gpio, "Onboard user button");
if (res != 0)
return res;

res = gpio_direction_input(gpio);
if (res != 0)
goto err_input;

button_gpio = gpio;
pr_info("Init GPIO%d OK\n", button_gpio);
button_state = gpio_get_value(button_gpio);
button_cnt = 0;

return 0;

err_input:
gpio_free(gpio);
return res;
}

static void button_gpio_deinit(void)
{
if (button_gpio >= 0) {
gpio_free(button_gpio);
pr_info("Deinit GPIO%d\n", button_gpio);
}
}

/* Module entry/exit points */
static int __init led_mod_init(void)
{
int res;
pr_info("GPIO Init\n");

res = button_gpio_init(BUTTON);
if (res != 0) {
pr_err("Can't set GPIO%d for button\n", BUTTON);
return res;
}
#ifdef TIMER_ENABLE
timer_period = ktime_set(0, 1000000); /*1 msec*/
hrtimer_init(&button_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_start(&button_timer, timer_period, HRTIMER_MODE_REL);
button_timer.function = timer_callback;
#endif
res = led_gpio_init(LED_GREEN, &ledg_gpio);
if (res != 0) {
pr_err("Can't set GPIO%d for output\n", LED_GREEN);
goto err_led;
}

gpio_set_value(ledg_gpio, 0);

res = led_gpio_init(LED_RED, &ledr_gpio);
if (res != 0) {
pr_err("Can't set GPIO%d for output\n", LED_RED);
goto err_led;
}
gpio_set_value(ledr_gpio, 1);

return 0;

err_led:
button_gpio_deinit();
return res;
}

static void __exit led_mod_exit(void)
{
gpio_set_value(ledg_gpio, 0);
gpio_set_value(ledr_gpio, 0);
button_gpio_deinit();
#ifdef TIMER_ENABLE
hrtimer_cancel(&button_timer);
#endif
}

module_init(led_mod_init);
module_exit(led_mod_exit);

MODULE_AUTHOR("Oleksandr Posukhov [email protected]>");
MODULE_DESCRIPTION("LED Test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
Loading