개요

리눅스 Eth MAC 디바이스 드라이버에서 Link Down 이벤트가 발생하지 않는 현상이 있었다.

확인해보니 PHY 칩이 Switch 구조로 되어있어 CPU 쪽으로 직접적인 인터럽트가 발생하지 않는 구조였기 때문이였다.

 

그래서, PHY 쪽 Link 상태 레지스터를 폴링하여 Link Down을 발생시킬 수 있도록 구현이 필요했다.

따라서, 커널 타이머를 사용해 주기적으로 EMAC(Eth MAC) 드라이버에서 PHY 레지스터를 읽을 수 있도록 구현하였다.

 

시스템의 커널 버전이 3.18.44로 요즘 사용하는 커널 타이머 소스는 컴파일되지 않아 2010년 정도의 자료를 뒤져서 찾아내었다..

 

예제 소스

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/time.h>
#include <linux/timer.h>


#define TIME_STEP    (1*HZ) // 1HZ = 1Sec


struct timer_list  *timer;
static int timertick=0;

void kerneltimer_timeover(unsigned long arg);

void kerneltimer_registertimer(struct timer_list* ptimer, unsigned long timeover)
{
     init_timer(ptimer);
     ptimer->expires  = jiffies + timeover;
     ptimer->data     = NULL;
     ptimer->function = kerneltimer_timeover;
     add_timer(ptimer);
}

void kerneltimer_timeover(unsigned long arg )
{
        printk("Timer tick:%d\n", timertick);
        timertick++;
        kerneltimer_registertimer(timer, TIME_STEP);
}

int kerneltimer_init(void)
{
    timer= kmalloc(sizeof(struct timer_list), GFP_KERNEL);
    
    if(timer== NULL) 
    	return -ENOMEM;
    
    memset(timer, 0, sizeof(struct timer_list));
    kerneltimer_registertimer(timer, TIME_STEP);
    return 0;
}

void kerneltimer_exit(void)
{
    if( timer!= NULL )
    {
        del_timer( timer) ;
        kfree( timer);
    }
}

module_init(kerneltimer_init);
module_exit(kerneltimer_exit);

 

끝으로

그런데 커널 타이머를 사용하다보니 커널에 존재하는 User Mode Helper API와 잘 사용할 수 있을거 같았다.

 

User Mode Helper API는 커널에서 User 영역 바이너리를 실행시키게 해주는 커널 API이다.

 

커널 타이머에 UMH(User Mode Helper)를 붙여서 /bin/ifconfig을 실행시키는 예제를 실행해보았는데 커널 에러가 syslog에 발생하였다.

 

확인해보니 UMH는 프로세스 컨텍스트에서만 실행이 가능한 구조였다. (드라이버 영역 내에서만)

아무튼,, 커널 타이머를 통해 콜백되는 형태로는 UMH를 사용하지 못하는거 같았다.

 

만약, 커널 드라이버에서 UMH를 주기적으로 호출하는 방법을 사용해야 한다면 커널 타이머로 커널 인터럽트를 발생시켜, 프로세스 컨텍스트에서 UMH를 사용할 수 있도록 해야겠다. 

 

References

https://damduc.tistory.com/229

https://stackoverflow.com/questions/4039602/example-for-kernel-timer-implementation-in-linux-in-kernel-2-6-32

https://kernelnewbies.kernelnewbies.narkive.com/iB9rF3uC/call-usermodehelper-from-a-timer-function

 

밑에꺼는 본 페이지랑 상관없는 커널 인터럽트에 관련된 자료

https://embetronicx.com/tutorials/linux/device-drivers/linux-device-driver-tutorial-part-13-interrupt-example-program-in-linux-kernel/

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기