PCIe AER及錯誤處理原理

一尖坤、錯誤分類

image.png

如上圖,pci傳輸過程中夯接,以及pcie設(shè)備自身發(fā)現(xiàn)的錯誤焕济,可以兩大類

  1. 可恢復(fù)錯誤: 表示硬件會自動恢復(fù)的錯誤,無需軟件參與
  2. 不可恢復(fù)錯誤盔几,不可恢復(fù)錯誤分為2小類:
    • Non-Fatal錯誤: 表示傳輸事務(wù)出錯不可靠晴弃,但是物理層link還OK
    • Fatal錯誤: 表示物理層link已經(jīng)出問題

從錯誤出現(xiàn)在PCIe所屬層級來分,可以分為4類:

  1. 物理層
  2. 數(shù)據(jù)鏈路層
  3. 傳輸層
  4. pcie設(shè)備內(nèi)部錯誤

二逊拍、錯誤檢測機制

Completion Status

傳輸過程中上鞠,如果接收端發(fā)現(xiàn)有問題,會在回復(fù)的TLP包中的completion status位置相應(yīng)的錯誤值芯丧,如下圖

image.png

cpl.status占了3bit芍阎,不同取值含義如下:

image.png

其中最主要的有2個:

  • cpl.status=0b001,表示UR
  • cpl.status=0b100注整,表示CA
    不在表中的取值當(dāng)前都是保留狀態(tài)

下圖是對tlp的一種判斷邏輯:


image.png

Error轉(zhuǎn)發(fā)

在規(guī)范中能曾,這種錯誤還被稱為:data poisoning度硝,還是很形象的肿轨。這種錯誤只針對發(fā)送TLP或者回復(fù)的TLP中攜帶有數(shù)據(jù)的情況。并且是中間接收節(jié)點(像switch的UP/DP口)檢測到TLP包中攜帶的數(shù)據(jù)有問題時蕊程,會置TLP中“EP”位為1椒袍,表示此TLP包攜帶的數(shù)據(jù)有問題


image.png

Error Message

device發(fā)現(xiàn)錯誤,通過特殊的Message類型的TLP發(fā)送給RC進(jìn)行處理藻茂,TLP如下圖所示


image.png

其中type類型低3bit必須是0驹暑,表示發(fā)給RC,Message Code表示錯誤級別辨赐,取值如下圖所示:


image.png

這里有幾個需要注意的點:

  • 錯誤消息是需要按錯誤級別發(fā)送給RC進(jìn)行統(tǒng)一處理
  • 錯誤消息來自PCIe設(shè)備优俘、傳統(tǒng)PCI設(shè)備、RC自己
  • 一個Request ID檢測到多條同級別的錯誤消息掀序,多條消息可能合并帆焕,同一級別的錯- 誤消息至少發(fā)送一條
  • 對于錯誤消息,RC根據(jù)Request ID來標(biāo)識消息來源不恭,并且將消息轉(zhuǎn)換成平臺級別的事件叶雹,像中斷

三财饥、錯誤列表

General PCIe error list

image.png

內(nèi)部錯誤是與PCIe接口相關(guān)的錯誤,它發(fā)生在組件內(nèi)折晦,可能不是由于PCIe接口本身的數(shù)據(jù)包或事件钥星,也不是由于在PCI上發(fā)起的事務(wù)表達(dá)。

  • 舉例1:數(shù)據(jù)包緩沖區(qū)錯誤被ECC糾正满着,上報corrected Internal Errror
  • 舉例2:數(shù)據(jù)包緩沖區(qū)錯誤無法被ECC糾正, 上報un corrected Internal Errror

Physical Layer Error List

image.png

規(guī)范中只有Receiver Error一種
在網(wǎng)上還看到屯掖,Training Error也是一種物理層錯誤,參見:這篇文章

Data Link Layer Error List

image.png

Transaction Layer Error List

image.png
image.png
image.png

四镐作、錯誤記錄

不支持AER

不支持AER的設(shè)備暮顺,有兩個地方會記錄部分錯誤信息:

  1. PCI兼容的配置空間中的status寄存器,由command寄存器控制


    image.png
image.png

對于Bridge响驴,像UP/DP/RP透且,還有Secondary Status/Bridge Control兩個寄存器控制,與Status/Command寄存器類似豁鲤,是記錄和控制下層bus下設(shè)備相關(guān)錯誤


image.png
  1. PCIe CAP下的Device Status寄存器秽誊,由device control寄存器控制


    image.png
image.png

支持AER

支持AER的設(shè)備,會將之前列的Error list記錄在AER CAP的相應(yīng)bit位


image.png

image.png

部分錯誤攜帶TLP header相關(guān)信息琳骡,存放在AER CAP的Hear Log/TLP Prefix Log寄存器

image.png
image.png

Multiple Error處理

在AER CAP中有一個Advanced Error Capabilites and Control Register寄存器:

  • First Error Pointer指向最先發(fā)生的Uncorrectable錯誤所在bit位的值锅论;Header Log寄存器記錄對應(yīng)錯誤的報頭信息
  • 當(dāng)?shù)谝粋€Uncorrectable錯誤被處理并清除之后, First Error Pointer/Header Log會指向下一個Uncorrectable錯誤的相關(guān)信息
  • 當(dāng)所有Uncorrectable錯誤被處理并清除之后楣号, First Error Pointer/Header Log指向無效值
  • 當(dāng)錯誤報頭記錄數(shù)量超過實現(xiàn)所支持的最大數(shù)量時最易,會報Header Log Overflow錯誤
image.png

RC

RC除了記錄上面描述的Device相關(guān)的AER信息以外,還需要記錄接收到從下層或RC自己上報的AER信息
通過source寄存器標(biāo)識錯誤來源炫狱,如下圖


image.png

Root Error Status寄存器中的位表示收到了什么類型的錯誤藻懒,如下圖


image.png

注意:Bit5/bit6只是為了區(qū)分收到的uncorrectable錯誤是Fatal的還是Non-Fatal的

RC收到AER信息之后,可以:

  • 配置觸發(fā)一個中斷(AER CAP中的Root Error Command Register來控制)视译,軟件來進(jìn)行處理AER


    image.png
  • 或者產(chǎn)生一個System Error(PCIe CAP里的Root Control Register來控制)


    image.png

Advisory Non-Fatal Error

在某些情況下嬉荆,非致命錯誤的檢測器不是確定錯誤是否可恢復(fù)的最合適的代理,或者它甚至不需要任何恢復(fù)操作酷含。主要由檢測代理(請求者鄙早、完成者、接收者)的角色和特定錯誤確定椅亚。

基于此限番,提出了Advisory Non-Fatal Error場景,在此場景下收到的Non-Fatal錯誤換成Correctable錯誤(如果使能了AER)呀舔,或者不上報錯誤消息(沒有使能AER)

  • Completer Sending a Completion with UR/CA Status
  • Intermediate Receiver
  • Ultimate PCI Express Receiver of a Poisoned TLP
  • Requester with Completion Timeout
  • Receiver of an Unexpected Completion

五弥虐、設(shè)備錯誤記錄以及上報的流程

image.png

六、錯誤消息上報控制

image.png

七、linux內(nèi)核對AER的處理

RC的AER功能初始化

/**
 * aer_enable_rootport - enable Root Port's interrupts when receiving messages
 * @rpc: pointer to a Root Port data structure
 *
 * Invoked when PCIe bus loads AER service driver.
 */
static void aer_enable_rootport(struct aer_rpc *rpc)
{
    struct pci_dev *pdev = rpc->rpd;
    int aer = pdev->aer_cap;
    u16 reg16;
    u32 reg32;

    /* Clear PCIe Capability's Device Status */
    pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &reg16);
    pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16);

    /* Disable system error generation in response to error messages */
    pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
                   SYSTEM_ERROR_INTR_ON_MESG_MASK);

    /* Clear error status */
    pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, &reg32);
    pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, reg32);
    pci_read_config_dword(pdev, aer + PCI_ERR_COR_STATUS, &reg32);
    pci_write_config_dword(pdev, aer + PCI_ERR_COR_STATUS, reg32);
    pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, &reg32);
    pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32);

    aer_enable_irq(pdev);
}

static void aer_enable_irq(struct pci_dev *pdev)
{
    int aer = pdev->aer_cap;
    u32 reg32;

    /* Enable Root Port's interrupt in response to error messages */
    pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
    reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
    pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
}

設(shè)備的AER初始化

void pci_aer_init(struct pci_dev *dev)
{
    int n;

    dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
    if (!dev->aer_cap)
        return;

    dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL);

    /*
     * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
     * PCI_ERR_COR_MASK, and PCI_ERR_CAP.  Root and Root Complex Event
     * Collectors also implement PCI_ERR_ROOT_COMMAND (PCIe r5.0, sec
     * 7.8.4).
     */
    n = pcie_cap_has_rtctl(dev) ? 5 : 4;
    pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n);

    pci_aer_clear_status(dev);

    if (pci_aer_available())
        pci_enable_pcie_error_reporting(dev);

    pcie_set_ecrc_checking(dev);
}
  • pci_aer_clear_status(dev);對應(yīng)的定義如下
int pci_aer_clear_status(struct pci_dev *dev)
{
    if (!pcie_aer_is_native(dev))
        return -EIO;

    return pci_aer_raw_clear_status(dev);
}

/**
 * pci_aer_raw_clear_status - Clear AER error registers.
 * @dev: the PCI device
 *
 * Clearing AER error status registers unconditionally, regardless of
 * whether they're owned by firmware or the OS.
 *
 * Returns 0 on success, or negative on failure.
 */
int pci_aer_raw_clear_status(struct pci_dev *dev)
{
    int aer = dev->aer_cap;
    u32 status;
    int port_type;

    if (!aer)
        return -EIO;

    port_type = pci_pcie_type(dev);
    if (port_type == PCI_EXP_TYPE_ROOT_PORT ||
        port_type == PCI_EXP_TYPE_RC_EC) {
        pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &status);
        pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, status);
    }

    pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS, &status);
    pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS, status);

    pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, &status);
    pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);

    return 0;
}
  • pci_enable_pcie_error_reporting(dev);對應(yīng)的定義如下
static int pci_enable_pcie_error_reporting(struct pci_dev *dev)
{
    int rc;

    if (!pcie_aer_is_native(dev))
        return -EIO;

    rc = pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_AER_FLAGS);
    return pcibios_err_to_errno(rc);
}
  • 對于Bridge來說躯舔,還需要配置Bridge Control寄存器的SEER驴剔,這一位是控制是否轉(zhuǎn)發(fā)從下面設(shè)備接收到的錯誤消息到上層
static void pci_configure_serr(struct pci_dev *dev)
{
    u16 control;

    if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {

        /*
         * A bridge will not forward ERR_ messages coming from an
         * endpoint unless SERR# forwarding is enabled.
         */
        pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &control);
        if (!(control & PCI_BRIDGE_CTL_SERR)) {
            control |= PCI_BRIDGE_CTL_SERR;
            pci_write_config_word(dev, PCI_BRIDGE_CONTROL, control);
        }
    }
}

設(shè)備AER初始化在設(shè)備枚舉中的調(diào)用層次如下圖


image.png

RC對AER的處理

  • 接收到AER中斷之后,會進(jìn)入AER的中斷處理函數(shù)粥庄,讀取status/source等信息
/**
 * aer_irq - Root Port's ISR
 * @irq: IRQ assigned to Root Port
 * @context: pointer to Root Port data structure
 *
 * Invoked when Root Port detects AER messages.
 */
static irqreturn_t aer_irq(int irq, void *context)
{
    struct pcie_device *pdev = (struct pcie_device *)context;
    struct aer_rpc *rpc = get_service_data(pdev);
    struct pci_dev *rp = rpc->rpd;
    int aer = rp->aer_cap;
    struct aer_err_source e_src = {};

    pci_read_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, &e_src.status);
    if (!(e_src.status & AER_ERR_STATUS_MASK))
        return IRQ_NONE;

    pci_read_config_dword(rp, aer + PCI_ERR_ROOT_ERR_SRC, &e_src.id);
    pci_write_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, e_src.status);

    if (!kfifo_put(&rpc->aer_fifo, e_src))
        return IRQ_HANDLED;

    return IRQ_WAKE_THREAD;
}
  • 中斷處理函數(shù)會將AER相關(guān)信息通過FIFO隊列傳送給后端處理線程isr丧失,isr出隊一個一個處理AER
static irqreturn_t aer_isr(int irq, void *context)
{
    struct pcie_device *dev = (struct pcie_device *)context;
    struct aer_rpc *rpc = get_service_data(dev);
    struct aer_err_source e_src;

    if (kfifo_is_empty(&rpc->aer_fifo))
        return IRQ_NONE;

    while (kfifo_get(&rpc->aer_fifo, &e_src))
        aer_isr_one_error(rpc, &e_src);
    return IRQ_HANDLED;
}
  • 處理AER的主要邏輯在aer_isr_one_error(rpc, &e_src)中,定義如下:
/**
 * aer_isr_one_error - consume an error detected by root port
 * @rpc: pointer to the root port which holds an error
 * @e_src: pointer to an error source
 */
static void aer_isr_one_error(struct aer_rpc *rpc,
        struct aer_err_source *e_src)
{
    struct pci_dev *pdev = rpc->rpd;
    struct aer_err_info e_info;

    pci_rootport_aer_stats_incr(pdev, e_src);

    /*
     * There is a possibility that both correctable error and
     * uncorrectable error being logged. Report correctable error first.
     */
    if (e_src->status & PCI_ERR_ROOT_COR_RCV) {
        e_info.id = ERR_COR_ID(e_src->id);
        e_info.severity = AER_CORRECTABLE;

        if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)
            e_info.multi_error_valid = 1;
        else
            e_info.multi_error_valid = 0;
        aer_print_port_info(pdev, &e_info);

        if (find_source_device(pdev, &e_info))
            aer_process_err_devices(&e_info);
    }

    if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {
        e_info.id = ERR_UNCOR_ID(e_src->id);

        if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)
            e_info.severity = AER_FATAL;
        else
            e_info.severity = AER_NONFATAL;

        if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)
            e_info.multi_error_valid = 1;
        else
            e_info.multi_error_valid = 0;

        aer_print_port_info(pdev, &e_info);

        if (find_source_device(pdev, &e_info))
            aer_process_err_devices(&e_info);
    }
}

主要分三塊內(nèi)容:

  • 統(tǒng)計RC收到各類型錯誤的計數(shù)
  • 處理此AER中的可恢復(fù)中斷
  • 處理此AER中的不可恢復(fù)中斷

而后兩塊內(nèi)容處理邏輯類似惜互,都包含三方面:

  • 找到AER來源布讹,即此AER是從哪個設(shè)備發(fā)上來的
  • 統(tǒng)計此設(shè)備上出現(xiàn)的各類錯誤的計數(shù)
  • 對此錯誤進(jìn)行處理
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市训堆,隨后出現(xiàn)的幾起案子描验,更是在濱河造成了極大的恐慌,老刑警劉巖坑鱼,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膘流,死亡現(xiàn)場離奇詭異,居然都是意外死亡鲁沥,警方通過查閱死者的電腦和手機呼股,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來画恰,“玉大人彭谁,你說我怎么就攤上這事≡噬龋” “怎么了缠局?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長考润。 經(jīng)常有香客問我狭园,道長,這世上最難降的妖魔是什么额划? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任妙啃,我火速辦了婚禮档泽,結(jié)果婚禮上俊戳,老公的妹妹穿的比我還像新娘。我一直安慰自己馆匿,他們只是感情好抑胎,可當(dāng)我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渐北,像睡著了一般阿逃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天恃锉,我揣著相機與錄音搀菩,去河邊找鬼。 笑死破托,一個胖子當(dāng)著我的面吹牛肪跋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播土砂,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼州既,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了萝映?” 一聲冷哼從身側(cè)響起吴叶,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎序臂,沒想到半個月后蚌卤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡奥秆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年造寝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吭练。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡诫龙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鲫咽,到底是詐尸還是另有隱情签赃,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布分尸,位于F島的核電站锦聊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏箩绍。R本人自食惡果不足惜孔庭,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望材蛛。 院中可真熱鬧圆到,春花似錦、人聲如沸卑吭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豆赏。三九已至挣菲,卻和暖如春富稻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背白胀。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工椭赋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人或杠。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓纹份,卻偏偏與公主長得像,于是被迫代替她去往敵國和親廷痘。 傳聞我的和親對象是個殘疾皇子蔓涧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容