顯示具有 embedded 標籤的文章。 顯示所有文章
顯示具有 embedded 標籤的文章。 顯示所有文章

2023/1/17

Note of Linux bottom-half handling - Softirq, tasklet, workqueue, and threaded interrupt

最近因為手上的問題,花了些時間了解 Linux 上的 bottom-half 機制,記錄下看了甚麼。

重點整理

Softirq

  • Software Interrupt context
    • Enable handling of hardware interrupt
    • The timing of executing softirq handlers
      • (1) exit of HW ISR
      • (2) running at ksoftirqd
      • (3) explicitly call do_softirq
    • Not allowed bottom-half context switch
      • no sleep, no scheduling, and no user memory access
  • Normal priority kernel thread per CPU basis, i.e. ksoftirqd
    • ksoftirqd/n, n is the CPU number
  • Each softirq thread has the same softirq handler.
    • Softirq of the same type can run on multiple CPUs
      • Each CPU has a set of softirq pending status bits
      • The registered softirq handlers are shared by CPUs
    • When one softirq handler is running, another softirq handler can run on another CPU.
      • Disable local CPU bottom-half
      • Enable local CPU interrupt
  • Statically allocated. Only 10 softirqs by default. 
    • Has problem on loadable kernel module. Solved by using tasklet.
  • Postpone the user-space execution
    • softirq has time limit to prevent it's too long
  • Basis of tasklet

Tasklet

  • Implemented upon softirqs (tasklet_sofirq and hi_softirq)
  • Software Interrupt context
  • A tasklet only run on one CPU
  • Different tasklets can run concurrently on multiple CPUs
    • Per-cpu taskelet list
    • Tasket_softirq and hi_softirq
  • Run atomically in a run-to-complete fashion

Work queue

  • Implemented upon kernel thread
  • Process context
  • Permit handlers to sleep

Above methods (softirq, tasklet, work queue) need us to explicitly arrange them in top-half handlers.

Threaded interrupts

  • Recommended way to implement bottom-half
  • Handle the complex of hardirq -> tasklet/softirq interaction and locking problems
  • Prioritizing the handlers share an interrupt line

參考資料


第一篇我能看的懂的,白話講解 bottom-half 的機制
講解 threaded interrupt 的由來
jserv 的上課筆記
有比較 threaded interrupt 與其他方式的實驗
Trace Linux source 裡對 softirqs, tasklet, workqueue 的實作。可以深度的瞭解這三個的實作,只是長度有點長,需要時間理解。

很仔細的講解 softirq, tasklet, 和 workqueue 的行為。用條列的方式解釋,可以搭配上面那篇的程式碼一起對照著看。有重點講解了 ksoftirq 的設計想法。

短短的,直接把 softirq 應該記住的重點直接點出來
linux kernel interrupt document。用 lecture 的方式閱讀也蠻清楚的。
裡面有講到 exception, trap, 和 interrupt 這三個在這篇文章中的定義,拿來參考用。

" 
Trap: user requested to transfer control to a special subroutine
Exception: automatically generated trap of exceptional condition
Interrupt: external hardware event
"

講解 preempt_count 的實作,中文有附圖,很清楚。另外也有 softirq 的文章,一樣也是有圖也清楚。
解釋為什麼 softirq 跑在 kernel thread 中,卻還是屬於 interrupt context。

" 
ksoftirqd is implemented as a set of threads, each of which is constrained to only run on a specific CPU. They are scheduled (at a very high priority) by the normal task scheduler. This implementation has the advantage that the time spent executing the bottom halves is accounted to a system task. It is thus possible for the user to see that the machine is overloaded with interrupt processing, and maybe take remedial action.
Although the work is now being done in process context rather than bottom half context, ksoftirqd sets up an environment identical to that found in bottom half context. Specifically, it executes the softirq handlers with local interrupts enabled and bottom halves disabled locally. Code which runs as a bottom half does not need to change for ksoftirqd to run it. 
"
這篇有簡述 Softirq 的行為,還有提到 softirq 在 kernel 2.6.23 之後會跑在 normal user-level priority,舊一點的資料都是說 softirq 會跑在 highest priority。

在自己手上的 kernel 5.10 上驗證這點。

localhost ~ # ps -e -o uid,pid,ppid,pri,ni,cmd | grep ksoft

    0    13     2  19   0 [ksoftirqd/0]
    0    22     2  19   0 [ksoftirqd/1]
    0    28     2  19   0 [ksoftirqd/2]
    0    34     2  19   0 [ksoftirqd/3]
    0    40     2  19   0 [ksoftirqd/4]
    0    47     2  19   0 [ksoftirqd/5]
    0    53     2  19   0 [ksoftirqd/6]
    0    59     2  19   0 [ksoftirqd/7]

19 is normal user-level priority on kernel 5.10.



2021/1/29

Cross compile mtd-utils

2019/10/23

為什麼 GPIO input 要用 pull-up/pull-down,output 要用 push-pull 或 open-drain?


最近花了點時間研究了 GPIO 為什麼有那麼多的設定要選,有 pull-up / pull-down,還有 push-pull。上網一查,發現相關的心得文章超多,代表了有很多的人都跟我一樣,時間和精神去了解,然後覺得有點價值,值得寫文章記錄下來。

目前看了幾篇文章覺得很有參考價值的有下面幾篇。

Open Drain Output vs. Push-Pull Output

單片機IO口科普:推輓輸出、開漏輸出詳解

Demystifying Microcontroller GPIO Settings

電路常見問題小記之IO口漏電(leakage)

我自己的理解是這樣的。

GPIO 從名稱就能知道,最重要的功能就是用來和外界做 Input 和 Output。從軟體的角度看,就像是 Chip 出了一個 pin 腳,外界只要接上那根 pin 就能跟 Chip 溝通了。



在軟體人的想像中,我想只要有線路接到 register 就夠了吧 ! 在想的仔細一點,加上軟體操作用的 register 好了。



可惜事情不是這麼簡單,現實的物理之壁很快就讓人認清現實。這麼做會有幾個問題要解決。這些問題是看著 GPIO 的設計後做的猜測,可能是為了解決這些問題才這麼做的。

  1. Input 的波型不是方波的話,怎麼辦 ?
  2. GPIO Pin 腳狀態是 floating 
  3. output  如何提供足夠的電流輸出到外面的設備 ? 

Input 的波型不是方波的話,怎麼辦 ?


用 schmitt trigger  來解。


GPIO Pin 腳狀態是 floating 


GPIO 有三種狀態,High impedance,High (voltage),Low (voltage)。

High 代表 digital 1, Low 代表 digital 0。根據 chip 的設計,通常 3.3V = High,0V = Low 。

'High impedance' 也可以寫成 'Hi-Z',代表不上不下,這時的 GPIO pin 可能為 1 也可能為 0,看當下的使用環境而定。這個用途是,當跟其他設備共用一條線時,不影響正在輸出 High / Low 的設備。當沒有共用時,就需要給他一個確定的狀態,避免誤動作。為什麼 floating 會造成誤動作,詳細請看下面的連結,講得很清楚。

浮接 Floating 是甚麼? 電路的不確定因素

回到 GPIO,這個問題就用 pull-up/pull-down 來處理。pull-up 表示預設為 high,pull-down 表示預設為 Low。對應的外部設備動作,pull-up 隱含設備有動作時會拉 Low,pull-down 隱含設備動作時會拉 high。


output  如何提供足夠的電流輸出到外面的設備 ?


這個問題是我想像出來的,目前還沒找到使用 push-pull 的原因,看到的都是在講說 push-pull 的原理,但沒有講是用來解決甚麼問題。

目前看到的 GPIO 有兩種設計來提供電流給外部設備用,一種是 Chip 內的電流,一種是外部的電流。兩種都由 GPIO 來控制供給的時間點。

使用 Chip 內電流的方式稱為 push-pull。外部電流稱為 open-drain (或 open-collector)。

Push-pull

我這邊會加個 inverter 是因為,光只有 PMOS 和 NMOS 的組合,得到的會是一個 inverter。這跟我想要的,GPIO output 1 時輸出電流,output 0 時輸入電流的預期不合,所以才在把他反過來。可以看這一篇 https://en.wikipedia.org/wiki/Inverter_(logic_gate) 提到的 inverter 作法。

Open-drain

Open-drain 由外部提供電流,所以一定要接一個外面的電源。接法就像是 pull-up。



最後,有些 Chip 很聰明,可以讓使用者選擇要用 push-pull 或是 open-drain,有些就不行。這邊我想了一下,覺得可以加一個 NAND 來做,不過出來的結果不是很理想,不太懂怎麼做比較對。

下面的連結可以看我模擬的結果
http://www.falstad.com/circuit/circuitjs.html?cct=$+1+0.000005+10.20027730826997+50+5+43%0Af+288+160+368+160+33+1.5+0.02%0Af+272+240+368+240+32+1.5+0.02%0Aw+368+176+368+224+0%0Aw+368+144+368+64+0%0Aw+16+176+16+64+0%0Aw+368+256+368+320+0%0Aw+16+240+16+320+0%0Aw+368+336+368+320+0%0Aw+368+176+464+176+0%0Ar+464+176+464+256+0+100%0Ag+464+256+464+288+0%0AR+16+64+16+48+0+0+40+5+0+0+0.5%0Ag+16+320+16+352+0%0Ar+16+176+16+240+0+1000%0As+16+176+160+176+0+0+false%0Ag+368+336+368+352+0%0AR+368+64+368+32+0+0+40+5+0+0+0.5%0AR+592+176+592+64+0+0+40+12+0+0+0.5%0Ar+592+176+496+176+0+200%0Aw+496+176+464+176+0%0AI+208+240+272+240+0+0.5+5%0As+64+96+128+96+0+0+false%0A151+208+160+288+160+0+2+0+5%0Aw+160+176+208+176+0%0Aw+64+96+16+176+0%0Aw+208+240+160+176+0%0Aw+160+144+208+144+0%0Aw+128+96+160+144+0%0Ax+49+56+260+59+4+14+0%5Cs(off):open%5Csdrain,%5Cs1%5Cs(on):push-pull%0Ax+36+239+182+242+4+14+GPIO%5Csout:%5Cs0%5Cs(off),%5Cs1%5Cs(on)%0Ax+492+265+523+268+4+14+Load%0Ab+432+192+504+242+0%0Ab+53+149+125+215+0%0Ab+58+69+130+119+0%0Ao+9+64+0+4099+5+0.05+0+2+9+3%0A