Posted, Non-Posted, and Completion Credits (PH/PD/NPH/NPD/CPLH/CPLD) Explained
- Posted, Non-Posted, and Completion Credits (PH/PD/NPH/NPD/CPLH/CPLD) Explained
- 1 . Introduction
- 2 . Why Multiple Credit Types?
- 3 . Posted Credits (PH / PD)
- 4 . Non-Posted Credits (NPH / NPD)
- 5 . Completion Credits (CPLH / CPLD)
- 6 . Why Separate Credits per TLP Type?
- 7 . Credit Consumption Examples
- 8 . Interaction Between Credit Types
- 9 . Flow Control at System Level
- 10 . Debug and Verification Tip
- NOTES
1 . Introduction
Every TLP transmitted in PCIe falls into one of three transaction categories:
- Posted (P)
- Non-Posted (NP)
- Completion (CPL)
To manage buffer availability for these transactions, PCIe defines six credit counters per Virtual Channel:
- PH, PD – Posted Header/Data
- NPH, NPD – Non-Posted Header/Data
- CPLH, CPLD – Completion Header/Data
Each represents how many packets (headers) or data doublewords (payloads) can be accepted by the receiver.
2 . Why Multiple Credit Types?
Different packet classes have different communication patterns:
Class | Example | Completion Expected? | Flow Characteristics |
Posted | Memory Write, Message | ❌ No | High throughput, one-way |
Non-Posted | Memory Read, I/O Read, Config Read | ✅ Yes | Must be tracked until completed |
Completion | Cpl / CplD | — | Must always be delivered back reliably |
If a single shared buffer were used, large posted writes could block important completions — causing deadlock.
Hence, PCIe defines separate logical buffers and credit pools.
3 . Posted Credits (PH / PD)
Purpose:
Used for packets that do not expect a response, like:
- Memory Write
- Message
- Message with Data
Credit Types:
- PH – Posted Header credit
- PD – Posted Data credit (measured in DWs)
Behavior:
- Consumed immediately upon TLP transmission.
- Not restored (no completion expected).
- Only replenished when receiver frees buffer and sends a Flow Control Update DLLP.
Design Note:
Posted transactions can be transmitted aggressively to maximize bandwidth since they are non-blocking.
4 . Non-Posted Credits (NPH / NPD)
Purpose:
Used for TLPs that require a completion, such as:
- Memory Read
- I/O Read / Write
- Configuration Read / Write
Credit Types:
- NPH – Non-Posted Header credit
- NPD – Non-Posted Data credit (for writes that expect a response)
Behavior:
- Consumed when a Non-Posted request is transmitted.
- The requester must track all outstanding Non-Posted requests using Tag + Requester ID.
- Credits are only freed when:
- The completer sends a Completion (Cpl / CplD), and
- The requester processes and retires that completion.
- The completer sends a Completion (Cpl / CplD), and
💡 Key point: Non-Posted credits ensure the receiver won’t be flooded with reads or I/O operations that it cannot service.
5 . Completion Credits (CPLH / CPLD)
Purpose:
Used by a Completer (target device) to send completion packets for previous requests.
Credit Types:
- CPLH – Completion Header credit
- CPLD – Completion Data credit
Behavior:
- Required before sending Completion or Completion with Data (CplD) TLPs.
- Ensures the Requester (upstream device) has buffer space ready for incoming completions.
- Prevents deadlock if the Requester cannot accept more completion data.
Example:
An Endpoint sending a read response consumes:
- 1 CPLH (header)
- N CPLD (based on payload length)
6 . Why Separate Credits per TLP Type?
Let’s understand with an example of potential deadlock:
Scenario:
- Endpoint’s Completion queue is full.
- Root Complex keeps sending more Non-Posted Reads.
- If there were a shared buffer, these reads would block the completion path.
Result: Both sides wait forever — deadlock.
Solution in PCIe:
- Separate credits (and thus buffers) for each class ensure forward progress for Completions even if Posted/Non-Posted queues are full.
7 . Credit Consumption Examples
Example 1 – Memory Write (Posted)
- Header → consumes 1 PH
- Payload (8 DW) → consumes 8 PD
Example 2 – Memory Read (Non-Posted)
- Header → 1 NPH
- No data payload → no NPD
Example 3 – Completion with Data (CplD)
- Header → 1 CPLH
- Payload (16 DW) → 16 CPLD
8 . Interaction Between Credit Types
Each transaction’s flow control type depends on its TLP class:
TLP Type | Header Credit | Data Credit | Completion Involved? |
Memory Write | PH | PD | No |
Memory Read | NPH | — | Yes |
I/O Write | NPH | NPD | Yes |
Message | PH | PD | No |
Completion | CPLH | CPLD | — |
⚙️ Hardware must maintain independent counters for each pair (H, D) and block transmission if any required counter reaches zero.
9 . Flow Control at System Level
Each direction of the link (Tx/Rx) maintains its own six credit counters per Virtual Channel.
For most designs using a single VC (VC0), this means 6 counters each for Tx and Rx.
If multiple VCs exist (VC0, VC1, etc.), then each VC has an independent set — preventing one class of traffic from consuming another’s credit pool.
10 . Debug and Verification Tip
In simulation or protocol analysis:
- Credits for each class can be tracked via Flow Control DLLPs.
- If PH or NPH counters reach zero while TLPs are still issued → design bug.
- If CPLD credits never increment → completion flow blocked, potential deadlock.
Example UVM check:
assert(!(send_tlp && credits[type]==0))
else $fatal("Sent TLP without credits!");
NOTES
- PCIe defines three transaction classes and six credit counters for precise buffer control.
- Posted Credits → for unidirectional requests (no completion).
- Non-Posted Credits → for requests requiring completions.
- Completion Credits → for sending completions back to requesters.
- Separation of credit pools ensures deadlock-free operation and high link utilization.
- Credit starvation or mismanagement is a top cause of flow stalls — always verify credit accounting logic.