Làm thế nào để nhân Linux xử lý các IRQ được chia sẻ?


14

Theo những gì tôi đã đọc cho đến nay, "khi kernel nhận được một ngắt, tất cả các trình xử lý đã đăng ký sẽ được gọi."

Tôi hiểu rằng các trình xử lý đã đăng ký cho mỗi IRQ có thể được xem qua /proc/interruptsvà tôi cũng hiểu rằng các trình xử lý đã đăng ký đến từ các trình điều khiển đã gọi request_irqđi qua trong một cuộc gọi lại có dạng:

irqreturn_t (*handler)(int, void *)

Dựa trên những gì tôi biết, mỗi lệnh gọi lại của trình xử lý ngắt này được liên kết với IRQ cụ thể sẽ được gọi và tùy thuộc vào trình xử lý để xác định xem ngắt có thực sự được xử lý hay không. Nếu trình xử lý không nên xử lý ngắt cụ thể, nó phải trả về macro kernel IRQ_NONE.

Điều tôi gặp khó khăn trong việc hiểu là, làm thế nào mỗi tài xế dự kiến ​​sẽ xác định liệu có nên xử lý ngắt hay không. Tôi cho rằng họ có thể theo dõi nội bộ nếu họ dự kiến ​​sẽ bị gián đoạn. Nếu vậy, tôi không biết làm thế nào họ có thể giải quyết tình huống trong đó nhiều tài xế đằng sau cùng một IRQ đang mong đợi một sự gián đoạn.

Lý do tôi cố gắng hiểu các chi tiết này là vì tôi đang rối tung với kexeccơ chế thực thi lại kernel ở giữa hoạt động của hệ thống trong khi chơi với các chân thiết lập lại và các thanh ghi khác nhau trên cầu PCIe cũng như PCI hạ lưu thiết bị. Và khi làm như vậy, sau khi khởi động lại, tôi cảm thấy hoảng loạn hạt nhân hoặc các trình điều khiển khác phàn nàn rằng họ đang bị gián đoạn mặc dù không có hoạt động nào diễn ra.

Làm thế nào xử lý quyết định rằng ngắt nên được xử lý bởi nó là bí ẩn.

Chỉnh sửa: Trong trường hợp có liên quan, kiến ​​trúc CPU được đề cập là x86.


1
stackoverflow.com/questions/14371513/for-a-shared-interrupt-line-how-do-i-find-which-interrupt-handler-to-usec
Ciro Santilli新疆改造中心法轮功六四事件

Câu trả lời:


14

Điều này được trình bày trong chương 10 của Trình điều khiển thiết bị Linux , phiên bản thứ 3, bởi Corbet et al. Nó có sẵn trực tuyến miễn phí , hoặc bạn có thể ném một số cách của O'Reilly cho các hình thức cây hoặc ebook chết. Phần liên quan đến câu hỏi của bạn bắt đầu trên trang 278 trong liên kết đầu tiên.

Để biết giá trị của nó, đây là nỗ lực của tôi để diễn giải ba trang đó, cộng với các bit khác mà tôi đã viết:

  • Khi bạn đăng ký trình xử lý IRQ được chia sẻ, kernel sẽ kiểm tra xem:

    a. không có trình xử lý nào khác tồn tại cho ngắt đó, hoặc

    b. tất cả những người đã đăng ký trước đó cũng yêu cầu chia sẻ ngắt

    Nếu một trong hai trường hợp được áp dụng, thì nó sẽ kiểm tra xem dev_idtham số của bạn là duy nhất, để kernel có thể phân biệt nhiều trình xử lý, ví dụ như trong quá trình loại bỏ trình xử lý.

  • Khi một thiết bị phần cứng PCI¹ tăng dòng IRQ, trình xử lý ngắt cấp thấp của kernel được gọi và đến lượt nó gọi tất cả các trình xử lý ngắt đã đăng ký, chuyển từng dev_idbộ xử lý mà bạn đã sử dụng để đăng ký trình xử lý qua request_irq().

    Các dev_idgiá trị cần phải được máy độc đáo. Cách phổ biến để làm điều đó là chuyển một con trỏ tới mỗi thiết bị structmà trình điều khiển của bạn sử dụng để quản lý thiết bị đó. Vì con trỏ này phải nằm trong không gian bộ nhớ của trình điều khiển của bạn để nó hữu ích cho trình điều khiển, nên nó thực sự là duy nhất cho trình điều khiển đó.

    Nếu có nhiều trình điều khiển được đăng ký cho một ngắt nhất định, tất cả chúng sẽ được gọi khi bất kỳ thiết bị nào tăng dòng ngắt chia sẻ đó. Nếu đó không phải là thiết bị của trình điều khiển của bạn đã làm điều này, trình xử lý ngắt trình điều khiển của bạn sẽ được chuyển một dev_idgiá trị không thuộc về nó. Trình xử lý ngắt trình điều khiển của bạn phải quay lại ngay lập tức khi điều này xảy ra.

    Một trường hợp khác là trình điều khiển của bạn đang quản lý nhiều thiết bị. Trình xử lý ngắt của trình điều khiển sẽ nhận được một trong các dev_idgiá trị mà trình điều khiển đã biết. Mã của bạn có nghĩa vụ thăm dò ý kiến ​​từng thiết bị để tìm ra cái nào đã làm gián đoạn.

    Ví dụ Corbet et al. cho là của một cổng song song PC. Khi nó xác nhận dòng ngắt, nó cũng đặt bit trên cùng trong thanh ghi thiết bị đầu tiên. (Nghĩa là, inb(0x378) & 0x80 == truegiả sử đánh số cổng I / O tiêu chuẩn.) Khi trình xử lý của bạn phát hiện ra điều này, nó được cho là thực hiện công việc của nó, sau đó xóa IRQ bằng cách ghi giá trị đọc từ cổng I / O trở lại cổng với đỉnh bit bị xóa.

    Tôi không thấy bất kỳ lý do nào mà cơ chế đặc biệt đó là đặc biệt. Một thiết bị phần cứng khác nhau có thể chọn một cơ chế khác. Điều quan trọng duy nhất là để một thiết bị cho phép ngắt được chia sẻ, nó phải có một số cách để người lái đọc trạng thái ngắt của thiết bị và một số cách để xóa ngắt. Bạn sẽ phải đọc bảng dữ liệu hoặc hướng dẫn lập trình của thiết bị để tìm hiểu cơ chế nào mà thiết bị cụ thể của bạn sử dụng.

  • Khi trình xử lý ngắt của bạn báo cho kernel, nó đã xử lý ngắt, điều đó không ngăn kernel tiếp tục gọi bất kỳ trình xử lý nào khác đã đăng ký cho cùng một ngắt đó. Điều này là không thể tránh khỏi nếu bạn muốn chia sẻ một dòng ngắt khi sử dụng các ngắt kích hoạt mức.

    Hãy tưởng tượng hai thiết bị khẳng định cùng một dòng ngắt cùng một lúc. (Hoặc ít nhất, gần đến mức mà hạt nhân không có thời gian để gọi một trình xử lý ngắt để xóa dòng và do đó xem xác nhận thứ hai là riêng biệt.) Nhân phải gọi tất cả các trình xử lý cho dòng ngắt đó, để cung cấp cho mỗi trình xử lý một cơ hội để truy vấn phần cứng liên quan của nó để xem nếu nó cần chú ý. Hai trình điều khiển khác nhau có thể xử lý thành công một ngắt trong cùng một lần đi qua danh sách xử lý cho một ngắt nhất định.

    Bởi vì điều này, điều bắt buộc là trình điều khiển của bạn nói với thiết bị mà nó đang quản lý để xóa xác nhận ngắt của nó đôi khi trước khi trình xử lý ngắt trở lại. Nó không rõ ràng với tôi những gì xảy ra khác. Dòng ngắt được xác nhận liên tục sẽ dẫn đến việc kernel liên tục gọi các trình xử lý ngắt được chia sẻ hoặc nó sẽ che dấu khả năng của kernel để xem các ngắt mới để các trình xử lý không bao giờ được gọi. Dù bằng cách nào, thảm họa.


Chú thích:

  1. Tôi đã chỉ định PCI ở trên vì tất cả các giả định ở trên đều giả định các ngắt kích hoạt mức , như được sử dụng trong thông số PCI gốc. ISA đã sử dụng các ngắt kích hoạt cạnh , điều này khiến việc chia sẻ trở nên khó khăn nhất và thậm chí chỉ có thể khi được phần cứng hỗ trợ. PCIe sử dụng ngắt tín hiệu tin nhắn ; thông báo ngắt chứa một giá trị duy nhất mà kernel có thể sử dụng để tránh trò chơi đoán vòng tròn cần thiết với chia sẻ ngắt PCI. PCIe có thể loại bỏ nhu cầu chia sẻ ngắt. (Tôi không biết nếu nó thực sự làm, chỉ là nó có tiềm năng.)

  2. Tất cả các trình điều khiển hạt nhân Linux đều có chung một không gian bộ nhớ, nhưng một trình điều khiển không liên quan không được cho là đang lẩn quẩn trong không gian bộ nhớ của người khác. Trừ khi bạn vượt qua con trỏ đó, bạn có thể chắc chắn rằng một trình điều khiển khác sẽ không tự mình tìm ra cùng một giá trị.


1
Giống như bạn đã đề cập, trình xử lý ngắt có thể được thông qua dev_idmà nó không sở hữu. Đối với tôi, dường như có một cơ hội khác không rằng một trình điều khiển không sở hữu dev_idcấu trúc vẫn có thể nhầm nó là của chính nó dựa trên cách nó diễn giải nội dung. Nếu đây không phải là trường hợp thì cơ chế nào sẽ ngăn chặn điều này?
bsirang

Bạn ngăn chặn nó bằng cách tạo dev_idmột con trỏ tới một cái gì đó trong không gian bộ nhớ của trình điều khiển. Tài xế khác có thể tạo nên một dev_idgiá trị mà xảy ra được confusable với một con trỏ tới bộ nhớ lái xe của bạn sở hữu, nhưng điều đó sẽ không xảy ra vì tất cả mọi người đang chơi đúng luật. Đây là không gian hạt nhân, hãy nhớ rằng: kỷ luật tự giác được coi là một vấn đề tất nhiên, không giống như mã không gian người dùng, có thể cho rằng bất cứ điều gì không bị cấm đều được cho phép.
Warren Young

Theo chương mười của LDD3: "Bất cứ khi nào hai hoặc nhiều trình điều khiển đang chia sẻ một dòng ngắt và phần cứng làm gián đoạn bộ xử lý trên dòng đó, kernel sẽ gọi mọi trình xử lý đã đăng ký cho ngắt đó, chuyển qua mỗi dev_id của chính nó" Có vẻ như cách hiểu trước đó là không chính xác về việc một trình xử lý ngắt có thể được thông qua trong dev_idđó nó không sở hữu.
bsirang

Đó là một đọc sai về phía tôi. Khi tôi viết điều đó, tôi đã nhầm lẫn hai khái niệm. Tôi đã chỉnh sửa câu trả lời của mình. Điều kiện yêu cầu trình xử lý ngắt của bạn quay trở lại nhanh chóng là nó được gọi do xác nhận ngắt bởi một thiết bị mà nó không quản lý. Giá trị của dev_idkhông giúp bạn xác định liệu điều này đã xảy ra. Bạn phải hỏi phần cứng, "Bạn reo?"
Warren Young

Vâng, bây giờ tôi cần tìm hiểu xem những gì tôi đang mày mò thực sự khiến các trình điều khiển khác tin rằng thiết bị của họ "reo" sau khi khởi động lại kernel thông qua kexec.
bsirang

4

Khi trình điều khiển yêu cầu IRQ được chia sẻ, nó sẽ chuyển một con trỏ tới kernel để tham chiếu đến cấu trúc cụ thể của thiết bị trong không gian bộ nhớ của trình điều khiển.

Theo LDD3:

Bất cứ khi nào hai hoặc nhiều trình điều khiển đang chia sẻ một dòng ngắt và phần cứng làm gián đoạn bộ xử lý trên dòng đó, kernel sẽ gọi mọi trình xử lý đã đăng ký cho ngắt đó, truyền cho mỗi dev_id của chính nó.

Khi kiểm tra trình xử lý IRQ của một số trình điều khiển, có vẻ như họ tự thăm dò phần cứng để xác định xem có nên xử lý ngắt hay trả lại hay không IRQ_NONE.

Ví dụ

Trình điều khiển UHCI-HCD
  status = inw(uhci->io_addr + USBSTS);
  if (!(status & ~USBSTS_HCH))  /* shared interrupt, not mine */
    return IRQ_NONE;

Trong đoạn mã trên, trình điều khiển đang đọc thanh USBSTSghi để xác định xem có dịch vụ ngắt hay không.

Trình điều khiển SDHCI
  intmask = sdhci_readl(host, SDHCI_INT_STATUS);

  if (!intmask || intmask == 0xffffffff) {
    result = IRQ_NONE;
    goto out;
  }

Giống như trong ví dụ trước, trình điều khiển đang kiểm tra một thanh ghi trạng thái, SDHCI_INT_STATUSđể xác định xem nó có cần phục vụ ngắt hay không.

Tài xế Ath5k
  struct ath5k_softc *sc = dev_id;
  struct ath5k_hw *ah = sc->ah;
  enum ath5k_int status;
  unsigned int counter = 1000;

  if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
        !ath5k_hw_is_intr_pending(ah)))
    return IRQ_NONE;

Chỉ một ví dụ nữa.


0

Vui lòng truy cập kiểm tra liên kết này :

Đó là một cách thông thường để kích hoạt nửa dưới hoặc bất kỳ logic nào khác trong trình xử lý IRQ chỉ sau khi kiểm tra trạng thái IRQ từ thanh ghi ánh xạ bộ nhớ. Do đó, vấn đề được giải quyết mặc định bởi một lập trình viên giỏi.


Nội dung liên kết của bạn không khả dụng
user3405291
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.